From dca082a392c284991592a3e74e5da597b9c4a372 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Tue, 15 Oct 2024 10:27:08 +1300 Subject: [PATCH] fix cert generation (#166) * fix cert generation and validation * update test --- Networking/Sources/CHelpers/helpers.c | 6 +- .../MsQuicSwift/QuicConfiguration.swift | 11 ++-- .../Sources/MsQuicSwift/QuicStatus.swift | 8 +++ Networking/Sources/Networking/Peer.swift | 2 +- .../MsQuicSwiftTests/QuicListenerTests.swift | 25 +++++--- .../Tests/NetworkingTests/PKCS12Tests.swift | 60 ++++++++++++++++++- 6 files changed, 94 insertions(+), 18 deletions(-) diff --git a/Networking/Sources/CHelpers/helpers.c b/Networking/Sources/CHelpers/helpers.c index 02c9436d..5d5b610a 100644 --- a/Networking/Sources/CHelpers/helpers.c +++ b/Networking/Sources/CHelpers/helpers.c @@ -37,9 +37,9 @@ int generate_self_signed_cert_and_pkcs12( // Set serial number (you might want to generate this randomly) ASN1_INTEGER_set(X509_get_serialNumber(cert), 1); - // // Set validity period (1 year) - // X509_gmtime_adj(X509_get_notBefore(cert), 0); - // X509_gmtime_adj(X509_get_notAfter(cert), 31536000L); + // Set validity period (1 year) + X509_gmtime_adj(X509_get_notBefore(cert), 0); + X509_gmtime_adj(X509_get_notAfter(cert), 31536000L); // Set subject and issuer (self-signed, so they're the same) X509_NAME *name = X509_get_subject_name(cert); diff --git a/Networking/Sources/MsQuicSwift/QuicConfiguration.swift b/Networking/Sources/MsQuicSwift/QuicConfiguration.swift index 06d70451..58840383 100644 --- a/Networking/Sources/MsQuicSwift/QuicConfiguration.swift +++ b/Networking/Sources/MsQuicSwift/QuicConfiguration.swift @@ -10,7 +10,7 @@ public final class QuicConfiguration: Sendable { _ptr.value } - public init(registration: QuicRegistration, pkcs12: Data, alpn: Data, settings: QuicSettings) throws { + public init(registration: QuicRegistration, pkcs12: Data, alpn: Data, client: Bool, settings: QuicSettings) throws { self.registration = registration var ptr: HQUIC? @@ -38,11 +38,14 @@ public final class QuicConfiguration: Sendable { cert.Asn1BlobLength = UInt32(pkcs12ptr.count) cert.PrivateKeyPassword = nil - let flags = + let flags = 0 + | (client ? QUIC_CREDENTIAL_FLAG_CLIENT.rawValue : 0) + // we validates it ourselves + | QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION.rawValue // we need custom validation of the certificate - QUIC_CREDENTIAL_FLAG_INDICATE_CERTIFICATE_RECEIVED.rawValue | + | QUIC_CREDENTIAL_FLAG_INDICATE_CERTIFICATE_RECEIVED.rawValue // so we don't need to deal with openssl objects - QUIC_CREDENTIAL_FLAG_USE_PORTABLE_CERTIFICATES.rawValue + | QUIC_CREDENTIAL_FLAG_USE_PORTABLE_CERTIFICATES.rawValue try withUnsafeMutablePointer(to: &cert) { certPtr in var credConfig = QUIC_CREDENTIAL_CONFIG( diff --git a/Networking/Sources/MsQuicSwift/QuicStatus.swift b/Networking/Sources/MsQuicSwift/QuicStatus.swift index bd3ec33f..df79be9e 100644 --- a/Networking/Sources/MsQuicSwift/QuicStatus.swift +++ b/Networking/Sources/MsQuicSwift/QuicStatus.swift @@ -85,4 +85,12 @@ public enum QuicStatusCode: UInt32, Equatable, Sendable, Codable { case internalError = 5 case tlsError = 126 case streamLimitReached = 86 + + case closeNotify = 0xBEBC300 + case badCert = 0xBEBC32A + case unsupportedCert = 0xBEBC32B + case revokedCert = 0xBEBC32C + case expiredCert = 0xBEBC32D + case unknownCert = 0xBEBC32E + case requiredCert = 0xBEBC374 } diff --git a/Networking/Sources/Networking/Peer.swift b/Networking/Sources/Networking/Peer.swift index 9d0d422f..cbb6a1bd 100644 --- a/Networking/Sources/Networking/Peer.swift +++ b/Networking/Sources/Networking/Peer.swift @@ -49,7 +49,7 @@ public final class Peer: Sendable { let registration = try QuicRegistration() let configuration = try QuicConfiguration( - registration: registration, pkcs12: config.pkcs12, alpn: config.alpn.data, settings: config.settings + registration: registration, pkcs12: config.pkcs12, alpn: config.alpn.data, client: false, settings: config.settings ) listener = try QuicListener( diff --git a/Networking/Tests/MsQuicSwiftTests/QuicListenerTests.swift b/Networking/Tests/MsQuicSwiftTests/QuicListenerTests.swift index b8b8115f..51a88a3f 100644 --- a/Networking/Tests/MsQuicSwiftTests/QuicListenerTests.swift +++ b/Networking/Tests/MsQuicSwiftTests/QuicListenerTests.swift @@ -19,7 +19,7 @@ struct QuicListenerTests { let registration: QuicRegistration init() throws { - setupTestLogger() + // setupTestLogger() registration = try QuicRegistration() } @@ -31,17 +31,18 @@ struct QuicListenerTests { // create listener let quicSettings = QuicSettings.defaultSettings - let configuration = try QuicConfiguration( + let serverConfiguration = try QuicConfiguration( registration: registration, pkcs12: pkcs12Data, alpn: Data("testalpn".utf8), + client: false, settings: quicSettings ) let listener = try QuicListener( handler: serverHandler, registration: registration, - configuration: configuration, + configuration: serverConfiguration, listenAddress: NetAddr(ipAddress: "127.0.0.1", port: 0), alpn: Data("testalpn".utf8) ) @@ -52,10 +53,18 @@ struct QuicListenerTests { // create connection to listener + let clientConfiguration = try QuicConfiguration( + registration: registration, + pkcs12: pkcs12Data, + alpn: Data("testalpn".utf8), + client: true, + settings: quicSettings + ) + let clientConnection = try QuicConnection( handler: clientHandler, registration: registration, - configuration: configuration + configuration: clientConfiguration ) try clientConnection.connect(to: listenAddress) @@ -64,7 +73,7 @@ struct QuicListenerTests { try stream1.send(with: Data("test data 1".utf8)) - try? await Task.sleep(for: .milliseconds(50)) + try? await Task.sleep(for: .milliseconds(100)) let serverConnection = serverHandler.events.value.compactMap { switch $0 { case let .newConnection(_, connection): @@ -77,7 +86,7 @@ struct QuicListenerTests { let stream2 = try serverConnection.createStream() try stream2.send(with: Data("other test data 2".utf8)) - try? await Task.sleep(for: .milliseconds(5)) + try? await Task.sleep(for: .milliseconds(100)) let remoteStream1 = clientHandler.events.value.compactMap { switch $0 { case let .streamStarted(_, stream): @@ -88,7 +97,7 @@ struct QuicListenerTests { }.first! try remoteStream1.send(with: Data("replay to 1".utf8)) - try? await Task.sleep(for: .milliseconds(5)) + try? await Task.sleep(for: .milliseconds(100)) let remoteStream2 = serverHandler.events.value.compactMap { switch $0 { case let .streamStarted(_, stream): @@ -99,7 +108,7 @@ struct QuicListenerTests { }.first! try remoteStream2.send(with: Data("another replay to 2".utf8)) - try? await Task.sleep(for: .milliseconds(5)) + try? await Task.sleep(for: .milliseconds(100)) let receivedData = serverHandler.events.value.compactMap { switch $0 { case let .dataReceived(_, data): diff --git a/Networking/Tests/NetworkingTests/PKCS12Tests.swift b/Networking/Tests/NetworkingTests/PKCS12Tests.swift index 79b65aae..6d89a1f7 100644 --- a/Networking/Tests/NetworkingTests/PKCS12Tests.swift +++ b/Networking/Tests/NetworkingTests/PKCS12Tests.swift @@ -1,4 +1,5 @@ import Foundation +import MsQuicSwift import Testing import Utils @@ -8,8 +9,63 @@ struct PKCS12Tests { @Test func generate() async throws { let privateKey = try Ed25519.SecretKey(from: Data32()) let cert = try generateSelfSignedCertificate(privateKey: privateKey) - print("len: \(cert.count)") - print(cert.toHexString()) #expect(cert.count > 0) + + let registration = try QuicRegistration() + + let serverHandler = MockQuicEventHandler() + let clientHandler = MockQuicEventHandler() + + // create listener + + let quicSettings = QuicSettings.defaultSettings + let serverConfiguration = try QuicConfiguration( + registration: registration, + pkcs12: cert, + alpn: Data("testalpn".utf8), + client: false, + settings: quicSettings + ) + + let listener = try QuicListener( + handler: serverHandler, + registration: registration, + configuration: serverConfiguration, + listenAddress: NetAddr(ipAddress: "127.0.0.1", port: 0), + alpn: Data("testalpn".utf8) + ) + + let listenAddress = try listener.listenAddress() + + // create connection to listener + + let clientConfiguration = try QuicConfiguration( + registration: registration, + pkcs12: cert, + alpn: Data("testalpn".utf8), + client: true, + settings: quicSettings + ) + + let clientConnection = try QuicConnection( + handler: clientHandler, + registration: registration, + configuration: clientConfiguration + ) + + try clientConnection.connect(to: listenAddress) + + try? await Task.sleep(for: .milliseconds(50)) + + let data = clientHandler.events.value.compactMap { + switch $0 { + case let .shouldOpen(_, certificate): + certificate as Data? + default: + nil + } + } + + #expect(data.first!.count > 0) } }