Skip to content

Commit

Permalink
parse certificate & test (#181)
Browse files Browse the repository at this point in the history
* avoid race conditions in stream (#173)

* avoid race conditions in stream

* fix

* update certificate

* update helpers

* update ignore

* udpate CHelpers

* need to fix public key

* update parseCertificate

* udpate ParseCertificate

* update swift format

* update clang format

* update clang format

* update error message

* update makefile

* update makefile

* update makefile

---------

Co-authored-by: Xiliang Chen <[email protected]>
  • Loading branch information
MacOMNI and xlc authored Oct 18, 2024
1 parent a961f5c commit 6d9e41b
Show file tree
Hide file tree
Showing 15 changed files with 361 additions and 279 deletions.
19 changes: 19 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 100
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
SplitEmptyFunction: false
AfterControlStatement: false
AfterClass: false
AfterStruct: false
BeforeElse: false
IndentBraces: false
AllowShortFunctionsOnASingleLine: false
BinPackParameters: false
BinPackArguments: false
AlignAfterOpenBracket: AlwaysBreak
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
PenaltyBreakBeforeFirstCallParameter: 0
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.DS_Store
.build
build
Packages
xcuserdata/
DerivedData/
Expand All @@ -20,3 +21,6 @@ tasks.json
*.swiftdeps~
Package.resolved
contents.xcworkspacedata
launch.json
settings.json
c_cpp_properties.json
31 changes: 29 additions & 2 deletions Boka/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ format-cargo:
.PHONY: format-all
format-all: format format-cargo

.PHONY: format-clang
format-clang:
find . \( -name "*.c" -o -name "helpers.h" \) -exec clang-format -i {} +

.PHONY: run
run: githooks
swift run --package-path Boka
123 changes: 108 additions & 15 deletions Networking/Sources/CHelpers/helpers.c
Original file line number Diff line number Diff line change
@@ -1,26 +1,118 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pkcs12.h>
#include <openssl/ssl3.h>
#include <openssl/x509v3.h>

#include "helpers.h"

// Function to parse certificate and extract public key and alternative name
int parse_pkcs12_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;
PKCS12 *p12 = NULL;
EVP_PKEY *pkey = NULL;
X509 *cert = NULL;
STACK_OF(X509) *ca = NULL;
STACK_OF(GENERAL_NAME) *alt_names = NULL;

bio = BIO_new_mem_buf(data, (int)length);
if (!bio) {
*error_message = "Failed to create BIO.";
goto cleanup;
}
p12 = d2i_PKCS12_bio(bio, NULL);
if (!p12) {
*error_message = "Failed to parse PKCS12.";
goto cleanup;
}

if (!PKCS12_parse(p12, NULL, &pkey, &cert, &ca)) {
*error_message = "Failed to parse PKCS12 structure.";
goto cleanup;
}

// Check if the key is ED25519
int sig_alg = X509_get_signature_nid(cert);
if (sig_alg != NID_ED25519) {
*error_message = "Certificate signature algorithm is not ED25519.";
goto cleanup;
}

// Extract 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 alternative name
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);
PKCS12_free(p12);
EVP_PKEY_free(pkey);
X509_free(cert);
sk_X509_pop_free(ca, X509_free);

return ret;
}

int generate_self_signed_cert_and_pkcs12(
const unsigned char *private_key_buf,
size_t private_key_len,
const char *alt_name, // null terminated string
unsigned char **pkcs12_data,
int *pkcs12_len
) {
int *pkcs12_len)
{
X509 *cert = NULL;
PKCS12 *p12 = NULL;
EVP_PKEY *ed25519_key = NULL;
unsigned char *temp_buf = NULL;
unsigned char *temp_buf = NULL;
int ret = 1;

// Create EVP_PKEY from the provided Ed25519 private key buffer
ed25519_key = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, private_key_buf, private_key_len);
ed25519_key =
EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, private_key_buf, private_key_len);
if (!ed25519_key) {
goto cleanup;
}
Expand All @@ -43,7 +135,8 @@ int generate_self_signed_cert_and_pkcs12(

// Set subject and issuer (self-signed, so they're the same)
X509_NAME *name = X509_get_subject_name(cert);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"Self-Signed Cert", -1, -1, 0);
X509_NAME_add_entry_by_txt(
name, "CN", MBSTRING_ASC, (unsigned char *)"Self-Signed Cert", -1, -1, 0);
X509_set_issuer_name(cert, name);

// Set public key
Expand All @@ -64,7 +157,7 @@ int generate_self_signed_cert_and_pkcs12(
goto cleanup;
}

// Create PKCS12 structure
// Create PKCS12 structure
p12 = PKCS12_create(NULL, "My Certificate", ed25519_key, cert, NULL, 0, 0, 0, 0, 0);
if (!p12) {
goto cleanup;
Expand All @@ -88,7 +181,7 @@ int generate_self_signed_cert_and_pkcs12(
// Actually encode the PKCS12 structure
*pkcs12_len = i2d_PKCS12(p12, &temp_buf);
if (*pkcs12_len <= 0) {
ret = 6;
ret = 6;
free(*pkcs12_data);
*pkcs12_data = NULL;
*pkcs12_len = 0;
Expand All @@ -98,16 +191,16 @@ int generate_self_signed_cert_and_pkcs12(
ret = 0;

cleanup:
if (ret != 0) {
ret = ERR_get_error();

}
if (ret != 0) {
ret = ERR_get_error();
}
X509_free(cert);
PKCS12_free(p12);
EVP_PKEY_free(ed25519_key);
return ret;
}

char *get_error_string(int error) {
char *get_error_string(int error)
{
return ERR_error_string(error, NULL);
}
18 changes: 13 additions & 5 deletions Networking/Sources/CHelpers/helpers.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
#include <stddef.h>
#include <arpa/inet.h>
#include <stddef.h>

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

int generate_self_signed_cert_and_pkcs12(
const unsigned char *private_key_buf,
size_t private_key_len,
const char *alt_name, // null terminated string
unsigned char **pkcs12_data,
int *pkcs12_len
);
int *pkcs12_len);

char *get_error_string(int error);

static inline uint16_t helper_ntohs(in_port_t netport) {
static inline uint16_t helper_ntohs(in_port_t netport)
{
return ntohs(netport);
}
}
15 changes: 11 additions & 4 deletions Networking/Sources/MsQuicSwift/QuicEventHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public struct ConnectionInfo: Sendable {
public let negotiatedAlpn: Data
public let serverName: String

public init(localAddress: NetAddr, remoteAddress: NetAddr, negotiatedAlpn: Data, serverName: String) {
public init(
localAddress: NetAddr, remoteAddress: NetAddr, negotiatedAlpn: Data, serverName: String
) {
self.localAddress = localAddress
self.remoteAddress = remoteAddress
self.negotiatedAlpn = negotiatedAlpn
Expand All @@ -24,7 +26,8 @@ public struct ConnectionInfo: Sendable {

public protocol QuicEventHandler: Sendable {
// listener events
func newConnection(_ listener: QuicListener, connection: QuicConnection, info: ConnectionInfo) -> QuicStatus
func newConnection(_ listener: QuicListener, connection: QuicConnection, info: ConnectionInfo)
-> QuicStatus

// connection events
func shouldOpen(_ connection: QuicConnection, certificate: Data?) -> QuicStatus
Expand All @@ -39,7 +42,9 @@ public protocol QuicEventHandler: Sendable {

// default implementations
extension QuicEventHandler {
public func newConnection(_: QuicListener, connection _: QuicConnection, info _: ConnectionInfo) -> QuicStatus {
public func newConnection(_: QuicListener, connection _: QuicConnection, info _: ConnectionInfo)
-> QuicStatus
{
.code(.success)
}

Expand Down Expand Up @@ -73,7 +78,9 @@ public final class MockQuicEventHandler: QuicEventHandler {

public init() {}

public func newConnection(_ listener: QuicListener, connection: QuicConnection, info: ConnectionInfo) -> QuicStatus {
public func newConnection(
_ listener: QuicListener, connection: QuicConnection, info: ConnectionInfo
) -> QuicStatus {
events.write { events in
events.append(.newConnection(listener: listener, connection: connection, info: info))
}
Expand Down
Loading

0 comments on commit 6d9e41b

Please sign in to comment.