Skip to content

Commit

Permalink
update peer test
Browse files Browse the repository at this point in the history
  • Loading branch information
MacOMNI committed Oct 23, 2024
1 parent f08b851 commit 8849624
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 153 deletions.
83 changes: 83 additions & 0 deletions Networking/Sources/CHelpers/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,89 @@

#include "helpers.h"

int parse_certificate(
const unsigned char *data,
size_t length,
unsigned char **public_key,
size_t *public_key_len,
char **alt_name,
char **error_message)
{
int ret = -1;
BIO *bio = NULL;
X509 *cert = NULL;
STACK_OF(GENERAL_NAME) *alt_names = NULL;

// Create BIO from certificate data
bio = BIO_new_mem_buf(data, (int)length);
if (!bio) {
*error_message = "Failed to create BIO.";
goto cleanup;
}

// Parse the X509 certificate from the BIO
cert = d2i_X509_bio(bio, NULL);
if (!cert) {
*error_message = "Failed to parse X509 certificate.";
goto cleanup;
}

// Extract the public key from the certificate
EVP_PKEY *pkey = X509_get_pubkey(cert);
if (!pkey) {
*error_message = "Failed to get public key from certificate.";
goto cleanup;
}

// Get the raw public key
if (EVP_PKEY_get_raw_public_key(pkey, NULL, public_key_len) <= 0) {
*error_message = "Failed to get public key length.";
goto cleanup;
}
*public_key = (unsigned char *)malloc(*public_key_len);
if (!*public_key) {
*error_message = "Failed to allocate memory for public key.";
goto cleanup;
}

if (EVP_PKEY_get_raw_public_key(pkey, *public_key, public_key_len) <= 0) {
*error_message = "Failed to extract public key.";
goto cleanup;
}

// Extract the alternative name from the certificate (if present)
alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
if (alt_names) {
for (int i = 0; i < sk_GENERAL_NAME_num(alt_names); i++) {
GENERAL_NAME *gen_name = sk_GENERAL_NAME_value(alt_names, i);
if (gen_name->type == GEN_DNS) {
ASN1_STRING *name = gen_name->d.dNSName;
*alt_name = strdup((char *)ASN1_STRING_get0_data(name));
break;
}
}
sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
}

if (!*alt_name) {
*error_message = "No alternative name found.";
goto cleanup;
}

ret = EXIT_SUCCESS; // Success

cleanup:
if (ret != 0 && *public_key) {
free(*public_key);
*public_key = NULL;
}
BIO_free(bio);
EVP_PKEY_free(pkey);
X509_free(cert);

return ret;
}

// Function to parse certificate and extract public key and alternative name
int parse_pkcs12_certificate(
const unsigned char *data,
Expand Down
10 changes: 9 additions & 1 deletion Networking/Sources/CHelpers/helpers.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
#include <arpa/inet.h>
#include <stddef.h>

int parse_certificate(
const unsigned char *data,
size_t length,
unsigned char **public_key,
size_t *public_key_len,
char **alt_name,
char **error_message);

int parse_pkcs12_certificate(
const unsigned char *data,
size_t length,
Expand All @@ -21,4 +29,4 @@ char *get_error_string(int error);
static inline uint16_t helper_ntohs(in_port_t netport)
{
return ntohs(netport);
}
}
42 changes: 32 additions & 10 deletions Networking/Sources/Networking/PKCS12.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,43 @@ enum CryptoError: Error {
case parseFailed(String)
}

public func parseCertificate(data: Data) throws -> (publicKey: Data, alternativeName: String) {
public enum CertificateType {
case x509
case p12
}

public func parseCertificate(data: Data, type: CertificateType) throws -> (
publicKey: Data, alternativeName: String
) {
var publicKeyPointer: UnsafeMutablePointer<UInt8>!
var publicKeyLen = 0
var altNamePointer: UnsafeMutablePointer<Int8>!
var errorMessage: UnsafeMutablePointer<Int8>?
defer { free(altNamePointer) }
let result = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
parse_pkcs12_certificate(
bytes.baseAddress!.assumingMemoryBound(to: UInt8.self),
data.count,
&publicKeyPointer,
&publicKeyLen,
&altNamePointer,
&errorMessage
)

let result: Int32 = switch type {
case .x509:
data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
parse_certificate(
bytes.baseAddress!.assumingMemoryBound(to: UInt8.self),
data.count,
&publicKeyPointer,
&publicKeyLen,
&altNamePointer,
&errorMessage
)
}
case .p12:
data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
parse_pkcs12_certificate(
bytes.baseAddress!.assumingMemoryBound(to: UInt8.self),
data.count,
&publicKeyPointer,
&publicKeyLen,
&altNamePointer,
&errorMessage
)
}
}

guard result == 0 else {
Expand Down
4 changes: 2 additions & 2 deletions Networking/Sources/Networking/Peer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ private struct PeerEventHandler<Handler: StreamHandler>: QuicEventHandler {
return .code(.requiredCert)
}
do {
let (publicKey, alternativeName) = try parseCertificate(data: certificate)
let (publicKey, alternativeName) = try parseCertificate(data: certificate,type: .x509)

Check failure on line 269 in Networking/Sources/Networking/Peer.swift

View workflow job for this annotation

GitHub Actions / Swift Lint

Comma Spacing (comma)

There should be no space before and one after any comma
logger.debug(
"Certificate parsed",
metadata: ["publicKey": "\(publicKey.toHexString())", "alternativeName": "\(alternativeName)"]
Expand Down Expand Up @@ -385,7 +385,7 @@ public final class MockPeerEventHandler: QuicEventHandler {
return .code(.requiredCert)
}
do {
let (publicKey, alternativeName) = try parseCertificate(data: certificate)
let (publicKey, alternativeName) = try parseCertificate(data: certificate,type: .x509)

Check failure on line 388 in Networking/Sources/Networking/Peer.swift

View workflow job for this annotation

GitHub Actions / Swift Lint

Comma Spacing (comma)

There should be no space before and one after any comma
if alternativeName != generateSubjectAlternativeName(pubkey: publicKey) {
return .code(.badCert)
}
Expand Down
60 changes: 60 additions & 0 deletions Networking/Tests/NetworkingTests/MockPeerEventTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,66 @@ final class MockPeerEventTests {
)
}

@Test
func connected() async throws {
let serverHandler = MockPeerEventHandler()
let clientHandler = MockPeerEventHandler()
let privateKey1 = try Ed25519.SecretKey(from: Data32())
let cert = try generateSelfSignedCertificate(privateKey: privateKey1)
let serverConfiguration = try QuicConfiguration(
registration: registration,
pkcs12: certData,
alpns: [Data("testalpn".utf8)],
client: false,
settings: QuicSettings.defaultSettings
)

let listener = try QuicListener(
handler: serverHandler,
registration: registration,
configuration: serverConfiguration,
listenAddress: NetAddr(ipAddress: "127.0.0.1", port: 0)!,
alpns: [Data("testalpn".utf8)]
)

let listenAddress = try listener.listenAddress()
// Client setup with certificate
let clientConfiguration = try QuicConfiguration(
registration: registration,
pkcs12: cert,
alpns: [Data("testalpn".utf8)],
client: true,
settings: QuicSettings.defaultSettings
)

let clientConnection = try QuicConnection(
handler: clientHandler,
registration: registration,
configuration: clientConfiguration
)

// Attempt to connect
try clientConnection.connect(to: listenAddress)
let stream1 = try clientConnection.createStream()
try stream1.send(data: Data("test data 1".utf8))

try? await Task.sleep(for: .milliseconds(100))
let (_, info) = serverHandler.events.value.compactMap {
switch $0 {
case let .newConnection(_, connection, info):
(connection, info) as (QuicConnection, ConnectionInfo)?
default:
nil
}
}.first!
let (ipAddress2, _) = info.remoteAddress.getAddressAndPort()

#expect(info.negotiatedAlpn == Data("testalpn".utf8))
#expect(info.serverName == "127.0.0.1")
#expect(info.localAddress == listenAddress)
#expect(ipAddress2 == "127.0.0.1")
}

@Test
func rejectsConDueToBadClientCert() async throws {
let serverHandler = MockPeerEventHandler()
Expand Down
6 changes: 3 additions & 3 deletions Networking/Tests/NetworkingTests/PKCS12Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import Utils
struct PKCS12Tests {
@Test func invalidParseCertificate() async throws {
#expect(throws: CryptoError.self) {
_ = try parseCertificate(data: Data("wrong cert data".utf8))
_ = try parseCertificate(data: Data("wrong cert data".utf8), type: .p12)
}
}

@Test func vailidParseCertificate() async throws {
@Test func vailidParseP12Certificate() async throws {
let privateKey = try Ed25519.SecretKey(from: Data32())
let cert = try generateSelfSignedCertificate(privateKey: privateKey)
let (publicKey, alternativeName) = try parseCertificate(data: cert)
let (publicKey, alternativeName) = try parseCertificate(data: cert, type: .p12)
#expect(alternativeName == generateSubjectAlternativeName(publicKey: privateKey.publicKey))
#expect(Data32(publicKey) == privateKey.publicKey.data)
}
Expand Down
Loading

0 comments on commit 8849624

Please sign in to comment.