|
@@ -13598,6 +13598,72 @@ inline bool tls_update_server_cert(tls_ctx_t ctx, const char *cert_pem,
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// Helper: Create client CA list from PEM string
|
|
|
|
|
+// Returns a new STACK_OF(X509_NAME)* or nullptr on failure
|
|
|
|
|
+// Caller takes ownership of returned list
|
|
|
|
|
+inline STACK_OF(X509_NAME) *
|
|
|
|
|
+ create_client_ca_list_from_pem(const char *ca_pem) {
|
|
|
|
|
+ if (!ca_pem) { return nullptr; }
|
|
|
|
|
+
|
|
|
|
|
+ auto ca_list = sk_X509_NAME_new_null();
|
|
|
|
|
+ if (!ca_list) { return nullptr; }
|
|
|
|
|
+
|
|
|
|
|
+ BIO *bio = BIO_new_mem_buf(ca_pem, -1);
|
|
|
|
|
+ if (!bio) {
|
|
|
|
|
+ sk_X509_NAME_pop_free(ca_list, X509_NAME_free);
|
|
|
|
|
+ return nullptr;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ X509 *cert = nullptr;
|
|
|
|
|
+ while ((cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) !=
|
|
|
|
|
+ nullptr) {
|
|
|
|
|
+ X509_NAME *name = X509_get_subject_name(cert);
|
|
|
|
|
+ if (name) { sk_X509_NAME_push(ca_list, X509_NAME_dup(name)); }
|
|
|
|
|
+ X509_free(cert);
|
|
|
|
|
+ }
|
|
|
|
|
+ BIO_free(bio);
|
|
|
|
|
+
|
|
|
|
|
+ return ca_list;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Helper: Extract CA names from X509_STORE
|
|
|
|
|
+// Returns a new STACK_OF(X509_NAME)* or nullptr on failure
|
|
|
|
|
+// Caller takes ownership of returned list
|
|
|
|
|
+inline STACK_OF(X509_NAME) *
|
|
|
|
|
+ extract_client_ca_list_from_store(X509_STORE *store) {
|
|
|
|
|
+ if (!store) { return nullptr; }
|
|
|
|
|
+
|
|
|
|
|
+ auto ca_list = sk_X509_NAME_new_null();
|
|
|
|
|
+ if (!ca_list) { return nullptr; }
|
|
|
|
|
+
|
|
|
|
|
+ auto objs = X509_STORE_get0_objects(store);
|
|
|
|
|
+ if (!objs) {
|
|
|
|
|
+ sk_X509_NAME_free(ca_list);
|
|
|
|
|
+ return nullptr;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
|
|
|
|
+ auto obj = sk_X509_OBJECT_value(objs, i);
|
|
|
|
|
+ if (X509_OBJECT_get_type(obj) == X509_LU_X509) {
|
|
|
|
|
+ auto cert = X509_OBJECT_get0_X509(obj);
|
|
|
|
|
+ if (cert) {
|
|
|
|
|
+ auto subject = X509_get_subject_name(cert);
|
|
|
|
|
+ if (subject) {
|
|
|
|
|
+ auto name_dup = X509_NAME_dup(subject);
|
|
|
|
|
+ if (name_dup) { sk_X509_NAME_push(ca_list, name_dup); }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (sk_X509_NAME_num(ca_list) == 0) {
|
|
|
|
|
+ sk_X509_NAME_free(ca_list);
|
|
|
|
|
+ return nullptr;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ca_list;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
inline bool tls_update_server_client_ca(tls_ctx_t ctx, const char *ca_pem) {
|
|
inline bool tls_update_server_client_ca(tls_ctx_t ctx, const char *ca_pem) {
|
|
|
if (!ctx || !ca_pem) { return false; }
|
|
if (!ctx || !ca_pem) { return false; }
|
|
|
auto ssl_ctx = static_cast<SSL_CTX *>(ctx);
|
|
auto ssl_ctx = static_cast<SSL_CTX *>(ctx);
|
|
@@ -13608,6 +13674,14 @@ inline bool tls_update_server_client_ca(tls_ctx_t ctx, const char *ca_pem) {
|
|
|
|
|
|
|
|
// SSL_CTX_set_cert_store takes ownership
|
|
// SSL_CTX_set_cert_store takes ownership
|
|
|
SSL_CTX_set_cert_store(ssl_ctx, static_cast<X509_STORE *>(store));
|
|
SSL_CTX_set_cert_store(ssl_ctx, static_cast<X509_STORE *>(store));
|
|
|
|
|
+
|
|
|
|
|
+ // Set client CA list for client certificate request
|
|
|
|
|
+ auto ca_list = create_client_ca_list_from_pem(ca_pem);
|
|
|
|
|
+ if (ca_list) {
|
|
|
|
|
+ // SSL_CTX_set_client_CA_list takes ownership of ca_list
|
|
|
|
|
+ SSL_CTX_set_client_CA_list(ssl_ctx, ca_list);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -13739,16 +13813,17 @@ inline tls_ctx_t create_server_context_from_x509(X509 *cert, EVP_PKEY *key,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (client_ca_store) {
|
|
if (client_ca_store) {
|
|
|
- auto ca_pem = x509_store_to_pem(client_ca_store);
|
|
|
|
|
- if (!ca_pem.empty()) {
|
|
|
|
|
- auto ca_store = tls_create_ca_store(ca_pem.c_str(), ca_pem.size());
|
|
|
|
|
- if (ca_store && tls_set_ca_store(ctx, ca_store)) {
|
|
|
|
|
- tls_set_verify_client(ctx, true);
|
|
|
|
|
- } else {
|
|
|
|
|
- out_error = static_cast<int>(tls_get_error());
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // Set cert store for verification (SSL_CTX_set_cert_store takes ownership)
|
|
|
|
|
+ SSL_CTX_set_cert_store(static_cast<SSL_CTX *>(ctx), client_ca_store);
|
|
|
|
|
+
|
|
|
|
|
+ // Extract and set client CA list directly from store (more efficient than
|
|
|
|
|
+ // PEM conversion)
|
|
|
|
|
+ auto ca_list = extract_client_ca_list_from_store(client_ca_store);
|
|
|
|
|
+ if (ca_list) {
|
|
|
|
|
+ SSL_CTX_set_client_CA_list(static_cast<SSL_CTX *>(ctx), ca_list);
|
|
|
}
|
|
}
|
|
|
- X509_STORE_free(client_ca_store);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ tls_set_verify_client(ctx, true);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return ctx;
|
|
return ctx;
|