From 3890809447ff6c7241336792de3803eb631004fe Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Tue, 29 Jul 2025 09:15:14 -0400 Subject: [PATCH 01/30] Initial Sectigo implementation containing sectigo-get-cert and sectigo-help commands --- docs/cli_usage.adoc | 233 +++++++++ docs/configuration.adoc | 20 + include/certifier/certifier_api_easy.h | 3 + include/certifier/property.h | 21 + internal_headers/certifier/certifier.h | 29 +- .../certifier/property_internal.h | 6 + internal_headers/certifier/sectigo_client.h | 94 ++++ libcertifier.cfg.sample | 28 +- src/certifier.c | 187 +++++--- src/certifier_api_easy.c | 201 +++++++- src/certifierclient.c | 1 + src/main.c | 314 ++++++++++++- src/property.c | 333 +++++++++++++ src/sectigo_client.c | 442 ++++++++++++++++++ tests/xc_apis/xc_api_tests.c | 34 +- 15 files changed, 1876 insertions(+), 70 deletions(-) create mode 100644 internal_headers/certifier/sectigo_client.h create mode 100644 src/sectigo_client.c diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index bd44df5..a3ec859 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -108,6 +108,15 @@ Same command with SAT authentication: ./certifierUtil print-cert -k -p ---- +*Fetch Sectigo Certificate* + +The certificate can be downloaded through the certificate ID returned as a result of running the command. + +---- +./certifierUtil sectigo-get-cert -C -I -e -s -N -r -b -A -x -G -E -O -J +-Z -U -T -K -u -l -W +---- + == *certifierUtil commands* |=== @@ -136,6 +145,12 @@ Same command with SAT authentication: | revoke | Revoke Certificate + +|sectigo-get-cert +|Requests Certificate from Sectigo + +|sectigo-help +|Provides information on implemented Sectigo commands |=== == *certifierUtil get-cert options* @@ -497,6 +512,139 @@ Disabled by default - Only error messages are shown. |=== +== *certifierUtil sectigo-get-cert options* + +|=== +| *Long Option* | *Short Option* | *Examples* | *Description* + +| help +| h +| --help + +-h +| Display this summary + +| common-name +| C +| --common-name + +-C +| Certificate common name + +| id +| I +| --id + +-I +| User or device ID + +| employee-type +| e +| --employee-type + +-e +| Employee type + +| server-platform +| s +| --server-platform + +-s +| Server platform + +| sensitive +| N +| --sensitive + +-N +| Mark as sensitive + +| project-name +| r +| --project-name + +-r +| Project name + +| business-justification +| b +| --business-justification + +-b +| Business justification + +| subject-alt-names +| A +| --subject-alt-names + +-A +| Subject alternative names (CSV) + +| ip-addresses +| x +| --ip-addresses + +-x +| IP addresses (CSV) + +| group-name +| G +| --group-name + +-G +| Group name + +| group-email +| E +| --group-email + +-E +| Group email + +| owner-fname +| O +| --owner-fname + +-O +| Owner first name + +| owner-lname +| J +| --owner-lname + +-J +| Owner last name + +| owner-email +| Z +| --owner-email + +-Z +| Owner email + +| owner-phonenum +| U +| --owner-phonenum + +-U +| Owner phone number + +| cert-type +| T +| --cert-type + +-T +| Certificate type + +| auth-token +| K +| --auth-token + +-K +| Sectigo API auth token + +| url +| u +| --url + +-u +| Sectigo API URL + +| config +| l +| --config + +-l +| Path to config file + +| tracking-id +| W +| --tracking-id + +-W +| Tracking ID + +|=== + *Configuration File* Configuration File is a file used to specify internal certifier util parameters such as timeouts, ecc curve types and other miscellaneous items. This file follows the JSON Format and can be manually editted from the `libcertifier.cfg.sample` template file present in the root directory. @@ -611,4 +759,89 @@ Note: 64-bit hex integer expected as input. | Mark request for a lite certificate. + Note: value type = `bool` +| libcertifier.sectigo.certifier.url +| "https://certs.xpki.io/api/createCertificate" +| Sectigo API endpoint URL + +| libcertifier.sectigo.auth.token +| "" +| Sectigo API authentication token + +| libcertifier.sectigo.common.name +| "example.com" +| Certificate common name (CN) + +| libcertifier.sectigo.group.name +| "Example Group" +| Group name for the certificate request + +| libcertifier.sectigo.group.email +| "group@example.com" +| Group email for notifications + +| libcertifier.sectigo.id +| "user123" +| User or device ID + +| libcertifier.sectigo.owner.fname +| "First" +| Owner's first name + +| libcertifier.sectigo.owner.lname +| "Last" +| Owner's last name + +| libcertifier.sectigo.employee.type +| "associate" +| Employee type (e.g., associate, employee, contractor) + +| libcertifier.sectigo.server.platform +| "Other" +| Server platform name. + +Note: Use any of the following options: Tomcat, Redhat Linux, Microsoft IIS 5.x and later, Apache/MODSSL, IBM HTTP server, Java Web Server (Javasoft/SUN), Oracle, SAP Web Application Server, Citrix, Other + +| libcertifier.sectigo.sensitive +| false +| Mark certificate as sensitive. + +Note: value type = `bool` + +| libcertifier.sectigo.project.name +| "ExampleProject" +| Project name + +| libcertifier.sectigo.business.justification +| "Testing" +| Business justification for the request + +| libcertifier.sectigo.subject.alt.names +| [] +| Subject alternative names. + +Note: value type = `array of strings` Pass empty array if you don't have. + +| libcertifier.sectigo.ip.addresses +| [] +| IP addresses. + +Note: value type = `array of strings` Pass empty array if you don't have. + +| libcertifier.sectigo.cert.type +| "comodo" +| Certificate type. + +Note: Always pass comodo for internet-facing apps + +| libcertifier.sectigo.owner.phonenum +| "1234567890" +| Owner's phone number + +| libcertifier.sectigo.owner.email +| "owner@example.com" +| Owner's email address + +| libcertifier.sectigo.tracking.id +| "1234" +| Tracking ID for the request + +| libcertifier.sectigo.source +| "libcertifier" +| Source identifier for the request + |=== diff --git a/docs/configuration.adoc b/docs/configuration.adoc index b4a31d2..ce20489 100644 --- a/docs/configuration.adoc +++ b/docs/configuration.adoc @@ -25,6 +25,26 @@ xref:libcertifier.adoc[*Back to Manual*] | libcertifier.tls.insecure.host | 0 | | libcertifier.tls.insecure.peer | 0 | | libcertifier.ext.key.usage | clientAuth,serverAuth | (See notes below) +| libcertifier.sectigo.certifier.url | https://certs.xpki.io/api/createCertificate | +| libcertifier.sectigo.auth.token | | +| libcertifier.sectigo.common.name | example.com | +| libcertifier.sectigo.group.name | ExampleGroup | +| libcertifier.sectigo.group.email | group@example.com | +| libcertifier.sectigo.id | user123 | +| libcertifier.sectigo.owner.fname | First | +| libcertifier.sectigo.owner.lname | Last | +| libcertifier.sectigo.employee.type | associate | +| libcertifier.sectigo.server.platform | Other | +| libcertifier.sectigo.sensitive | false | +| libcertifier.sectigo.project.name | ExampleProject | +| libcertifier.sectigo.business.justification | Testing | +| libcertifier.sectigo.subject.alt.names | [] | +| libcertifier.sectigo.ip.addresses | [] | +| libcertifier.sectigo.cert.type | comodo | +| libcertifier.sectigo.owner.phonenum | 1234567890 | +| libcertifier.sectigo.owner.email | owner@example.com | +| libcertifier.sectigo.tracking.id | 1234 | +| libcertifier.sectigo.source | libcertifier | |======= == Extended Key Usage values: diff --git a/include/certifier/certifier_api_easy.h b/include/certifier/certifier_api_easy.h index c7fc562..0037064 100644 --- a/include/certifier/certifier_api_easy.h +++ b/include/certifier/certifier_api_easy.h @@ -101,6 +101,9 @@ typedef enum CERTIFIER_MODE_PRINT_HELP = 65536, + CERTIFIER_MODE_SECTIGO_GET_CERT, + + CERTIFIER_MODE_SECTIGO_PRINT_HELP // 131072 is unused } CERTIFIER_MODE; diff --git a/include/certifier/property.h b/include/certifier/property.h index 7e01b6e..fa9412e 100644 --- a/include/certifier/property.h +++ b/include/certifier/property.h @@ -202,6 +202,27 @@ typedef enum CERTIFIER_OPT */ CERTIFIER_OPT_MTLS_P12_PATH, CERTIFIER_OPT_MTLS_P12_PASSWORD, + + CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, + CERTIFIER_OPT_SECTIGO_COMMON_NAME, + CERTIFIER_OPT_SECTIGO_GROUP_NAME, + CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, + CERTIFIER_OPT_SECTIGO_ID, + CERTIFIER_OPT_SECTIGO_OWNER_FNAME, + CERTIFIER_OPT_SECTIGO_OWNER_LNAME, + CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, + CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, + CERTIFIER_OPT_SECTIGO_SENSITIVE, + CERTIFIER_OPT_SECTIGO_PROJECT_NAME, + CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, + CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, + CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, + CERTIFIER_OPT_SECTIGO_CERT_TYPE, + CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM, + CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, + CERTIFIER_OPT_SECTIGO_TRACKING_ID, + CERTIFIER_OPT_SECTIGO_SOURCE, + CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, } CERTIFIER_OPT; diff --git a/internal_headers/certifier/certifier.h b/internal_headers/certifier/certifier.h index 2204277..e2264fa 100644 --- a/internal_headers/certifier/certifier.h +++ b/internal_headers/certifier/certifier.h @@ -21,6 +21,10 @@ #include "certifier/property.h" #include "certifier/types.h" +#include "certifier/error.h" +#include "certifier/property_internal.h" + +#define SMALL_STRING_SIZE 64 #ifdef __cplusplus extern "C" { @@ -28,7 +32,6 @@ extern "C" { /* CHUNK is the size of the memory chunk used by the zlib routines. */ #define CHUNK 10000 - #define ALLOWABLE_CHARACTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnpqrstuvwxyz0123456879" #define CERTIFIER_ERR_INIT_CERTIFIER 1000 @@ -138,7 +141,23 @@ typedef enum CERTIFIER_LOG_FATAL } CertifierLogPriority; -typedef struct Certifier Certifier; +typedef struct Map +{ + char node_address[SMALL_STRING_SIZE]; + char * base64_public_key; + unsigned char * der_public_key; + int der_public_key_len; + ECC_KEY * private_ec_key; + X509_CERT * x509_cert; +} Map; + +typedef struct Certifier +{ + CertifierPropMap * prop_map; + Map tmp_map; + CertifierError last_error; + bool sectigo_mode; +} Certifier; Certifier * certifier_new(void); @@ -165,6 +184,8 @@ bool certifier_is_option_set(Certifier * certifier, int name); */ int certifier_load_cfg_file(Certifier * certifier); +int sectigo_load_cfg_file(Certifier * certifier); + char * certifier_get_version(Certifier * certifier); /** @@ -250,6 +271,10 @@ void certifier_print_certificate(Certifier * certifier, const char * pem, int pe void certifier_print_certificate_validity(Certifier * certifier); +CertifierError sectigo_generate_certificate_signing_request(Certifier *certifier, char **out_csr_pem); + +CertifierPropMap * certifier_get_prop_map(Certifier * certifier); + #ifdef __cplusplus } #endif diff --git a/internal_headers/certifier/property_internal.h b/internal_headers/certifier/property_internal.h index f1a79c6..38a0669 100644 --- a/internal_headers/certifier/property_internal.h +++ b/internal_headers/certifier/property_internal.h @@ -49,6 +49,8 @@ typedef struct _PropMap CertifierPropMap; */ CertifierPropMap * property_new(void); +CertifierPropMap * property_new_sectigo(void); + CertifierPropMap * property_ext(void); int property_destroy(CertifierPropMap * prop_map); @@ -76,12 +78,16 @@ int property_set_ext(CertifierPropMap * prop_map); int property_set(CertifierPropMap * prop_map, CERTIFIER_OPT name, const void * value); +int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * value); + int property_set_int(CertifierPropMap * prop_map, CERTIFIER_OPT name, int value); void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name); int property_set_defaults_from_cfg_file(CertifierPropMap * propMap); +int property_set_sectigo_defaults_from_cfg_file(CertifierPropMap * propMap); + const char * get_default_cfg_filename(); const char * get_default_ca_path(); diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h new file mode 100644 index 0000000..acc8338 --- /dev/null +++ b/internal_headers/certifier/sectigo_client.h @@ -0,0 +1,94 @@ +/** + * Copyright 2019 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SECTIGO_CLIENT_H +#define SECTIGO_CLIENT_H + + +#include +#include +#include +#include +#include +#include +#include +#include + +extern pthread_mutex_t lock; + +#ifdef __cplusplus +extern "C" { +#endif + + +#define IMPULSE_URL "https://certs-dev.xpki.io/" +typedef struct{ +const char * sectigo_auth_token; +const char * sectigo_common_name; +const char * sectigo_group_name; +const char * sectigo_group_email; +const char * sectigo_id; +const char * sectigo_owner_fname; +const char * sectigo_owner_lname; +const char * sectigo_employee_type; +const char * sectigo_server_platform; +bool sectigo_sensitive; +const char * sectigo_project_name; +const char * sectigo_business_justification; +const char * sectigo_subject_alt_names; +const char * sectigo_ip_addresses; +const char * sectigo_owner_phonenum; +const char * sectigo_owner_email; +const char * sectigo_cert_type; +const char * sectigo_url; +const char * sectigo_tracking_id; + + +} get_cert_sectigo_param_t; + + +typedef enum{ + SECTIGO_CLIENT_SUCCESS = 0, + SECTIGO_CLIENT_INVALID_ARGUMENT, + SECTIGO_CLIENT_NOT_IMPLEMENTED, + SECTIGO_CLIENT_ERROR_INTERNAL, + +} SECTIGO_CLIENT_ERROR_CODE; + +typedef enum +{ + SECTIGO_AUTH_X509, + SECTIGO_AUTH_SAT, +} SECTIGO_AUTH_TYPE; + +CertifierError sectigo_client_request_certificate(CertifierPropMap * props, const unsigned char * csr, +const char * node_address, const char * certifier_id, char ** out_cert); + +CertifierError sectigo_generate_certificate_signing_request(Certifier *certifier, char **out_csr_pem); + +Certifier * get_sectigo_certifier_instance(); + +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params); + +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(get_cert_sectigo_param_t * params); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index 570ab17..d0d92be 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -1,8 +1,8 @@ { "libcertifier.certifier.url": "https://certifier.xpki.io/v1/certifier", - "libcertifier.profile.name": "XFN_Matter_OP_Class_3_ICA", + "libcertifier.profile.name": "Xfinity_Default_Issuing_ECC_ICA", "libcertifier.validity.days": 365, - "libcertifier.auth.type": "X509", + "libcertifier.auth.type": "x509", "libcertifier.ecc.curve.id": "prime256v1", "libcertifier.http.connect.timeout": 20, "libcertifier.http.timeout": 20, @@ -23,5 +23,27 @@ "libcertifier.product.id":"1101", "libcertifier.cn.name":"AAAAAAAA", "libcertifier.node.id":"CCCCCCCCCCCCCCCC", - "libcertifier.ext.key.usage":"critical,clientAuth,serverAuth" + "libcertifier.ext.key.usage":"critical,clientAuth,serverAuth", + + "libcertifier.sectigo.certifier.url": "https://certs.xpki.io/api/createCertificate", + "libcertifier.sectigo.auth.token": "", + "libcertifier.sectigo.common.name": "example.com", + "libcertifier.sectigo.group.name": "Example Group", + "libcertifier.sectigo.group.email": "group@example.com", + "libcertifier.sectigo.id": "user123", + "libcertifier.sectigo.owner.fname": "First", + "libcertifier.sectigo.owner.lname": "Last", + "libcertifier.sectigo.employee.type": "associate", + "libcertifier.sectigo.server.platform": "Other", + "libcertifier.sectigo.sensitive": false, + "libcertifier.sectigo.project.name": "ExampleProject", + "libcertifier.sectigo.business.justification": "Testing", + "libcertifier.sectigo.subject.alt.names": [], + "libcertifier.sectigo.ip.addresses": [], + "libcertifier.sectigo.cert.type": "comodo", + "libcertifier.sectigo.owner.phonenum": "1234567890", + "libcertifier.sectigo.owner.email": "owner@example.com", + "libcertifier.sectigo.tracking.id": "1234", + "libcertifier.sectigo.source": "libcertifier" + } diff --git a/src/certifier.c b/src/certifier.c index 93b0f3f..8dffc9e 100644 --- a/src/certifier.c +++ b/src/certifier.c @@ -31,6 +31,16 @@ #include "certifier/timer.h" #include "curl/curl.h" +#include +#include +#include +#include +#include +#include +#include "certifier/log.h" +#include "certifier/error.h" +#include "certifier/property.h" + #ifndef CERTIFIER_VERSION #define CERTIFIER_VERSION "0.1-071320 (opensource)" #endif @@ -43,22 +53,8 @@ static CERTIFIER_LOG_callback logger; -typedef struct Map -{ - char node_address[SMALL_STRING_SIZE]; - char * base64_public_key; - unsigned char * der_public_key; - int der_public_key_len; - ECC_KEY * private_ec_key; - X509_CERT * x509_cert; -} Map; - -struct Certifier -{ - CertifierPropMap * prop_map; - Map tmp_map; - CertifierError last_error; -}; + + static inline void free_tmp(Certifier * certifier); @@ -1014,50 +1010,51 @@ int certifier_set_property(Certifier * certifier, int name, const void * value) int return_code = 0; const void * origValue = property_get(certifier->prop_map, name); - return_code = property_set(certifier->prop_map, name, value); + if (certifier->sectigo_mode) { + // Only set Sectigo properties for Sectigo flows + return_code = sectigo_property_set(certifier->prop_map, name, value); + } else { + // Only set XPKI properties for XPKI flows + return_code = property_set(certifier->prop_map, name, value); + } if (return_code != 0) { return CERTIFIER_ERR_PROPERTY_SET + return_code; } - switch (name) - { + switch (name) +{ case CERTIFIER_OPT_CFG_FILENAME: { - log_info("Configuration file changed; loading settings"); - - /* Blow away all settings and reload from config to avoid mixed configs */ - CertifierPropMap * orig = certifier->prop_map; - certifier->prop_map = property_new(); - if (certifier->prop_map == NULL) - { - log_error("Could not allocate enough memory to construct certifier->prop_map"); - return CERTIFIER_ERR_PROPERTY_SET_MEMORY; - } - property_set(certifier->prop_map, name, value); - - if (value != NULL) - { - return_code = certifier_load_cfg_file(certifier); - } - else - { - return_code = 0; - } - - if (return_code == 0) - { - property_destroy(orig); - } - else - { - property_destroy(certifier->prop_map); - certifier->prop_map = orig; - return_code = property_set(certifier->prop_map, name, origValue); - log_warn("Failed to load configuration (configuration unmodified)!"); + log_info("Configuration file changed; loading settings"); + + CertifierPropMap *orig = certifier->prop_map; + int loader_result = 0; + + if (value != NULL) { + if (certifier->sectigo_mode) { + + loader_result = sectigo_load_cfg_file(certifier); + if (loader_result != 0) { + log_warn("Failed to load Sectigo configuration!"); + return CERTIFIER_ERR_PROPERTY_SET + loader_result; + } + } else { + loader_result = certifier_load_cfg_file(certifier); + if (loader_result == 0) { + + property_destroy(orig); + + } else { + property_destroy(certifier->prop_map); + certifier->prop_map = orig; + loader_result = property_set(certifier->prop_map, name, property_get(orig, name)); + log_warn("Failed to load configuration (configuration unmodified)!"); + return CERTIFIER_ERR_PROPERTY_SET + loader_result; + } } - - break; } + break; +} case CERTIFIER_OPT_LOG_FUNCTION: certifier_set_log_callback(certifier, value); @@ -1115,6 +1112,23 @@ int certifier_load_cfg_file(Certifier * certifier) return return_code; } +int sectigo_load_cfg_file(Certifier * certifier) +{ + NULL_CHECK(certifier); + + int return_code = 0; + + // Only set Sectigo keys from config + return_code = property_set_sectigo_defaults_from_cfg_file(certifier->prop_map); + + if (return_code != 0) + { + return_code = CERTIFIER_ERR_PROPERTY_SET + return_code; + } + + return return_code; +} + char * certifier_create_info(Certifier * certifier, const int return_code, const char * output) { if (certifier == NULL) @@ -1541,3 +1555,72 @@ char * certifier_create_csr_post_data(CertifierPropMap * props, const unsigned c return json_csr; } + +CertifierError sectigo_generate_certificate_signing_request(Certifier *certifier, char **out_csr_pem) { + CertifierError rc = CERTIFIER_ERROR_INITIALIZER; + EVP_PKEY *pkey = NULL; + X509_REQ *req = NULL; + X509_NAME *name = NULL; + BIO *bio = NULL; + BUF_MEM *bptr = NULL; + char *common_name = (char *)certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); + + if (!common_name) { + set_last_error(certifier, 14, "Common Name not set"); + rc.application_error_code = 14; + rc.application_error_msg = "Common Name not set"; + return rc; + } + + + pkey = EVP_PKEY_new(); + RSA *rsa = RSA_new(); + BIGNUM *bn = BN_new(); + BN_set_word(bn, RSA_F4); + + RSA_generate_key_ex(rsa, 2048, bn, NULL); + EVP_PKEY_assign_RSA(pkey, rsa); + BN_free(bn); + + + req = X509_REQ_new(); + X509_REQ_set_pubkey(req, pkey); + + name = X509_NAME_new(); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char*)common_name, -1, -1, 0); + X509_REQ_set_subject_name(req, name); + + if (!X509_REQ_sign(req, pkey, EVP_sha256())) { + set_last_error(certifier, 15, "Error signing CSR"); + rc.application_error_code = 15; + rc.application_error_msg = "Error signing CSR"; + goto cleanup; + } + + //CSR to PEM + bio = BIO_new(BIO_s_mem()); + PEM_write_bio_X509_REQ(bio, req); + BIO_get_mem_ptr(bio, &bptr); + + *out_csr_pem = (char *)malloc(bptr->length + 1); + memcpy(*out_csr_pem, bptr->data, bptr->length); + (*out_csr_pem)[bptr->length] = '\0'; + + rc.application_error_code = 0; + rc.application_error_msg = NULL; + +cleanup: + if (bio) BIO_free(bio); + if (req) X509_REQ_free(req); + if (name) X509_NAME_free(name); + if (pkey) EVP_PKEY_free(pkey); + return rc; +} + +CertifierPropMap * certifier_get_prop_map(Certifier * certifier) +{ + if (certifier == NULL) { + return NULL; + } + return certifier->prop_map; +} \ No newline at end of file diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index a0ef341..29c5386 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -26,6 +26,7 @@ #include "certifier/security.h" #include "certifier/types.h" #include "certifier/util.h" +#include "certifier/sectigo_client.h" #include #include @@ -56,6 +57,7 @@ #define GET_CERT_SHORT_OPTIONS "fT:P:o:i:n:F:a:w:" #define VALIDITY_DAYS_SHORT_OPTION "t:" #define CA_PATH_SHORT_OPTION "c:" +#define SECTIGO_GET_CERT_SHORT_OPTIONS "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:" #define BASE_LONG_OPTIONS \ { "help", no_argument, NULL, 'h' }, { "input-p12-path", required_argument, NULL, 'k' }, \ @@ -90,6 +92,31 @@ "ca-path", required_argument, NULL, 'c' \ } +#define SECTIGO_GET_CERT_LONG_OPTIONS \ + { "common-name", required_argument, NULL, 'C' }, \ + { "id", required_argument, NULL, 'I' }, \ + { "employee-type", required_argument, NULL, 'e' }, \ + { "server-platform", required_argument, NULL, 's' }, \ + { "sensitive", no_argument, NULL, 'N' }, \ + { "project-name", required_argument, NULL, 'r' }, \ + { "business-justification", required_argument, NULL, 'b' }, \ + { "subject-alt-names", required_argument, NULL, 'A' }, \ + { "ip-addresses", required_argument, NULL, 'x' }, \ + {"url", required_argument, NULL, 'u'}, \ + { "auth-token", required_argument, NULL, 'K' }, \ + { "group-name", required_argument, NULL, 'G' }, \ + { "group-email", required_argument, NULL, 'E' }, \ + { "owner-fname", required_argument, NULL, 'O' }, \ + { "owner-lname", required_argument, NULL, 'J' }, \ + { "owner-email", required_argument, NULL, 'Z' }, \ + { "owner-phonenum", required_argument, NULL, 'U' }, \ + { "cert-type", required_argument, NULL, 'T' }, \ + { "config", required_argument, NULL, 'l' }, \ + { "tracking-id", required_argument, NULL, 'W' }, \ + { NULL, 0, NULL, 0 } + //make default arg '*' for san and ip + //only take in choices=['fte', 'contractor', 'associate'] + static void finish_operation(CERTIFIER * easy, int return_code, const char * operation_output); // Private data @@ -304,6 +331,7 @@ CERTIFIER_MODE certifier_api_easy_get_mode(CERTIFIER * easy) { "renew-cert", CERTIFIER_MODE_RENEW_CERT }, { "print-cert", CERTIFIER_MODE_PRINT_CERT }, { "revoke", CERTIFIER_MODE_REVOKE_CERT }, + { "sectigo-get-cert", CERTIFIER_MODE_SECTIGO_GET_CERT} }; for (int i = 0; i < sizeof(command_map) / sizeof(command_map_t); ++i) @@ -739,6 +767,61 @@ static int do_print_cert(CERTIFIER * easy) return return_code; } +static int do_sectigo_get_cert(CERTIFIER * easy) +{ + int return_code = 0; + char * csr_pem = NULL; + char * cert = NULL; + + // Check for required Sectigo properties + const char *common_name = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); + const char *employee_type = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE); + const char *server_platform = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM); + const char *project_name = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME); + const char *business_justification = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION); + + if (util_is_empty(common_name) || util_is_empty(employee_type) || + util_is_empty(server_platform) || util_is_empty(project_name) || + util_is_empty(business_justification)) { + finish_operation(easy, CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1, + "Missing required Sectigo flags (common-name, employee-type, server-platform, project-name, business-justification)"); + return CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + } + + + return_code = certifier_setup_keys(easy->certifier); + if (return_code != 0) { + finish_operation(easy, return_code, NULL); + return return_code; + } + + //Generate CSR + CertifierError rc = sectigo_generate_certificate_signing_request(easy->certifier, &csr_pem); + if (rc.application_error_code != 0 || csr_pem == NULL) { + finish_operation(easy, rc.application_error_code, NULL); + return rc.application_error_code; + } + + // Call Sectigo client to request certificate + CertifierPropMap * props = certifier_easy_api_get_props(easy->certifier); + rc = sectigo_client_request_certificate(props, (unsigned char *)csr_pem, certifier_get_node_address(easy->certifier), NULL, &cert); + + + XFREE(csr_pem); + + //Handle result + if (rc.application_error_code == 0 && cert != NULL) { + finish_operation(easy, 0, cert); + XFREE(cert); + return 0; + } else { + finish_operation(easy, rc.application_error_code, rc.application_error_msg); + if (cert) XFREE(cert); + return rc.application_error_code; + } +} + + char * certifier_api_easy_get_version(CERTIFIER * easy) { if (easy == NULL) @@ -777,7 +860,8 @@ int certifier_api_easy_print_helper(CERTIFIER * easy) "get-cert-status\n" "renew-cert\n" "print-cert\n" - "revoke\n"); + "revoke\n" + "get-sectigo-cert"); } return 0; @@ -826,7 +910,8 @@ static int process_command_line(CERTIFIER * easy) static const char * const get_cert_status_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; static const char * const renew_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; static const char * const print_cert_short_options = BASE_SHORT_OPTIONS; - static const char * const revoke_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; + static const char * const revoke_cert_short_options = BASE_SHORT_OPTIONS; + static const char * const sectigo_get_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; static const struct option get_cert_long_opts[] = { BASE_LONG_OPTIONS, GET_CRT_TOKEN_LONG_OPTIONS, GET_CERT_LONG_OPTIONS, VALIDITY_DAYS_LONG_OPTION, @@ -836,6 +921,7 @@ static int process_command_line(CERTIFIER * easy) static const struct option renew_cert_long_opts[] = { BASE_LONG_OPTIONS, CA_PATH_LONG_OPTION, { NULL, 0, NULL, 0 } }; static const struct option print_cert_long_opts[] = { BASE_LONG_OPTIONS, { NULL, 0, NULL, 0 } }; static const struct option revoke_cert_long_opts[] = { BASE_LONG_OPTIONS, CA_PATH_LONG_OPTION, { NULL, 0, NULL, 0 } }; + static const struct option sectigo_get_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_GET_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; static command_opt_lut_t command_opt_lut[] = { { CERTIFIER_MODE_REGISTER, get_cert_short_options, get_cert_long_opts }, @@ -844,6 +930,7 @@ static int process_command_line(CERTIFIER * easy) { CERTIFIER_MODE_RENEW_CERT, renew_cert_short_options, renew_cert_long_opts }, { CERTIFIER_MODE_PRINT_CERT, print_cert_short_options, print_cert_long_opts }, { CERTIFIER_MODE_REVOKE_CERT, revoke_cert_short_options, revoke_cert_long_opts }, + {CERTIFIER_MODE_SECTIGO_GET_CERT, sectigo_get_cert_short_options, sectigo_get_cert_long_opts} }; char * version_string = certifier_api_easy_get_version(easy); @@ -1067,6 +1154,100 @@ static int process_command_line(CERTIFIER * easy) case 'v': return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_LOG_LEVEL, (void *) (size_t) 0); break; + case 'C': // common-name + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME, optarg); + } + break; + case 'I': // id + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_ID, optarg); + } + break; + case 'e': // employee-type + if (optarg) { + // Validate allowed values: "fte", "contractor", "associate" + if (strcmp(optarg, "fte") && strcmp(optarg, "contractor") && strcmp(optarg, "associate")) { + log_error("Invalid employee-type: %s. Allowed: fte, contractor, associate.", optarg); + return_code = 1; + break; + } + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, optarg); + } + break; + case 's': // server-platform + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, optarg); + } + break; + case 'N': // sensitive + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE, (void *)true); + break; + case 'r': // project-name + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, optarg); + } + break; + case 'b': // business-justification + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, optarg); + } + break; + case 'A': // subject-alt-names + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, optarg); + } + break; + case 'x': // ip-addresses + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, optarg); + } + break; + case 'K': // auth-token + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, optarg); + } + break; + case 'u': // sectigo url + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, optarg); + } + case 'G': // group-name + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_GROUP_NAME, optarg); + } + break; + case 'E': // group-email + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, optarg); + } + break; + case 'O': // owner-fname + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_FNAME, optarg); + } + break; + case 'J': // owner-lname + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_LNAME, optarg); + } + break; + case 'M': // owner-email + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, optarg); + } + break; + case 'Z': // owner-phonenum + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM, optarg); + } + break; + case 'U': // cert-type + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERT_TYPE, optarg); + } + break; + break; case '?': /* Case when user enters the command as * $ ./libCertifier -p @@ -1343,10 +1524,26 @@ int certifier_api_easy_perform(CERTIFIER * easy) break; } + //For SECTIGO MODE +switch(easy -> mode){ + case CERTIFIER_MODE_NONE: + break; + + case CERTIFIER_MODE_SECTIGO_GET_CERT: + do_sectigo_get_cert(easy); + break; + + default: + finish_operation(easy, -1, "Invalid mode"); + break; +} + cleanup: return easy->last_info.error_code; } + + http_response * certifier_api_easy_http_post(const CERTIFIER * easy, const char * url, const char * http_headers[], const char * csr) { diff --git a/src/certifierclient.c b/src/certifierclient.c index 6a4124e..7134ad6 100644 --- a/src/certifierclient.c +++ b/src/certifierclient.c @@ -634,3 +634,4 @@ CertifierError certifierclient_check_certificate_status(CertifierPropMap * props return rc; } + diff --git a/src/main.c b/src/main.c index 72a106f..627efc3 100644 --- a/src/main.c +++ b/src/main.c @@ -20,13 +20,10 @@ #include "certifier/log.h" #include "certifier/xpki_client.h" #include "certifier/xpki_client_internal.h" - -XPKI_CLIENT_ERROR_CODE xpki_perform(int argc, char ** argv); - -int main(int argc, char ** argv) -{ - return xpki_perform(argc, argv); -} +#include "certifier/sectigo_client.h" +#include "certifier/certifier_api_easy.h" +#include "certifier/certifier_internal.h" +#include "certifier/certifier.h" typedef enum { @@ -40,6 +37,14 @@ typedef enum XPKI_MODE_REVOKE_CERT, } XPKI_MODE; +typedef enum +{ + SECTIGO_MODE_NONE, + SECTIGO_MODE_GET_CERT, + SECTIGO_MODE_PRINT_HELP + +} SECTIGO_MODE; + typedef union { get_cert_param_t get_cert_param; @@ -47,6 +52,29 @@ typedef union renew_cert_param_t renew_cert_param; } xc_parameter_t; +typedef union +{ + get_cert_sectigo_param_t sectigo_get_cert_param; +}sectigo_parameter_t; + + +XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, int argc, char ** argv); +XPKI_CLIENT_ERROR_CODE xpki_perform(int argc, char ** argv); +SECTIGO_CLIENT_ERROR_CODE sectigo_perform(int argc, char ** argv); + +int main(int argc, char **argv) +{ + pthread_mutex_init(&lock, NULL); + // check for "sectigo-get-cert" as the first argument + if (argc > 1 && strncmp(argv[1], "sectigo", strlen("sectigo")) == 0) { + // Call Sectigo mode + return sectigo_perform(argc, argv); + } else { + // Default to XPKI mode + return xpki_perform(argc, argv); + } +} + XPKI_MODE xpki_get_mode(int argc, char ** argv) { if (argc <= 1 && argv[1] == NULL) @@ -78,6 +106,28 @@ XPKI_MODE xpki_get_mode(int argc, char ** argv) return XPKI_MODE_NONE; } +SECTIGO_MODE sectigo_get_mode(int argc, char ** argv){ + typedef struct{ + char * name; + SECTIGO_MODE mode; + } command_map_t; + + command_map_t command_map[] = { + {"sectigo-help", SECTIGO_MODE_PRINT_HELP}, {"sectigo-get-cert", SECTIGO_MODE_GET_CERT} + }; + + for(int i = 0; i < sizeof(command_map) / sizeof(command_map_t); ++i){ + if (strcmp(argv[1], command_map[i].name) == 0){ + return command_map[i].mode; + } + + } + + + return SECTIGO_MODE_NONE; +} + + XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) { if (mode == XPKI_MODE_PRINT_VERSION) @@ -111,11 +161,25 @@ XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) return XPKI_CLIENT_SUCCESS; } +SECTIGO_CLIENT_ERROR_CODE sectigo_print_helper(SECTIGO_MODE mode){ + if (mode == SECTIGO_MODE_PRINT_HELP || mode == SECTIGO_MODE_NONE) + { + XFPRINTF(stdout, + "Usage: certifierUtil [COMMANDS] [OPTIONS]\n" + "Commands:\n" + "help\n" + "sectigo-get-cert\n"); + } + + return SECTIGO_CLIENT_SUCCESS; +} + #define BASE_SHORT_OPTIONS "hp:L:k:vm" #define GET_CRT_TOKEN_SHORT_OPTIONS "X:S:" #define GET_CERT_SHORT_OPTIONS "fT:P:o:i:n:F:a:w:" #define VALIDITY_DAYS_SHORT_OPTION "t:" #define CA_PATH_SHORT_OPTION "c:" +#define SECTIGO_GET_CERT_SHORT_OPTIONS "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W" #define BASE_LONG_OPTIONS \ { "help", no_argument, NULL, 'h' }, { "input-p12-path", required_argument, NULL, 'k' }, \ @@ -150,6 +214,31 @@ XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) "ca-path", required_argument, NULL, 'c' \ } +#define SECTIGO_GET_CERT_LONG_OPTIONS \ + { "common-name", required_argument, NULL, 'C' }, \ + { "id", required_argument, NULL, 'I' }, \ + { "employee-type", required_argument, NULL, 'e' }, \ + { "server-platform", required_argument, NULL, 's' }, \ + { "sensitive", no_argument, NULL, 'N' }, \ + { "project-name", required_argument, NULL, 'r' }, \ + { "business-justification", required_argument, NULL, 'b' }, \ + { "subject-alt-names", required_argument, NULL, 'A' }, \ + { "ip-addresses", required_argument, NULL, 'x' }, \ + {"url", required_argument, NULL, 'u'}, \ + { "auth-token", required_argument, NULL, 'K' }, \ + { "group-name", required_argument, NULL, 'G' }, \ + { "group-email", required_argument, NULL, 'E' }, \ + { "owner-fname", required_argument, NULL, 'O' }, \ + { "owner-lname", required_argument, NULL, 'J' }, \ + { "owner-email", required_argument, NULL, 'Z' }, \ + { "owner-phonenum", required_argument, NULL, 'U' }, \ + { "cert-type", required_argument, NULL, 'T' }, \ + { "config", required_argument, NULL, 'l' }, \ + { "tracking-id", required_argument, NULL, 'W' }, \ + { NULL, 0, NULL, 0 } \ + //make default arg '*' for san and ip + //only take in choices=['fte', 'contractor', 'associate'] + typedef struct { XPKI_MODE mode; @@ -157,6 +246,14 @@ typedef struct const struct option * long_opts; } command_opt_lut_t; +typedef struct +{ + SECTIGO_MODE mode; + const char * short_opts; + const struct option * long_opts; +} sectigo_command_opt_lut_t; + + static size_t get_command_opt_index(command_opt_lut_t * command_opt_lut, size_t n_entries, XPKI_MODE mode) { for (size_t i = 0; i < n_entries; ++i) @@ -216,6 +313,8 @@ static const char * get_command_opt_helper(XPKI_MODE mode) } } + + XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, int argc, char ** argv) { VerifyOrReturnError(xc_parameter != NULL, XPKI_CLIENT_INVALID_ARGUMENT); @@ -234,8 +333,7 @@ XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, in break; default: return XPKI_CLIENT_NOT_IMPLEMENTED; - } - + } static const char * const get_cert_short_options = BASE_SHORT_OPTIONS GET_CRT_TOKEN_SHORT_OPTIONS GET_CERT_SHORT_OPTIONS VALIDITY_DAYS_SHORT_OPTION CA_PATH_SHORT_OPTION; static const char * const get_cert_status_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; @@ -451,6 +549,204 @@ XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, in return error_code; } +// --- Sectigo Option Table --- +static const char * const sectigo_get_cert_short_options = "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:h"; +static const struct option sectigo_get_cert_long_opts[] = { + { "common-name", required_argument, NULL, 'C' }, + { "id", required_argument, NULL, 'I' }, + { "employee-type", required_argument, NULL, 'e' }, + { "server-platform", required_argument, NULL, 's' }, + { "sensitive", no_argument, NULL, 'N' }, + { "project-name", required_argument, NULL, 'r' }, + { "business-justification", required_argument, NULL, 'b' }, + { "subject-alt-names", required_argument, NULL, 'A' }, + { "ip-addresses", required_argument, NULL, 'x' }, + {"url", required_argument, NULL, 'u'}, + { "auth-token", required_argument, NULL, 'K' }, + { "group-name", required_argument, NULL, 'G' }, + { "group-email", required_argument, NULL, 'E' }, + { "owner-fname", required_argument, NULL, 'O' }, + { "owner-lname", required_argument, NULL, 'J' }, + { "owner-email", required_argument, NULL, 'Z' }, + { "owner-phonenum", required_argument, NULL, 'U' }, + { "cert-type", required_argument, NULL, 'T' }, + { "config", required_argument, NULL, 'l' }, + { "tracking-id", required_argument, NULL, 'W' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } + //make default arg '*' for san and ip + //only take in choices=['fte', 'contractor', 'associate'] +}; + +// --- Sectigo Option Parsing --- +SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t * sectigo_parameter, int argc, char ** argv) +{ + VerifyOrReturnError(sectigo_parameter != NULL, SECTIGO_CLIENT_INVALID_ARGUMENT); + VerifyOrReturnError(argv != NULL, SECTIGO_CLIENT_INVALID_ARGUMENT); + + SECTIGO_CLIENT_ERROR_CODE error_code = SECTIGO_CLIENT_SUCCESS; + memset(§igo_parameter->sectigo_get_cert_param, 0, sizeof(get_cert_sectigo_param_t)); + sectigo_parameter->sectigo_get_cert_param.sectigo_subject_alt_names = ""; + sectigo_parameter->sectigo_get_cert_param.sectigo_ip_addresses = ""; + for (;;) + { + int option_index; + int opt = XGETOPT_LONG(argc, argv, sectigo_get_cert_short_options, + sectigo_get_cert_long_opts, &option_index); + + if (opt == -1 || error_code != SECTIGO_CLIENT_SUCCESS) + { + break; + } + + switch (opt) + { + case 'h': + XFPRINTF(stdout, + "Usage: certifierUtil sectigo-get-cert [OPTIONS]\n" + "--common-name [value] (-C)\n" + "--id [value] (-I)\n" + "--employee-type [value] (-e)\n" + "--server-platform [value] (-s)\n" + "--sensitive (-N)\n" + "--project-name [value] (-r)\n" + "--business-justification [value] (-b)\n" + "--subject-alt-names [value] (-A)\n" + "--ip-addresses [value] (-x)\n" + "--group-name [value] (-G)\n" + "--group-email [value] (-E)\n" + "--owner-fname [value] (-O)\n" + "--owner-lname [value] (-J)\n" + "--owner-email [value] (-Z)\n" + "--owner-phonenum [value] (-U)\n" + "--cert-type [value] (-T)\n" + "--auth-token [value] (-K)\n" + "--url [value] (-u)\n" + "--config [value] (-l)\n" + "--tracking-id [value] (-W)\n" +); + exit(0); + break; + case 'C': + sectigo_parameter->sectigo_get_cert_param.sectigo_common_name = optarg; + break; + case 'I': + sectigo_parameter->sectigo_get_cert_param.sectigo_id = optarg; + break; + case 'e': + sectigo_parameter->sectigo_get_cert_param.sectigo_employee_type = optarg; + break; + case 's': + sectigo_parameter->sectigo_get_cert_param.sectigo_server_platform = optarg; + break; + case 'N': + sectigo_parameter->sectigo_get_cert_param.sectigo_sensitive = true; + break; + case 'r': + sectigo_parameter->sectigo_get_cert_param.sectigo_project_name = optarg; + break; + case 'b': + sectigo_parameter->sectigo_get_cert_param.sectigo_business_justification = optarg; + break; + case 'A': + sectigo_parameter->sectigo_get_cert_param.sectigo_subject_alt_names = optarg; + break; + case 'x': + sectigo_parameter->sectigo_get_cert_param.sectigo_ip_addresses = optarg; + break; + case 'l': + // config file path, handled in sectigo_perform + break; + case 'G': + sectigo_parameter->sectigo_get_cert_param.sectigo_group_name = optarg; + break; + case 'E': + sectigo_parameter->sectigo_get_cert_param.sectigo_group_email = optarg; + break; + case 'O': + sectigo_parameter->sectigo_get_cert_param.sectigo_owner_fname = optarg; + break; + case 'J': + sectigo_parameter->sectigo_get_cert_param.sectigo_owner_lname = optarg; + break; + case 'Z': + sectigo_parameter->sectigo_get_cert_param.sectigo_owner_email = optarg; + break; + case 'U': + sectigo_parameter->sectigo_get_cert_param.sectigo_owner_phonenum = optarg; + break; + case 'T': + sectigo_parameter->sectigo_get_cert_param.sectigo_cert_type = optarg; + break; + case 'K': + sectigo_parameter->sectigo_get_cert_param.sectigo_auth_token = optarg; + break; + case 'u': + sectigo_parameter->sectigo_get_cert_param.sectigo_url = optarg; + break; + case 'W': + sectigo_parameter->sectigo_get_cert_param.sectigo_tracking_id = optarg; + break; + case '?': + log_info("Invalid or missing Sectigo option"); + error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; + break; + default: + log_info("Unknown Sectigo option: %c", opt); + error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; + break; + } + } + + return error_code; +} +SECTIGO_CLIENT_ERROR_CODE sectigo_perform(int argc, char ** argv){ + SECTIGO_MODE mode = sectigo_get_mode(argc, argv); + const char *config_path = NULL; + if (mode == SECTIGO_MODE_NONE || mode == SECTIGO_MODE_PRINT_HELP) + { + return sectigo_print_helper(mode); + } + if (argc <= 2) { + fprintf(stderr, "Error: No arguments provided after 'sectigo-get-cert'.\n"); + return SECTIGO_CLIENT_INVALID_ARGUMENT; + } + sectigo_parameter_t sectigo_parameter; + ReturnErrorOnFailure(sectigo_process(mode, §igo_parameter, argc - 1, &argv[1])); + switch (mode) + { + + case SECTIGO_MODE_GET_CERT: + Certifier *certifier = NULL; + for (int i = 1; i < argc - 1; ++i) { + if ((strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--config") == 0) && (i + 1 < argc)) { + config_path = argv[i + 1]; + break; + } + } + if (config_path) { + certifier = get_sectigo_certifier_instance(); + certifier->sectigo_mode = true; + certifier_set_property(certifier, CERTIFIER_OPT_CFG_FILENAME, config_path); + log_debug("Config loaded, certifier pointer: %p", (void*)certifier); + + } + if (!certifier) { + log_error("Certifier instance is NULL!"); + return SECTIGO_CLIENT_ERROR_INTERNAL; +} + + return xc_sectigo_get_cert(§igo_parameter.sectigo_get_cert_param); + break; + case SECTIGO_MODE_NONE: + case SECTIGO_MODE_PRINT_HELP: + return sectigo_print_helper(mode); + break; + default: + break; + } + return SECTIGO_CLIENT_SUCCESS; +} XPKI_CLIENT_ERROR_CODE xpki_perform(int argc, char ** argv) { XPKI_MODE mode = xpki_get_mode(argc, argv); diff --git a/src/property.c b/src/property.c index 8413ed6..7dae88b 100644 --- a/src/property.c +++ b/src/property.c @@ -53,6 +53,32 @@ #define DEFAULT_AUTORENEW_INTERVAL 86400 #define DEFAULT_AUTORENEW_CERTS_PATH "~/.libcertifier" +static char * simple_json_array_to_csv(const char *json_array_str) +{ + // Assumes input like ["a","b","c"] + if (!json_array_str || json_array_str[0] != '[') return XSTRDUP(""); + size_t len = strlen(json_array_str); + char *csv = XCALLOC(len + 1, sizeof(char)); + if (!csv) return NULL; + + size_t j = 0; + bool in_string = false; + for (size_t i = 0; i < len; ++i) { + char c = json_array_str[i]; + if (c == '"') { + in_string = !in_string; + continue; + } + if (in_string) { + csv[j++] = c; + } else if (c == ',' && j > 0) { + csv[j++] = ','; + } + } + csv[j] = '\0'; + return csv; +} + const char * get_default_cfg_filename() { static char cfg[] = DEFAULT_CFG_FILENAME; @@ -175,6 +201,27 @@ struct _PropMap X509_CERT * cert_x509_out; char * mtls_filename; char * mtls_p12_filename; + //Sectigo values + char * sectigo_auth_token; + char * sectigo_common_name; + char * sectigo_group_name; + char * sectigo_group_email; + char * sectigo_id; + char * sectigo_owner_fname; + char * sectigo_owner_lname; + char * sectigo_employee_type; + char * sectigo_server_platform; + bool sectigo_sensitive; + char * sectigo_project_name; + char * sectigo_business_justification; + char * sectigo_subject_alt_names; + char * sectigo_ip_addresses; + char * sectigo_owner_phonenum; + char * sectigo_owner_email; + char * sectigo_cert_type; + char * sectigo_tracking_id; + char * sectigo_source; + char * sectigo_url; }; static void free_prop_map_values(CertifierPropMap * prop_map); @@ -311,6 +358,85 @@ int property_set_int(CertifierPropMap * prop_map, CERTIFIER_OPT name, int value) return retval; } +int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * value) +{ + int retval = 0; + switch (name) + { + case CERTIFIER_OPT_CFG_FILENAME: + prop_map->cfg_filename = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_LOG_LEVEL: + prop_map->log_level = (int)(size_t)value; + log_set_level(prop_map->log_level); + break; + case CERTIFIER_OPT_SECTIGO_AUTH_TOKEN: + prop_map->sectigo_auth_token = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_COMMON_NAME: + prop_map->sectigo_common_name = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_GROUP_NAME: + prop_map->sectigo_group_name = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_GROUP_EMAIL: + prop_map->sectigo_group_email = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_ID: + prop_map->sectigo_id = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_OWNER_FNAME: + prop_map->sectigo_owner_fname = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_OWNER_LNAME: + prop_map->sectigo_owner_lname = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE: + prop_map->sectigo_employee_type = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM: + prop_map->sectigo_server_platform = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_SENSITIVE: + prop_map->sectigo_sensitive = (bool)(size_t)value; + break; + case CERTIFIER_OPT_SECTIGO_PROJECT_NAME: + prop_map->sectigo_project_name = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION: + prop_map->sectigo_business_justification = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES: + prop_map->sectigo_subject_alt_names = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_IP_ADDRESSES: + prop_map->sectigo_ip_addresses = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_CERT_TYPE: + prop_map->sectigo_cert_type = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM: + prop_map->sectigo_owner_phonenum = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_OWNER_EMAIL: + prop_map->sectigo_owner_email = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_TRACKING_ID: + prop_map->sectigo_tracking_id = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_SOURCE: + prop_map->sectigo_source = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_CERTIFIER_URL: + prop_map->sectigo_url = XSTRDUP((const char *)value); + break; + default: + log_warn("sectigo_property_set: unrecognized property [%d]", name); + retval = CERTIFIER_ERR_PROPERTY_SET_10; + break; + } + return retval; +} int property_set(CertifierPropMap * prop_map, CERTIFIER_OPT name, const void * value) { int retval = 0; @@ -771,6 +897,67 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) break; } + case CERTIFIER_OPT_SECTIGO_AUTH_TOKEN: + retval = (void *) prop_map->sectigo_auth_token; + break; + case CERTIFIER_OPT_SECTIGO_COMMON_NAME: + retval = (void *) prop_map->sectigo_common_name; + break; + case CERTIFIER_OPT_SECTIGO_GROUP_NAME: + retval = (void *) prop_map->sectigo_group_name; + break; + case CERTIFIER_OPT_SECTIGO_GROUP_EMAIL: + retval = (void *) prop_map->sectigo_group_email; + break; + case CERTIFIER_OPT_SECTIGO_ID: + retval = (void *) prop_map->sectigo_id; + break; + case CERTIFIER_OPT_SECTIGO_OWNER_FNAME: + retval = (void *) prop_map->sectigo_owner_fname; + break; + case CERTIFIER_OPT_SECTIGO_OWNER_LNAME: + retval = (void *) prop_map->sectigo_owner_lname; + break; + case CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE: + retval = (void *) prop_map->sectigo_employee_type; + break; + case CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM: + retval = (void *) prop_map->sectigo_server_platform; + break; + case CERTIFIER_OPT_SECTIGO_SENSITIVE: + retval = (void *)(size_t) prop_map->sectigo_sensitive; + break; + case CERTIFIER_OPT_SECTIGO_PROJECT_NAME: + retval = (void *) prop_map->sectigo_project_name; + break; + case CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION: + retval = (void *) prop_map->sectigo_business_justification; + break; + case CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES: + retval = (void *) prop_map->sectigo_subject_alt_names; + break; + case CERTIFIER_OPT_SECTIGO_IP_ADDRESSES: + retval = (void *) prop_map->sectigo_ip_addresses; + break; + case CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM: + retval = (void *) prop_map->sectigo_owner_phonenum; + break; + case CERTIFIER_OPT_SECTIGO_OWNER_EMAIL: + retval = (void *) prop_map->sectigo_owner_email; + break; + case CERTIFIER_OPT_SECTIGO_CERT_TYPE: + retval = (void *) prop_map->sectigo_cert_type; + break; + case CERTIFIER_OPT_SECTIGO_TRACKING_ID: + retval = (void *) prop_map->sectigo_tracking_id; + break; + case CERTIFIER_OPT_SECTIGO_SOURCE: + retval = (void *) prop_map->sectigo_source; + break; + case CERTIFIER_OPT_SECTIGO_CERTIFIER_URL: + retval = (void *) prop_map->sectigo_url; + break; + default: log_warn("property_get: unrecognized property [%d]", name); retval = NULL; @@ -947,6 +1134,121 @@ int property_set_defaults(CertifierPropMap * prop_map) return return_code; } +int property_set_sectigo_defaults_from_cfg_file(CertifierPropMap * propMap) +{ + JSON_Value *json; + int ret = 0; + char *file_contents = NULL; + size_t file_contents_len = 0; + + log_info("Loading Sectigo cfg file: %s", propMap->cfg_filename); + + ret = util_slurp(propMap->cfg_filename, &file_contents, &file_contents_len); + if (ret != 0) { + log_error("Failed to read config file: %s", propMap->cfg_filename); + if (file_contents) XFREE(file_contents); + return 1; + } + + file_contents[file_contents_len] = '\0'; + json = json_parse_string_with_comments(file_contents); + XFREE(file_contents); + if (!json) { + log_error("Failed to parse JSON config file: %s", propMap->cfg_filename); + return 1; + } + + JSON_Object *root = json_object(json); + size_t count = json_object_get_count(root); + for (size_t i = 0; i < count; ++i) { + const char *key = json_object_get_name(root, i); + + // Only process keys starting with "libcertifier.sectigo." + if (strncmp(key, "libcertifier.sectigo.", strlen("libcertifier.sectigo.")) != 0) { + continue; + } + + + + // Handle boolean for sensitive + if (strcmp(key, "libcertifier.sectigo.sensitive") == 0) { + int bool_val = json_object_get_boolean(root, key); + propMap->sectigo_sensitive = (bool)bool_val; + continue; + } + + // Handle arrays for subject alt names and ip addresses + if (strcmp(key, "libcertifier.sectigo.subject.alt.names") == 0) { + const char *array_str = json_object_get_string(root, key); + char *csv = NULL; + if (array_str) { + csv = simple_json_array_to_csv(array_str); + } else { + csv = XSTRDUP(""); // Always set to empty string if missing/empty + } + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, csv); + XFREE(csv); + continue; +} +if (strcmp(key, "libcertifier.sectigo.ip.addresses") == 0) { + const char *array_str = json_object_get_string(root, key); + char *csv = NULL; + if (array_str) { + csv = simple_json_array_to_csv(array_str); + } else { + csv = XSTRDUP(""); + } + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, csv); + XFREE(csv); + continue; +} + + const char *value_str = json_object_get_string(root, key); + if (value_str) { + // Map config key to property enum + if (strcmp(key, "libcertifier.sectigo.auth.token") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, value_str); + else if (strcmp(key, "libcertifier.sectigo.common.name") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_COMMON_NAME, value_str); + else if (strcmp(key, "libcertifier.sectigo.group.name") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_GROUP_NAME, value_str); + else if (strcmp(key, "libcertifier.sectigo.group.email") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, value_str); + else if (strcmp(key, "libcertifier.sectigo.id") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_ID, value_str); + else if (strcmp(key, "libcertifier.sectigo.owner.fname") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_FNAME, value_str); + else if (strcmp(key, "libcertifier.sectigo.owner.lname") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_LNAME, value_str); + else if (strcmp(key, "libcertifier.sectigo.employee.type") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, value_str); + else if (strcmp(key, "libcertifier.sectigo.server.platform") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, value_str); + else if (strcmp(key, "libcertifier.sectigo.project.name") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, value_str); + else if (strcmp(key, "libcertifier.sectigo.business.justification") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, value_str); + else if (strcmp(key, "libcertifier.sectigo.owner.phonenum") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM, value_str); + else if (strcmp(key, "libcertifier.sectigo.owner.email") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, value_str); + else if (strcmp(key, "libcertifier.sectigo.cert.type") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERT_TYPE, value_str); + else if (strcmp(key, "libcertifier.sectigo.certifier.url") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, value_str); + else if (strcmp(key, "libcertifier.sectigo.tracking.id") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_TRACKING_ID, value_str); + else if (strcmp(key, "libcertifier.sectigo.source") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SOURCE, value_str); + // Add more mappings as needed + } + } + + if (json) json_value_free(json); + return 0; +} + + int property_set_ext(CertifierPropMap * prop_map) { JSON_Value * json; @@ -1339,4 +1641,35 @@ static void free_prop_map_values(CertifierPropMap * prop_map) security_free_cert(prop_map->cert_x509_out); FV(prop_map->mtls_filename); FV(prop_map->mtls_p12_filename); + FV(prop_map->sectigo_auth_token); + FV(prop_map->sectigo_common_name); + FV(prop_map->sectigo_group_name); + FV(prop_map->sectigo_group_email); + FV(prop_map->sectigo_id); + FV(prop_map->sectigo_owner_fname); + FV(prop_map->sectigo_owner_lname); + FV(prop_map->sectigo_employee_type); + FV(prop_map->sectigo_server_platform); + FV(prop_map->sectigo_project_name); + FV(prop_map->sectigo_business_justification); + FV(prop_map->sectigo_subject_alt_names); + FV(prop_map->sectigo_ip_addresses); + FV(prop_map->sectigo_owner_phonenum); + FV(prop_map->sectigo_owner_email); + FV(prop_map->sectigo_cert_type); + FV(prop_map->sectigo_tracking_id); + FV(prop_map->sectigo_source); + FV(prop_map->sectigo_url); +} + +CertifierPropMap * property_new_sectigo(void) +{ + CertifierPropMap * prop_map = XCALLOC(1, sizeof(CertifierPropMap)); + if (prop_map == NULL) + { + log_error("Could not initialize CertifierPropMap."); + return NULL; + } + + return prop_map; } diff --git a/src/sectigo_client.c b/src/sectigo_client.c new file mode 100644 index 0000000..2842fc8 --- /dev/null +++ b/src/sectigo_client.c @@ -0,0 +1,442 @@ +/** + * Copyright 2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "certifier/sectigo_client.h" +#include +#include +#include "certifier/code_utils.h" +#include "certifier/types.h" +#include "certifier/certifierclient.h" +#include "certifier/certifier_internal.h" +#include "certifier/http.h" +#include "certifier/log.h" +#include "certifier/parson.h" +#include "certifier/util.h" +#include "certifier/error.h" +#include "certifier/property_internal.h" + +#include +#include +#include +pthread_mutex_t lock; + +Certifier * get_sectigo_certifier_instance() +{ + static Certifier * certifier = NULL; + + if (certifier == NULL) + { + certifier = XCALLOC(1, sizeof(Certifier)); + certifier->sectigo_mode = true; + certifier->prop_map = property_new_sectigo(); + certifier_set_property(certifier, CERTIFIER_OPT_LOG_LEVEL, (void *) (size_t) 0); + certifier_set_property(certifier, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, "https://certs-dev.xpki.io/api/createCertificate"); + } + return certifier; +} + + +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(get_cert_sectigo_param_t * params) +{ + Certifier * certifier = get_sectigo_certifier_instance(); + + memset(params, 0, sizeof(get_cert_sectigo_param_t)); + + void * param = NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); +params->sectigo_auth_token = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); +params->sectigo_common_name = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_GROUP_NAME); +params->sectigo_group_name = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL); +params->sectigo_group_email = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_ID); +params->sectigo_id = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_FNAME); +params->sectigo_owner_fname = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_LNAME); +params->sectigo_owner_lname = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE); +params->sectigo_employee_type = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM); +params->sectigo_server_platform = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME); +params->sectigo_project_name = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION); +params->sectigo_business_justification = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES); +params->sectigo_subject_alt_names = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES); +params->sectigo_ip_addresses = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERT_TYPE); +params->sectigo_cert_type = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM); +params->sectigo_owner_phonenum = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL); +params->sectigo_owner_email = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL); +params->sectigo_url = param ? XSTRDUP((const char *)param) : NULL; + +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE); +params->sectigo_sensitive = param ? *((bool *)param) : false; + + return SECTIGO_CLIENT_SUCCESS; +} + + +CertifierError sectigo_client_request_certificate(CertifierPropMap * props, const unsigned char * csr, +const char * node_address, const char * certifier_id, char ** out_cert) + +{ + Certifier *certifier = get_sectigo_certifier_instance(); + CertifierError rc = CERTIFIER_ERROR_INITIALIZER; + JSON_Value *root_value = NULL; + JSON_Object *root_obj = NULL; + char *json_body = NULL; + if (out_cert == NULL) + { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("out cert cannot be null"); + return rc; + } + + char auth_header[VERY_LARGE_STRING_SIZE * 4] = ""; + char tracking_header[LARGE_STRING_SIZE] = ""; + char source_header[SMALL_STRING_SIZE] = ""; + JSON_Object * parsed_json_object_value = NULL; + JSON_Value * parsed_json_root_value = NULL; + char * serialized_string = NULL; + http_response * resp = NULL; + const char * tracking_id = property_get(props, CERTIFIER_OPT_SECTIGO_TRACKING_ID); + const char * bearer_token = property_get(props, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); + const char * source = property_get(props, CERTIFIER_OPT_SECTIGO_SOURCE); + const char * certifier_url = property_get(props, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL); + + + if (!tracking_id) { + log_error("Missing CERTIFIER_OPT_SECTIGO_TRACKING_ID"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Tracking ID is missing"); + goto cleanup; +} + +if (!bearer_token) { + log_error("Missing CERTIFIER_OPT_SECTIGO_AUTH_TOKEN"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Bearer token is missing"); + goto cleanup; +} +if (!certifier_url) { + log_error("Missing CERTIFIER_OPT_SECTIGO_CERTIFIER_URL"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Certifier URL is missing"); + goto cleanup; +} +if (!source) { + log_error("Missing CERTIFIER_OPT_SECTIGO_SOURCE"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Source is missing"); + goto cleanup; +} + + log_debug("Tracking ID is: %s\n", tracking_id); + log_debug("Source ID is: %s\n", source); + + + + +if (bearer_token != NULL) { + snprintf(auth_header, sizeof(auth_header), "Authorization: %s", bearer_token); +} +snprintf(tracking_header, sizeof(tracking_header), "x-xpki-request-id: %s", tracking_id); +snprintf(source_header, sizeof(source_header), "x-xpki-source: %s", source); + +const char *headers[] = { + "Accept: */*", + "Connection: keep-alive", + "cache-control: no-cache", + "Content-Type: application/json", + source_header, + tracking_header, + "x-xpki-partner-id: comcast", + auth_header, + NULL +}; + + if (util_is_empty(source)) + { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("CERTIFIER_OPT_SECTIGO_SOURCE must be set to a non-empty string!"); + goto cleanup; + } + + + + CertifierError csr_rc = sectigo_generate_certificate_signing_request(certifier, &serialized_string); + if (csr_rc.application_error_code != 0 || serialized_string == NULL) { + rc.application_error_code = csr_rc.application_error_code; + rc.application_error_msg = csr_rc.application_error_msg; + goto cleanup; +} + // Take Mutex + if (pthread_mutex_lock(&lock) != 0) + { + rc.application_error_code = 17; + rc.application_error_msg = "sectigo_client_request_certificate: pthread_mutex_lock failed"; + goto cleanup; + } + // Give Mutex + if (pthread_mutex_unlock(&lock) != 0) + { + rc.application_error_code = 18; + rc.application_error_msg = "sectigo_client_request_certificate: pthread_mutex_unlock failed"; + goto cleanup; + } + get_cert_sectigo_param_t params; + xc_sectigo_get_default_cert_param(¶ms); + // Build JSON body + root_value = json_value_init_object(); + root_obj = json_value_get_object(root_value); + + json_object_set_string(root_obj, "certificateSigningRequest", serialized_string); + + json_object_set_string(root_obj, "commonName", params.sectigo_common_name ? params.sectigo_common_name : ""); +json_object_set_string(root_obj, "groupName", params.sectigo_group_name ? params.sectigo_group_name : ""); +json_object_set_string(root_obj, "groupEmailAddress", params.sectigo_group_email ? params.sectigo_group_email : ""); +json_object_set_string(root_obj, "id", params.sectigo_id ? params.sectigo_id : ""); +json_object_set_string(root_obj, "ownerFirstName", params.sectigo_owner_fname ? params.sectigo_owner_fname : ""); +json_object_set_string(root_obj, "ownerLastName", params.sectigo_owner_lname ? params.sectigo_owner_lname : ""); +json_object_set_string(root_obj, "employeeType", params.sectigo_employee_type ? params.sectigo_employee_type : ""); +json_object_set_string(root_obj, "serverPlatform", params.sectigo_server_platform ? params.sectigo_server_platform : ""); +json_object_set_string(root_obj, "projectName", params.sectigo_project_name ? params.sectigo_project_name : ""); +json_object_set_string(root_obj, "businessJustification", params.sectigo_business_justification ? params.sectigo_business_justification : ""); +json_object_set_string(root_obj, "certificateType", params.sectigo_cert_type ? params.sectigo_cert_type : ""); +json_object_set_string(root_obj, "ownerPhoneNumber", params.sectigo_owner_phonenum ? params.sectigo_owner_phonenum : ""); +json_object_set_string(root_obj, "ownerEmailAddress", params.sectigo_owner_email ? params.sectigo_owner_email : ""); +json_object_set_string(root_obj, "certifierUrl", params.sectigo_url ? params.sectigo_url : ""); +json_object_set_value(root_obj, "sensitive", json_value_init_boolean(params.sectigo_sensitive)); + // Always set subjectAltNames and ipAddresses, even if empty + +// subjectAltNames as array +JSON_Value *san_array = json_value_init_array(); +JSON_Array *san_json_array = json_value_get_array(san_array); +if (params.sectigo_subject_alt_names && strlen(params.sectigo_subject_alt_names) > 0) { + char *san_copy = XSTRDUP(params.sectigo_subject_alt_names); + char *token = strtok(san_copy, ","); + while (token) { + json_array_append_value(san_json_array, json_value_init_string(token)); + token = strtok(NULL, ","); + } + XFREE(san_copy); +} +json_object_set_value(root_obj, "subjectAltNames", san_array); + +// ipAddresses as array +JSON_Value *ip_array = json_value_init_array(); +JSON_Array *ip_json_array = json_value_get_array(ip_array); +if (params.sectigo_ip_addresses && strlen(params.sectigo_ip_addresses) > 0) { + char *ip_copy = XSTRDUP(params.sectigo_ip_addresses); + char *token = strtok(ip_copy, ","); + while (token) { + json_array_append_value(ip_json_array, json_value_init_string(token)); + token = strtok(NULL, ","); + } + XFREE(ip_copy); +} +json_object_set_value(root_obj, "ipAddresses", ip_array); + json_body = json_serialize_to_string(root_value); + + + resp = http_post(props, certifier_url, headers, json_body); + if (resp == NULL) + { + goto cleanup; + } + + + rc.application_error_code = resp->error; + + // Check for errors + if (resp->error != 0) + { + rc.application_error_msg = util_format_curl_error("sectigo_client_request_certificate", resp->http_code, resp->error, + resp->error_msg, resp->payload, __FILE__, __LINE__); + goto cleanup; + } + + if (resp->payload == NULL) + { + log_error("ERROR: Failed to populate payload"); + goto cleanup; + } + + + parsed_json_root_value = json_parse_string_with_comments(resp->payload); + if (json_value_get_type(parsed_json_root_value) != JSONObject) + { + rc.application_error_msg = + util_format_curl_error("sectigo_client_request_certificate", resp->http_code, resp->error, + "Could not parse JSON. Expected it to be an array.", resp->payload, __FILE__, __LINE__); + goto cleanup; + } + + parsed_json_object_value = json_value_get_object(parsed_json_root_value); + + if (parsed_json_object_value == NULL) + { + rc.application_error_msg = + util_format_curl_error("sectigo_client_request_certificate", resp->http_code, resp->error, + "Could not parse JSON. parsed_json_object_value is NULL!.", resp->payload, __FILE__, __LINE__); + goto cleanup; + } + + + +cleanup: + + http_free_response(resp); + + if (parsed_json_root_value) + { + json_value_free(parsed_json_root_value); + } + + XFREE(serialized_string); + if (json_body) + json_free_serialized_string(json_body); + if (root_value) + json_value_free(root_value); + return rc; +} + +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params) +{ + Certifier *certifier = get_sectigo_certifier_instance(); + + // Build JSON body + JSON_Value *root_value = json_value_init_object(); + JSON_Object *root_obj = json_value_get_object(root_value); + + // Add all parameters to JSON body using passed-in params + if (params->sectigo_common_name) + json_object_set_string(root_obj, "commonName", params->sectigo_common_name); + if (params->sectigo_group_name) + json_object_set_string(root_obj, "groupName", params->sectigo_group_name); + if (params->sectigo_group_email) + json_object_set_string(root_obj, "groupEmailAddress", params->sectigo_group_email); +if (params->sectigo_id) + json_object_set_string(root_obj, "id", params->sectigo_id); +if (params->sectigo_owner_fname) + json_object_set_string(root_obj, "ownerFirstName", params->sectigo_owner_fname); +if (params->sectigo_owner_lname) + json_object_set_string(root_obj, "ownerLastName", params->sectigo_owner_lname); +if (params->sectigo_employee_type) + json_object_set_string(root_obj, "employeeType", params->sectigo_employee_type); +if (params->sectigo_server_platform) + json_object_set_string(root_obj, "serverPlatform", params->sectigo_server_platform); +if (params->sectigo_project_name) + json_object_set_string(root_obj, "projectName", params->sectigo_project_name); +if (params->sectigo_business_justification) + json_object_set_string(root_obj, "businessJustification", params->sectigo_business_justification); +// subjectAltNames as array +JSON_Value *san_array = json_value_init_array(); +JSON_Array *san_json_array = json_value_get_array(san_array); +if (params->sectigo_subject_alt_names && strlen(params->sectigo_subject_alt_names) > 0) { + char *san_copy = XSTRDUP(params->sectigo_subject_alt_names); + char *token = strtok(san_copy, ","); + while (token) { + json_array_append_value(san_json_array, json_value_init_string(token)); + token = strtok(NULL, ","); + } + XFREE(san_copy); +} +json_object_set_value(root_obj, "subjectAltNames", san_array); + +// ipAddresses as array +JSON_Value *ip_array = json_value_init_array(); +JSON_Array *ip_json_array = json_value_get_array(ip_array); +if (params->sectigo_ip_addresses && strlen(params->sectigo_ip_addresses) > 0) { + char *ip_copy = XSTRDUP(params->sectigo_ip_addresses); + char *token = strtok(ip_copy, ","); + while (token) { + json_array_append_value(ip_json_array, json_value_init_string(token)); + token = strtok(NULL, ","); + } + XFREE(ip_copy); +} +json_object_set_value(root_obj, "ipAddresses", ip_array); +if (params->sectigo_cert_type) + json_object_set_string(root_obj, "certificateType", params->sectigo_cert_type); +if (params->sectigo_owner_phonenum) + json_object_set_string(root_obj, "ownerPhoneNumber", params->sectigo_owner_phonenum); +if (params->sectigo_owner_email) + json_object_set_string(root_obj, "ownerEmailAddress", params->sectigo_owner_email); +if (params->sectigo_url) + json_object_set_string(root_obj, "certifierUrl", params->sectigo_url); + // Generate CSR and add to body + char *csr_pem = NULL; + CertifierError csr_rc = sectigo_generate_certificate_signing_request(certifier, &csr_pem); + if (csr_rc.application_error_code != 0 || csr_pem == NULL) { + log_error("Failed to generate CSR: %s", csr_rc.application_error_msg); + if (csr_pem) XFREE(csr_pem); + json_value_free(root_value); + return csr_rc.application_error_code; + } + json_object_set_string(root_obj, "certificateSigningRequest", csr_pem); + + // Serialize JSON body + char *json_body = json_serialize_to_string(root_value); + + // Call the request function + CertifierPropMap *props = certifier_get_prop_map(certifier); + char *cert_output = NULL; + CertifierError req_rc = sectigo_client_request_certificate( + props, + (unsigned char *)csr_pem, + NULL, // node_address + NULL, // certifier_id + &cert_output + ); + + + + // Cleanup + if (csr_pem) XFREE(csr_pem); + if (json_body) json_free_serialized_string(json_body); + if (root_value) json_value_free(root_value); + + return req_rc.application_error_code; +} diff --git a/tests/xc_apis/xc_api_tests.c b/tests/xc_apis/xc_api_tests.c index 183c30e..9e5fc67 100644 --- a/tests/xc_apis/xc_api_tests.c +++ b/tests/xc_apis/xc_api_tests.c @@ -18,7 +18,7 @@ #include #include - +#include #include static const char * token = NULL; @@ -237,7 +237,36 @@ static void test_get_cert_validity() TEST_ASSERT_EQUAL_INT(XPKI_CLIENT_SUCCESS, error); TEST_ASSERT_EQUAL_INT(XPKI_CLIENT_CERT_ABOUT_TO_EXPIRE, status); } - +static void test_get_sectigo_cert() +{ + SECTIGO_CLIENT_ERROR_CODE error; + get_cert_sectigo_param_t params = { 0 }; + + // Fill parameters (simulate config or CLI) + params.sectigo_auth_token = "token"; + params.sectigo_common_name = "sectigotest.comcast.com"; + params.sectigo_group_name = "GroupName"; + params.sectigo_group_email = "example@comcast.com"; + params.sectigo_id = "exid"; + params.sectigo_owner_fname = "First"; + params.sectigo_owner_lname = "Last"; + params.sectigo_employee_type = "associate"; + params.sectigo_server_platform = "other"; + params.sectigo_sensitive = "false"; + params.sectigo_project_name = "Testing create with SAT"; + params.sectigo_business_justification = "Testing create with SAT"; + params.sectigo_subject_alt_names = "*"; + params.sectigo_ip_addresses = "*"; + params.sectigo_cert_type = "comodo"; + params.sectigo_owner_phonenum = "2670000000"; + params.sectigo_owner_email = "first_last@comcast.com"; + params.sectigo_url = "https://certs-dev.xpki.io/api/createCertificate"; + + // Call the API + error = xc_sectigo_get_cert(¶ms); + + TEST_ASSERT_EQUAL_INT(SECTIGO_CLIENT_SUCCESS, error); +} int main(int argc, char ** argv) { UNITY_BEGIN(); @@ -254,6 +283,7 @@ int main(int argc, char ** argv) RUN_TEST(test_renew_cert); RUN_TEST(test_print_cert_validity); RUN_TEST(test_get_cert_validity); + RUN_TEST(test_get_sectigo_cert); return UNITY_END(); } From 3ebb090bbaa3a0e519bc53cb26e090cbfe94883f Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Mon, 4 Aug 2025 09:36:07 -0400 Subject: [PATCH 02/30] Update libcertifier.cfg.sample --- libcertifier.cfg.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index d0d92be..7589a3c 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -1,6 +1,6 @@ { "libcertifier.certifier.url": "https://certifier.xpki.io/v1/certifier", - "libcertifier.profile.name": "Xfinity_Default_Issuing_ECC_ICA", + "libcertifier.profile.name": "XFN_Matter_OP_Class_3_ICA", "libcertifier.validity.days": 365, "libcertifier.auth.type": "x509", "libcertifier.ecc.curve.id": "prime256v1", From c2ad302ed9b5ea411539304535b170cf4fe09997 Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Mon, 4 Aug 2025 10:42:04 -0400 Subject: [PATCH 03/30] Update cli_usage.adoc --- docs/cli_usage.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index a3ec859..be0ff16 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -113,7 +113,7 @@ Same command with SAT authentication: The certificate can be downloaded through the certificate ID returned as a result of running the command. ---- -./certifierUtil sectigo-get-cert -C -I -e -s -N -r -b -A -x -G -E -O -J +./certifierUtil sectigo-get-cert -C -I -e [employee/associate/contractor] -s -N -r -b -A -x -G -E -O -J -Z -U -T -K -u -l -W ---- From 4d199e8de2d7ca05f8df486e12fb81ae13278bfd Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Mon, 4 Aug 2025 11:01:21 -0400 Subject: [PATCH 04/30] Update cli_usage.adoc --- docs/cli_usage.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index be0ff16..e662f2b 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -113,7 +113,7 @@ Same command with SAT authentication: The certificate can be downloaded through the certificate ID returned as a result of running the command. ---- -./certifierUtil sectigo-get-cert -C -I -e [employee/associate/contractor] -s -N -r -b -A -x -G -E -O -J +./certifierUtil sectigo-get-cert -C -I -e [fte/associate/contractor] -s -N -r -b -A -x -G -E -O -J -Z -U -T -K -u -l -W ---- From 26ccee9bd4038249d25b845cd2ddd8047b46072f Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Mon, 4 Aug 2025 11:08:59 -0400 Subject: [PATCH 05/30] Update sectigo_client.c --- src/sectigo_client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sectigo_client.c b/src/sectigo_client.c index 2842fc8..4e2b79d 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -33,7 +33,6 @@ #include #include #include -pthread_mutex_t lock; Certifier * get_sectigo_certifier_instance() { From 79ba22a03da370191f91fbdda2412cfb6b8b13f5 Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:22:46 -0400 Subject: [PATCH 06/30] Update main.c --- src/main.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index 627efc3..b4b56cf 100644 --- a/src/main.c +++ b/src/main.c @@ -155,7 +155,9 @@ XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) "get-cert-status\n" "renew-cert\n" "print-cert\n" - "revoke\n"); + "revoke\n" + "sectigo-get-cert\n" + "sectigo-help\n"); } return XPKI_CLIENT_SUCCESS; @@ -235,6 +237,7 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_print_helper(SECTIGO_MODE mode){ { "cert-type", required_argument, NULL, 'T' }, \ { "config", required_argument, NULL, 'l' }, \ { "tracking-id", required_argument, NULL, 'W' }, \ + {"source", required_argument, NULL, 'Y'} \ { NULL, 0, NULL, 0 } \ //make default arg '*' for san and ip //only take in choices=['fte', 'contractor', 'associate'] @@ -550,7 +553,7 @@ XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, in } // --- Sectigo Option Table --- -static const char * const sectigo_get_cert_short_options = "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:h"; +static const char * const sectigo_get_cert_short_options = "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:Y:h"; static const struct option sectigo_get_cert_long_opts[] = { { "common-name", required_argument, NULL, 'C' }, { "id", required_argument, NULL, 'I' }, @@ -572,6 +575,7 @@ static const struct option sectigo_get_cert_long_opts[] = { { "cert-type", required_argument, NULL, 'T' }, { "config", required_argument, NULL, 'l' }, { "tracking-id", required_argument, NULL, 'W' }, + {"source", required_argument, NULL, 'Y'}, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } //make default arg '*' for san and ip @@ -624,68 +628,92 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t "--url [value] (-u)\n" "--config [value] (-l)\n" "--tracking-id [value] (-W)\n" + "--source [value] (-Y)\n" ); exit(0); break; case 'C': sectigo_parameter->sectigo_get_cert_param.sectigo_common_name = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_COMMON_NAME, optarg); break; case 'I': sectigo_parameter->sectigo_get_cert_param.sectigo_id = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_ID, optarg); break; case 'e': sectigo_parameter->sectigo_get_cert_param.sectigo_employee_type = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, optarg); break; case 's': sectigo_parameter->sectigo_get_cert_param.sectigo_server_platform = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, optarg); break; case 'N': sectigo_parameter->sectigo_get_cert_param.sectigo_sensitive = true; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SENSITIVE, optarg); break; case 'r': sectigo_parameter->sectigo_get_cert_param.sectigo_project_name = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_PROJECT_NAME, optarg); break; case 'b': sectigo_parameter->sectigo_get_cert_param.sectigo_business_justification = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, optarg); break; case 'A': sectigo_parameter->sectigo_get_cert_param.sectigo_subject_alt_names = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, optarg); break; case 'x': sectigo_parameter->sectigo_get_cert_param.sectigo_ip_addresses = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, optarg); break; case 'l': // config file path, handled in sectigo_perform break; case 'G': sectigo_parameter->sectigo_get_cert_param.sectigo_group_name = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_GROUP_NAME, optarg); break; case 'E': sectigo_parameter->sectigo_get_cert_param.sectigo_group_email = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, optarg); break; case 'O': sectigo_parameter->sectigo_get_cert_param.sectigo_owner_fname = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_FNAME, optarg); break; case 'J': sectigo_parameter->sectigo_get_cert_param.sectigo_owner_lname = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_LNAME, optarg); break; case 'Z': sectigo_parameter->sectigo_get_cert_param.sectigo_owner_email = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, optarg); break; case 'U': sectigo_parameter->sectigo_get_cert_param.sectigo_owner_phonenum = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM, optarg); break; case 'T': sectigo_parameter->sectigo_get_cert_param.sectigo_cert_type = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERT_TYPE, optarg); break; case 'K': sectigo_parameter->sectigo_get_cert_param.sectigo_auth_token = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, optarg); break; case 'u': sectigo_parameter->sectigo_get_cert_param.sectigo_url = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, optarg); break; case 'W': sectigo_parameter->sectigo_get_cert_param.sectigo_tracking_id = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_TRACKING_ID, optarg); + break; + case 'Y': + sectigo_parameter->sectigo_get_cert_param.sectigo_source = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SOURCE, optarg); break; case '?': log_info("Invalid or missing Sectigo option"); @@ -731,10 +759,7 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_perform(int argc, char ** argv){ log_debug("Config loaded, certifier pointer: %p", (void*)certifier); } - if (!certifier) { - log_error("Certifier instance is NULL!"); - return SECTIGO_CLIENT_ERROR_INTERNAL; -} + return xc_sectigo_get_cert(§igo_parameter.sectigo_get_cert_param); break; From 99fc4641f435a0b78f7718d4136e586f75ccb3f3 Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:23:13 -0400 Subject: [PATCH 07/30] Update certifier_api_easy.c --- src/certifier_api_easy.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index 29c5386..969e723 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -57,7 +57,7 @@ #define GET_CERT_SHORT_OPTIONS "fT:P:o:i:n:F:a:w:" #define VALIDITY_DAYS_SHORT_OPTION "t:" #define CA_PATH_SHORT_OPTION "c:" -#define SECTIGO_GET_CERT_SHORT_OPTIONS "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:" +#define SECTIGO_GET_CERT_SHORT_OPTIONS "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:S:h" #define BASE_LONG_OPTIONS \ { "help", no_argument, NULL, 'h' }, { "input-p12-path", required_argument, NULL, 'k' }, \ @@ -1247,7 +1247,10 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERT_TYPE, optarg); } break; - break; + case 'Y': //source + if(optarg){ + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SOURCE, optarg); + } case '?': /* Case when user enters the command as * $ ./libCertifier -p From a2a28036ba59109e934de97e8bb0709ce53585e9 Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:46:14 -0400 Subject: [PATCH 08/30] Update sectigo_client.h --- internal_headers/certifier/sectigo_client.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index acc8338..104e67b 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -57,6 +57,7 @@ const char * sectigo_owner_email; const char * sectigo_cert_type; const char * sectigo_url; const char * sectigo_tracking_id; +const char * sectigo_source; } get_cert_sectigo_param_t; @@ -91,4 +92,4 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(get_cert_sectigo_par } #endif -#endif \ No newline at end of file +#endif From 6f51fa8823a5c5633c2374fb7ef58375c46df6ac Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:47:29 -0400 Subject: [PATCH 09/30] Update xc_api_tests.c --- tests/xc_apis/xc_api_tests.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/xc_apis/xc_api_tests.c b/tests/xc_apis/xc_api_tests.c index 9e5fc67..e9726eb 100644 --- a/tests/xc_apis/xc_api_tests.c +++ b/tests/xc_apis/xc_api_tests.c @@ -261,6 +261,7 @@ static void test_get_sectigo_cert() params.sectigo_owner_phonenum = "2670000000"; params.sectigo_owner_email = "first_last@comcast.com"; params.sectigo_url = "https://certs-dev.xpki.io/api/createCertificate"; + params.sectigo_source = "libcertifier"; // Call the API error = xc_sectigo_get_cert(¶ms); From e921da677b8f193df4be5e30d65345665d20095d Mon Sep 17 00:00:00 2001 From: Preetam <149848764+PreetamChamkura@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:48:54 -0400 Subject: [PATCH 10/30] Update cli_usage.adoc --- docs/cli_usage.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index e662f2b..9d96e88 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -114,7 +114,7 @@ The certificate can be downloaded through the certificate ID returned as a resul ---- ./certifierUtil sectigo-get-cert -C -I -e [fte/associate/contractor] -s -N -r -b -A -x -G -E -O -J --Z -U -T -K -u -l -W +-Z -U -T -K -u -l -W -Y ---- == *certifierUtil commands* From d10b6cbc6b7dc2d133d20b57a41b79f108642c3a Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Thu, 5 Feb 2026 14:43:34 -0500 Subject: [PATCH 11/30] Edit property names to more closely align with PyCertifier --- docs/cli_usage.adoc | 10 ++-- docs/configuration.adoc | 14 ++++-- include/certifier/property.h | 8 +-- internal_headers/certifier/sectigo_client.h | 6 +-- libcertifier.cfg.sample | 8 +-- src/certifier_api_easy.c | 10 ++-- src/main.c | 14 +++--- src/property.c | 56 ++++++++++----------- src/sectigo_client.c | 39 +++++++------- tests/xc_apis/xc_api_tests.c | 6 +-- 10 files changed, 88 insertions(+), 83 deletions(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index 9d96e88..fa17d69 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -759,9 +759,9 @@ Note: 64-bit hex integer expected as input. | Mark request for a lite certificate. + Note: value type = `bool` -| libcertifier.sectigo.certifier.url +| libcertifier.sectigo.url | "https://certs.xpki.io/api/createCertificate" -| Sectigo API endpoint URL +| Sectigo URL | libcertifier.sectigo.auth.token | "" @@ -783,11 +783,11 @@ Note: value type = `bool` | "user123" | User or device ID -| libcertifier.sectigo.owner.fname +| libcertifier.sectigo.owner.first.name | "First" | Owner's first name -| libcertifier.sectigo.owner.lname +| libcertifier.sectigo.owner.last.name | "Last" | Owner's last name @@ -828,7 +828,7 @@ Note: value type = `array of strings` Pass empty array if you don't have. | Certificate type. + Note: Always pass comodo for internet-facing apps -| libcertifier.sectigo.owner.phonenum +| libcertifier.sectigo.owner.phone.number | "1234567890" | Owner's phone number diff --git a/docs/configuration.adoc b/docs/configuration.adoc index ce20489..f58fa6f 100644 --- a/docs/configuration.adoc +++ b/docs/configuration.adoc @@ -2,6 +2,7 @@ xref:libcertifier.adoc[*Back to Manual*] == Configuration +== xPKI Certificates |======= | *Property Name* | *Default Value* | *Description* | libcertifier.certifier.url | https://certifier.xpki.io/v1/certifier/certificate | @@ -25,14 +26,19 @@ xref:libcertifier.adoc[*Back to Manual*] | libcertifier.tls.insecure.host | 0 | | libcertifier.tls.insecure.peer | 0 | | libcertifier.ext.key.usage | clientAuth,serverAuth | (See notes below) -| libcertifier.sectigo.certifier.url | https://certs.xpki.io/api/createCertificate | +|======= + +== Sectigo Certificates +|======= +| *Property Name* | *Default Value* | *Description* +| libcertifier.sectigo.url | https://certs.xpki.io/api/createCertificate | | libcertifier.sectigo.auth.token | | | libcertifier.sectigo.common.name | example.com | | libcertifier.sectigo.group.name | ExampleGroup | | libcertifier.sectigo.group.email | group@example.com | | libcertifier.sectigo.id | user123 | -| libcertifier.sectigo.owner.fname | First | -| libcertifier.sectigo.owner.lname | Last | +| libcertifier.sectigo.owner.first.name | First | +| libcertifier.sectigo.owner.last.name | Last | | libcertifier.sectigo.employee.type | associate | | libcertifier.sectigo.server.platform | Other | | libcertifier.sectigo.sensitive | false | @@ -41,7 +47,7 @@ xref:libcertifier.adoc[*Back to Manual*] | libcertifier.sectigo.subject.alt.names | [] | | libcertifier.sectigo.ip.addresses | [] | | libcertifier.sectigo.cert.type | comodo | -| libcertifier.sectigo.owner.phonenum | 1234567890 | +| libcertifier.sectigo.owner.phone.number | 1234567890 | | libcertifier.sectigo.owner.email | owner@example.com | | libcertifier.sectigo.tracking.id | 1234 | | libcertifier.sectigo.source | libcertifier | diff --git a/include/certifier/property.h b/include/certifier/property.h index fa9412e..b830fd1 100644 --- a/include/certifier/property.h +++ b/include/certifier/property.h @@ -208,8 +208,8 @@ typedef enum CERTIFIER_OPT CERTIFIER_OPT_SECTIGO_GROUP_NAME, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, CERTIFIER_OPT_SECTIGO_ID, - CERTIFIER_OPT_SECTIGO_OWNER_FNAME, - CERTIFIER_OPT_SECTIGO_OWNER_LNAME, + CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, + CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, CERTIFIER_OPT_SECTIGO_SENSITIVE, @@ -218,11 +218,11 @@ typedef enum CERTIFIER_OPT CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, CERTIFIER_OPT_SECTIGO_CERT_TYPE, - CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM, + CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, CERTIFIER_OPT_SECTIGO_TRACKING_ID, CERTIFIER_OPT_SECTIGO_SOURCE, - CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, + CERTIFIER_OPT_SECTIGO_URL, } CERTIFIER_OPT; diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index 104e67b..299269f 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -43,8 +43,8 @@ const char * sectigo_common_name; const char * sectigo_group_name; const char * sectigo_group_email; const char * sectigo_id; -const char * sectigo_owner_fname; -const char * sectigo_owner_lname; +const char * sectigo_owner_first_name; +const char * sectigo_owner_last_name; const char * sectigo_employee_type; const char * sectigo_server_platform; bool sectigo_sensitive; @@ -52,7 +52,7 @@ const char * sectigo_project_name; const char * sectigo_business_justification; const char * sectigo_subject_alt_names; const char * sectigo_ip_addresses; -const char * sectigo_owner_phonenum; +const char * sectigo_owner_phone_number; const char * sectigo_owner_email; const char * sectigo_cert_type; const char * sectigo_url; diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index 7589a3c..c02d2e1 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -25,14 +25,14 @@ "libcertifier.node.id":"CCCCCCCCCCCCCCCC", "libcertifier.ext.key.usage":"critical,clientAuth,serverAuth", - "libcertifier.sectigo.certifier.url": "https://certs.xpki.io/api/createCertificate", + "libcertifier.sectigo.url": "https://certs.xpki.io/api/createCertificate", "libcertifier.sectigo.auth.token": "", "libcertifier.sectigo.common.name": "example.com", "libcertifier.sectigo.group.name": "Example Group", "libcertifier.sectigo.group.email": "group@example.com", "libcertifier.sectigo.id": "user123", - "libcertifier.sectigo.owner.fname": "First", - "libcertifier.sectigo.owner.lname": "Last", + "libcertifier.sectigo.owner.first.name": "First", + "libcertifier.sectigo.owner.last.name": "Last", "libcertifier.sectigo.employee.type": "associate", "libcertifier.sectigo.server.platform": "Other", "libcertifier.sectigo.sensitive": false, @@ -41,7 +41,7 @@ "libcertifier.sectigo.subject.alt.names": [], "libcertifier.sectigo.ip.addresses": [], "libcertifier.sectigo.cert.type": "comodo", - "libcertifier.sectigo.owner.phonenum": "1234567890", + "libcertifier.sectigo.owner.phone.number": "1234567890", "libcertifier.sectigo.owner.email": "owner@example.com", "libcertifier.sectigo.tracking.id": "1234", "libcertifier.sectigo.source": "libcertifier" diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index 969e723..b0ea50e 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -1210,7 +1210,7 @@ static int process_command_line(CERTIFIER * easy) break; case 'u': // sectigo url if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, optarg); + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_URL, optarg); } case 'G': // group-name if (optarg) { @@ -1224,12 +1224,12 @@ static int process_command_line(CERTIFIER * easy) break; case 'O': // owner-fname if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_FNAME, optarg); + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, optarg); } break; case 'J': // owner-lname if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_LNAME, optarg); + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, optarg); } break; case 'M': // owner-email @@ -1237,9 +1237,9 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, optarg); } break; - case 'Z': // owner-phonenum + case 'Z': // owner-phone-number if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM, optarg); + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, optarg); } break; case 'U': // cert-type diff --git a/src/main.c b/src/main.c index b4b56cf..9d707f5 100644 --- a/src/main.c +++ b/src/main.c @@ -680,20 +680,20 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, optarg); break; case 'O': - sectigo_parameter->sectigo_get_cert_param.sectigo_owner_fname = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_FNAME, optarg); + sectigo_parameter->sectigo_get_cert_param.sectigo_owner_first_name = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, optarg); break; case 'J': - sectigo_parameter->sectigo_get_cert_param.sectigo_owner_lname = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_LNAME, optarg); + sectigo_parameter->sectigo_get_cert_param.sectigo_owner_last_name = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, optarg); break; case 'Z': sectigo_parameter->sectigo_get_cert_param.sectigo_owner_email = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, optarg); break; case 'U': - sectigo_parameter->sectigo_get_cert_param.sectigo_owner_phonenum = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM, optarg); + sectigo_parameter->sectigo_get_cert_param.sectigo_owner_phone_number = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, optarg); break; case 'T': sectigo_parameter->sectigo_get_cert_param.sectigo_cert_type = optarg; @@ -705,7 +705,7 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t break; case 'u': sectigo_parameter->sectigo_get_cert_param.sectigo_url = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, optarg); + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_URL, optarg); break; case 'W': sectigo_parameter->sectigo_get_cert_param.sectigo_tracking_id = optarg; diff --git a/src/property.c b/src/property.c index 7dae88b..9736093 100644 --- a/src/property.c +++ b/src/property.c @@ -207,8 +207,8 @@ struct _PropMap char * sectigo_group_name; char * sectigo_group_email; char * sectigo_id; - char * sectigo_owner_fname; - char * sectigo_owner_lname; + char * sectigo_owner_first_name; + char * sectigo_owner_last_name; char * sectigo_employee_type; char * sectigo_server_platform; bool sectigo_sensitive; @@ -216,7 +216,7 @@ struct _PropMap char * sectigo_business_justification; char * sectigo_subject_alt_names; char * sectigo_ip_addresses; - char * sectigo_owner_phonenum; + char * sectigo_owner_phone_number; char * sectigo_owner_email; char * sectigo_cert_type; char * sectigo_tracking_id; @@ -385,11 +385,11 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_ID: prop_map->sectigo_id = XSTRDUP((const char *)value); break; - case CERTIFIER_OPT_SECTIGO_OWNER_FNAME: - prop_map->sectigo_owner_fname = XSTRDUP((const char *)value); + case CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME: + prop_map->sectigo_owner_first_name = XSTRDUP((const char *)value); break; - case CERTIFIER_OPT_SECTIGO_OWNER_LNAME: - prop_map->sectigo_owner_lname = XSTRDUP((const char *)value); + case CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME: + prop_map->sectigo_owner_last_name = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE: prop_map->sectigo_employee_type = XSTRDUP((const char *)value); @@ -415,8 +415,8 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_CERT_TYPE: prop_map->sectigo_cert_type = XSTRDUP((const char *)value); break; - case CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM: - prop_map->sectigo_owner_phonenum = XSTRDUP((const char *)value); + case CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER: + prop_map->sectigo_owner_phone_number = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_OWNER_EMAIL: prop_map->sectigo_owner_email = XSTRDUP((const char *)value); @@ -427,7 +427,7 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_SOURCE: prop_map->sectigo_source = XSTRDUP((const char *)value); break; - case CERTIFIER_OPT_SECTIGO_CERTIFIER_URL: + case CERTIFIER_OPT_SECTIGO_URL: prop_map->sectigo_url = XSTRDUP((const char *)value); break; default: @@ -912,11 +912,11 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) case CERTIFIER_OPT_SECTIGO_ID: retval = (void *) prop_map->sectigo_id; break; - case CERTIFIER_OPT_SECTIGO_OWNER_FNAME: - retval = (void *) prop_map->sectigo_owner_fname; + case CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME: + retval = (void *) prop_map->sectigo_owner_first_name; break; - case CERTIFIER_OPT_SECTIGO_OWNER_LNAME: - retval = (void *) prop_map->sectigo_owner_lname; + case CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME: + retval = (void *) prop_map->sectigo_owner_last_name; break; case CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE: retval = (void *) prop_map->sectigo_employee_type; @@ -939,8 +939,8 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) case CERTIFIER_OPT_SECTIGO_IP_ADDRESSES: retval = (void *) prop_map->sectigo_ip_addresses; break; - case CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM: - retval = (void *) prop_map->sectigo_owner_phonenum; + case CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER: + retval = (void *) prop_map->sectigo_owner_phone_number; break; case CERTIFIER_OPT_SECTIGO_OWNER_EMAIL: retval = (void *) prop_map->sectigo_owner_email; @@ -954,7 +954,7 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) case CERTIFIER_OPT_SECTIGO_SOURCE: retval = (void *) prop_map->sectigo_source; break; - case CERTIFIER_OPT_SECTIGO_CERTIFIER_URL: + case CERTIFIER_OPT_SECTIGO_URL: retval = (void *) prop_map->sectigo_url; break; @@ -1216,10 +1216,10 @@ if (strcmp(key, "libcertifier.sectigo.ip.addresses") == 0) { sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, value_str); else if (strcmp(key, "libcertifier.sectigo.id") == 0) sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_ID, value_str); - else if (strcmp(key, "libcertifier.sectigo.owner.fname") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_FNAME, value_str); - else if (strcmp(key, "libcertifier.sectigo.owner.lname") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_LNAME, value_str); + else if (strcmp(key, "libcertifier.sectigo.owner.first.name") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, value_str); + else if (strcmp(key, "libcertifier.sectigo.owner.last.name") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, value_str); else if (strcmp(key, "libcertifier.sectigo.employee.type") == 0) sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, value_str); else if (strcmp(key, "libcertifier.sectigo.server.platform") == 0) @@ -1228,14 +1228,14 @@ if (strcmp(key, "libcertifier.sectigo.ip.addresses") == 0) { sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, value_str); else if (strcmp(key, "libcertifier.sectigo.business.justification") == 0) sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, value_str); - else if (strcmp(key, "libcertifier.sectigo.owner.phonenum") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM, value_str); + else if (strcmp(key, "libcertifier.sectigo.owner.phone.number") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, value_str); else if (strcmp(key, "libcertifier.sectigo.owner.email") == 0) sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, value_str); else if (strcmp(key, "libcertifier.sectigo.cert.type") == 0) sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERT_TYPE, value_str); - else if (strcmp(key, "libcertifier.sectigo.certifier.url") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, value_str); + else if (strcmp(key, "libcertifier.sectigo.url") == 0) + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_URL, value_str); else if (strcmp(key, "libcertifier.sectigo.tracking.id") == 0) sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_TRACKING_ID, value_str); else if (strcmp(key, "libcertifier.sectigo.source") == 0) @@ -1646,15 +1646,15 @@ static void free_prop_map_values(CertifierPropMap * prop_map) FV(prop_map->sectigo_group_name); FV(prop_map->sectigo_group_email); FV(prop_map->sectigo_id); - FV(prop_map->sectigo_owner_fname); - FV(prop_map->sectigo_owner_lname); + FV(prop_map->sectigo_owner_first_name); + FV(prop_map->sectigo_owner_last_name); FV(prop_map->sectigo_employee_type); FV(prop_map->sectigo_server_platform); FV(prop_map->sectigo_project_name); FV(prop_map->sectigo_business_justification); FV(prop_map->sectigo_subject_alt_names); FV(prop_map->sectigo_ip_addresses); - FV(prop_map->sectigo_owner_phonenum); + FV(prop_map->sectigo_owner_phone_number); FV(prop_map->sectigo_owner_email); FV(prop_map->sectigo_cert_type); FV(prop_map->sectigo_tracking_id); diff --git a/src/sectigo_client.c b/src/sectigo_client.c index 4e2b79d..33c65b2 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -44,7 +44,7 @@ Certifier * get_sectigo_certifier_instance() certifier->sectigo_mode = true; certifier->prop_map = property_new_sectigo(); certifier_set_property(certifier, CERTIFIER_OPT_LOG_LEVEL, (void *) (size_t) 0); - certifier_set_property(certifier, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL, "https://certs-dev.xpki.io/api/createCertificate"); + certifier_set_property(certifier, CERTIFIER_OPT_SECTIGO_URL, "https://certs-dev.xpki.io/api/createCertificate"); } return certifier; } @@ -73,12 +73,11 @@ params->sectigo_group_email = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_ID); params->sectigo_id = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_FNAME); -params->sectigo_owner_fname = param ? XSTRDUP((const char *)param) : NULL; - -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_LNAME); -params->sectigo_owner_lname = param ? XSTRDUP((const char *)param) : NULL; +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME); +params->sectigo_owner_first_name = param ? XSTRDUP((const char *)param) : NULL; +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME); +params->sectigo_owner_last_name = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE); params->sectigo_employee_type = param ? XSTRDUP((const char *)param) : NULL; @@ -100,13 +99,13 @@ params->sectigo_ip_addresses = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERT_TYPE); params->sectigo_cert_type = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONENUM); -params->sectigo_owner_phonenum = param ? XSTRDUP((const char *)param) : NULL; +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER); +params->sectigo_owner_phone_number = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL); params->sectigo_owner_email = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL); +param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_URL); params->sectigo_url = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE); @@ -142,7 +141,7 @@ const char * node_address, const char * certifier_id, char ** out_cert) const char * tracking_id = property_get(props, CERTIFIER_OPT_SECTIGO_TRACKING_ID); const char * bearer_token = property_get(props, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); const char * source = property_get(props, CERTIFIER_OPT_SECTIGO_SOURCE); - const char * certifier_url = property_get(props, CERTIFIER_OPT_SECTIGO_CERTIFIER_URL); + const char * certifier_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); if (!tracking_id) { @@ -159,7 +158,7 @@ if (!bearer_token) { goto cleanup; } if (!certifier_url) { - log_error("Missing CERTIFIER_OPT_SECTIGO_CERTIFIER_URL"); + log_error("Missing CERTIFIER_OPT_SECTIGO_URL"); rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; rc.application_error_msg = util_format_error_here("Certifier URL is missing"); goto cleanup; @@ -236,14 +235,14 @@ const char *headers[] = { json_object_set_string(root_obj, "groupName", params.sectigo_group_name ? params.sectigo_group_name : ""); json_object_set_string(root_obj, "groupEmailAddress", params.sectigo_group_email ? params.sectigo_group_email : ""); json_object_set_string(root_obj, "id", params.sectigo_id ? params.sectigo_id : ""); -json_object_set_string(root_obj, "ownerFirstName", params.sectigo_owner_fname ? params.sectigo_owner_fname : ""); -json_object_set_string(root_obj, "ownerLastName", params.sectigo_owner_lname ? params.sectigo_owner_lname : ""); +json_object_set_string(root_obj, "ownerFirstName", params.sectigo_owner_first_name ? params.sectigo_owner_first_name : ""); +json_object_set_string(root_obj, "ownerLastName", params.sectigo_owner_last_name ? params.sectigo_owner_last_name : ""); json_object_set_string(root_obj, "employeeType", params.sectigo_employee_type ? params.sectigo_employee_type : ""); json_object_set_string(root_obj, "serverPlatform", params.sectigo_server_platform ? params.sectigo_server_platform : ""); json_object_set_string(root_obj, "projectName", params.sectigo_project_name ? params.sectigo_project_name : ""); json_object_set_string(root_obj, "businessJustification", params.sectigo_business_justification ? params.sectigo_business_justification : ""); json_object_set_string(root_obj, "certificateType", params.sectigo_cert_type ? params.sectigo_cert_type : ""); -json_object_set_string(root_obj, "ownerPhoneNumber", params.sectigo_owner_phonenum ? params.sectigo_owner_phonenum : ""); +json_object_set_string(root_obj, "ownerPhoneNumber", params.sectigo_owner_phone_number ? params.sectigo_owner_phone_number : ""); json_object_set_string(root_obj, "ownerEmailAddress", params.sectigo_owner_email ? params.sectigo_owner_email : ""); json_object_set_string(root_obj, "certifierUrl", params.sectigo_url ? params.sectigo_url : ""); json_object_set_value(root_obj, "sensitive", json_value_init_boolean(params.sectigo_sensitive)); @@ -358,10 +357,10 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params) json_object_set_string(root_obj, "groupEmailAddress", params->sectigo_group_email); if (params->sectigo_id) json_object_set_string(root_obj, "id", params->sectigo_id); -if (params->sectigo_owner_fname) - json_object_set_string(root_obj, "ownerFirstName", params->sectigo_owner_fname); -if (params->sectigo_owner_lname) - json_object_set_string(root_obj, "ownerLastName", params->sectigo_owner_lname); +if (params->sectigo_owner_first_name) + json_object_set_string(root_obj, "ownerFirstName", params->sectigo_owner_first_name); +if (params->sectigo_owner_last_name) + json_object_set_string(root_obj, "ownerLastName", params->sectigo_owner_last_name); if (params->sectigo_employee_type) json_object_set_string(root_obj, "employeeType", params->sectigo_employee_type); if (params->sectigo_server_platform) @@ -399,8 +398,8 @@ if (params->sectigo_ip_addresses && strlen(params->sectigo_ip_addresses) > 0) { json_object_set_value(root_obj, "ipAddresses", ip_array); if (params->sectigo_cert_type) json_object_set_string(root_obj, "certificateType", params->sectigo_cert_type); -if (params->sectigo_owner_phonenum) - json_object_set_string(root_obj, "ownerPhoneNumber", params->sectigo_owner_phonenum); +if (params->sectigo_owner_phone_number) + json_object_set_string(root_obj, "ownerPhoneNumber", params->sectigo_owner_phone_number); if (params->sectigo_owner_email) json_object_set_string(root_obj, "ownerEmailAddress", params->sectigo_owner_email); if (params->sectigo_url) diff --git a/tests/xc_apis/xc_api_tests.c b/tests/xc_apis/xc_api_tests.c index e9726eb..ddcadab 100644 --- a/tests/xc_apis/xc_api_tests.c +++ b/tests/xc_apis/xc_api_tests.c @@ -248,8 +248,8 @@ static void test_get_sectigo_cert() params.sectigo_group_name = "GroupName"; params.sectigo_group_email = "example@comcast.com"; params.sectigo_id = "exid"; - params.sectigo_owner_fname = "First"; - params.sectigo_owner_lname = "Last"; + params.sectigo_owner_first_name = "First"; + params.sectigo_owner_last_name = "Last"; params.sectigo_employee_type = "associate"; params.sectigo_server_platform = "other"; params.sectigo_sensitive = "false"; @@ -258,7 +258,7 @@ static void test_get_sectigo_cert() params.sectigo_subject_alt_names = "*"; params.sectigo_ip_addresses = "*"; params.sectigo_cert_type = "comodo"; - params.sectigo_owner_phonenum = "2670000000"; + params.sectigo_owner_phone_number = "2670000000"; params.sectigo_owner_email = "first_last@comcast.com"; params.sectigo_url = "https://certs-dev.xpki.io/api/createCertificate"; params.sectigo_source = "libcertifier"; From a6fffea3d3bfd56fc688b5ee874ef109bb836123 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Thu, 5 Feb 2026 14:44:48 -0500 Subject: [PATCH 12/30] Improve debug log formatting --- src/http.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/http.c b/src/http.c index 3db22fb..f05f590 100644 --- a/src/http.c +++ b/src/http.c @@ -34,10 +34,10 @@ static void set_curl_options(CURL * curl, CertifierPropMap * prop_map) char * mtls_p12 = property_get(prop_map, CERTIFIER_OPT_MTLS_P12_PATH); char * mtls_password = property_get(prop_map, CERTIFIER_OPT_MTLS_P12_PASSWORD); - log_debug("[set_curl_options] - Host Validation=%i", host_validation); - log_debug("[set_curl_options] - Peer Validation=%i", peer_validation); - log_debug("[set_curl_options] - Debug HTTP Enabled=%i", is_debug_http_enabled); - log_debug("[set_curl_options] - Trace HTTP Enabled=%i", is_trace_http_enabled); + log_debug("[set_curl_options] - Host Validation=%i\n", host_validation); + log_debug("[set_curl_options] - Peer Validation=%i\n", peer_validation); + log_debug("[set_curl_options] - Debug HTTP Enabled=%i\n", is_debug_http_enabled); + log_debug("[set_curl_options] - Trace HTTP Enabled=%i\n", is_trace_http_enabled); // First set the URL that is about to receive our POST. http_set_curlopt(curl, CURLOPT_ACCEPT_ENCODING, ""); From 1eb835f689b32cc8dd069fcf1f8614879e0f60cb Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Thu, 5 Feb 2026 15:33:17 -0500 Subject: [PATCH 13/30] Enforce automatic generation of random tracking ID and remove sectigo tracking ID flag --- docs/cli_usage.adoc | 6 ------ docs/configuration.adoc | 1 - include/certifier/property.h | 1 - internal_headers/certifier/sectigo_client.h | 1 - libcertifier.cfg.sample | 1 - src/main.c | 4 ---- src/property.c | 20 ++++++++++---------- src/sectigo_client.c | 10 +--------- 8 files changed, 11 insertions(+), 33 deletions(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index fa17d69..05f0a4e 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -637,12 +637,6 @@ Disabled by default - Only error messages are shown. -l | Path to config file -| tracking-id -| W -| --tracking-id + --W -| Tracking ID - |=== *Configuration File* diff --git a/docs/configuration.adoc b/docs/configuration.adoc index f58fa6f..2d5fd66 100644 --- a/docs/configuration.adoc +++ b/docs/configuration.adoc @@ -49,7 +49,6 @@ xref:libcertifier.adoc[*Back to Manual*] | libcertifier.sectigo.cert.type | comodo | | libcertifier.sectigo.owner.phone.number | 1234567890 | | libcertifier.sectigo.owner.email | owner@example.com | -| libcertifier.sectigo.tracking.id | 1234 | | libcertifier.sectigo.source | libcertifier | |======= diff --git a/include/certifier/property.h b/include/certifier/property.h index b830fd1..97c59ff 100644 --- a/include/certifier/property.h +++ b/include/certifier/property.h @@ -220,7 +220,6 @@ typedef enum CERTIFIER_OPT CERTIFIER_OPT_SECTIGO_CERT_TYPE, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, - CERTIFIER_OPT_SECTIGO_TRACKING_ID, CERTIFIER_OPT_SECTIGO_SOURCE, CERTIFIER_OPT_SECTIGO_URL, diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index 299269f..3a7f4fd 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -56,7 +56,6 @@ const char * sectigo_owner_phone_number; const char * sectigo_owner_email; const char * sectigo_cert_type; const char * sectigo_url; -const char * sectigo_tracking_id; const char * sectigo_source; diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index c02d2e1..0f8eae5 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -43,7 +43,6 @@ "libcertifier.sectigo.cert.type": "comodo", "libcertifier.sectigo.owner.phone.number": "1234567890", "libcertifier.sectigo.owner.email": "owner@example.com", - "libcertifier.sectigo.tracking.id": "1234", "libcertifier.sectigo.source": "libcertifier" } diff --git a/src/main.c b/src/main.c index 9d707f5..61ebd30 100644 --- a/src/main.c +++ b/src/main.c @@ -707,10 +707,6 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t sectigo_parameter->sectigo_get_cert_param.sectigo_url = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_URL, optarg); break; - case 'W': - sectigo_parameter->sectigo_get_cert_param.sectigo_tracking_id = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_TRACKING_ID, optarg); - break; case 'Y': sectigo_parameter->sectigo_get_cert_param.sectigo_source = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SOURCE, optarg); diff --git a/src/property.c b/src/property.c index 9736093..9ea0a6c 100644 --- a/src/property.c +++ b/src/property.c @@ -219,7 +219,6 @@ struct _PropMap char * sectigo_owner_phone_number; char * sectigo_owner_email; char * sectigo_cert_type; - char * sectigo_tracking_id; char * sectigo_source; char * sectigo_url; }; @@ -421,9 +420,6 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_OWNER_EMAIL: prop_map->sectigo_owner_email = XSTRDUP((const char *)value); break; - case CERTIFIER_OPT_SECTIGO_TRACKING_ID: - prop_map->sectigo_tracking_id = XSTRDUP((const char *)value); - break; case CERTIFIER_OPT_SECTIGO_SOURCE: prop_map->sectigo_source = XSTRDUP((const char *)value); break; @@ -948,9 +944,6 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) case CERTIFIER_OPT_SECTIGO_CERT_TYPE: retval = (void *) prop_map->sectigo_cert_type; break; - case CERTIFIER_OPT_SECTIGO_TRACKING_ID: - retval = (void *) prop_map->sectigo_tracking_id; - break; case CERTIFIER_OPT_SECTIGO_SOURCE: retval = (void *) prop_map->sectigo_source; break; @@ -1236,8 +1229,6 @@ if (strcmp(key, "libcertifier.sectigo.ip.addresses") == 0) { sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERT_TYPE, value_str); else if (strcmp(key, "libcertifier.sectigo.url") == 0) sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_URL, value_str); - else if (strcmp(key, "libcertifier.sectigo.tracking.id") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_TRACKING_ID, value_str); else if (strcmp(key, "libcertifier.sectigo.source") == 0) sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SOURCE, value_str); // Add more mappings as needed @@ -1657,7 +1648,6 @@ static void free_prop_map_values(CertifierPropMap * prop_map) FV(prop_map->sectigo_owner_phone_number); FV(prop_map->sectigo_owner_email); FV(prop_map->sectigo_cert_type); - FV(prop_map->sectigo_tracking_id); FV(prop_map->sectigo_source); FV(prop_map->sectigo_url); } @@ -1670,6 +1660,16 @@ CertifierPropMap * property_new_sectigo(void) log_error("Could not initialize CertifierPropMap."); return NULL; } + + char * trace_id = NULL; + + // generate tracking ID + trace_id = util_generate_random_value(16, ALLOWABLE_CHARACTERS); + if (trace_id) + { + property_set(prop_map, CERTIFIER_OPT_TRACKING_ID, trace_id); + XFREE(trace_id); + } return prop_map; } diff --git a/src/sectigo_client.c b/src/sectigo_client.c index 33c65b2..3dc1028 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -138,18 +138,10 @@ const char * node_address, const char * certifier_id, char ** out_cert) JSON_Value * parsed_json_root_value = NULL; char * serialized_string = NULL; http_response * resp = NULL; - const char * tracking_id = property_get(props, CERTIFIER_OPT_SECTIGO_TRACKING_ID); + const char * tracking_id = property_get(props, CERTIFIER_OPT_TRACKING_ID); const char * bearer_token = property_get(props, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); const char * source = property_get(props, CERTIFIER_OPT_SECTIGO_SOURCE); const char * certifier_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); - - - if (!tracking_id) { - log_error("Missing CERTIFIER_OPT_SECTIGO_TRACKING_ID"); - rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; - rc.application_error_msg = util_format_error_here("Tracking ID is missing"); - goto cleanup; -} if (!bearer_token) { log_error("Missing CERTIFIER_OPT_SECTIGO_AUTH_TOKEN"); From 86f4fb32d4f992c7308b55bbc2f8a9b255778453 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Sun, 8 Feb 2026 21:02:36 -0500 Subject: [PATCH 14/30] Fixing test warnings/errors and formatting --- src/certifier.c | 7 +- src/certifierclient.c | 1 - src/main.c | 4 +- src/sectigo_client.c | 359 ++++++++++++++++++++---------------------- src/xpki_client.c | 2 + tests/tests.c | 68 ++++---- 6 files changed, 213 insertions(+), 228 deletions(-) diff --git a/src/certifier.c b/src/certifier.c index 8dffc9e..09898ef 100644 --- a/src/certifier.c +++ b/src/certifier.c @@ -388,8 +388,6 @@ static int save_x509certs_to_filesystem(Certifier * certifier, char * x509_certs CertifierError certifier_err_info = CERTIFIER_ERROR_INITIALIZER; X509_LIST * certs = NULL; const char * password = NULL; - unsigned char *x509_der; - size_t x509_len; log_info("\nTrimming x509 certificates...\n"); util_trim(x509_certs); @@ -875,14 +873,14 @@ CertifierPropMap * _certifier_get_properties(Certifier * certifier) void _certifier_set_x509_cert(Certifier * certifier, const X509_CERT * cert) { security_free_cert(certifier->tmp_map.x509_cert); - X509_CERT * tmp = NULL; + const X509_CERT * tmp = NULL; if (cert != NULL) { tmp = cert; } - certifier->tmp_map.x509_cert = tmp; + certifier->tmp_map.x509_cert = (X509_CERT *)tmp; } void _certifier_set_ecc_key(Certifier * certifier, const ECC_KEY * key) @@ -1008,7 +1006,6 @@ int certifier_set_property(Certifier * certifier, int name, const void * value) NULL_CHECK(certifier); int return_code = 0; - const void * origValue = property_get(certifier->prop_map, name); if (certifier->sectigo_mode) { // Only set Sectigo properties for Sectigo flows diff --git a/src/certifierclient.c b/src/certifierclient.c index 7134ad6..6a4124e 100644 --- a/src/certifierclient.c +++ b/src/certifierclient.c @@ -634,4 +634,3 @@ CertifierError certifierclient_check_certificate_status(CertifierPropMap * props return rc; } - diff --git a/src/main.c b/src/main.c index 61ebd30..f52bf8b 100644 --- a/src/main.c +++ b/src/main.c @@ -92,7 +92,7 @@ XPKI_MODE xpki_get_mode(int argc, char ** argv) { "help", XPKI_MODE_PRINT_HELP }, { "version", XPKI_MODE_PRINT_VERSION }, { "get-cert", XPKI_MODE_GET_CERT }, { "get-cert-status", XPKI_MODE_GET_CERT_STATUS }, { "renew-cert", XPKI_MODE_RENEW_CERT }, { "print-cert", XPKI_MODE_PRINT_CERT }, - { "revoke", XPKI_CLIENT_CERT_REVOKED }, + { "revoke", XPKI_MODE_REVOKE_CERT }, }; for (int i = 0; i < sizeof(command_map) / sizeof(command_map_t); ++i) @@ -789,7 +789,7 @@ XPKI_CLIENT_ERROR_CODE xpki_perform(int argc, char ** argv) case XPKI_MODE_GET_CERT_STATUS: { XPKI_CLIENT_CERT_STATUS status; ReturnErrorOnFailure(xc_get_cert_status(&xc_parameter.get_cert_status_param, &status)); - return status; + return (XPKI_CLIENT_ERROR_CODE)status; } break; case XPKI_MODE_RENEW_CERT: diff --git a/src/sectigo_client.c b/src/sectigo_client.c index 3dc1028..f2055dd 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -59,71 +59,71 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(get_cert_sectigo_par void * param = NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); -params->sectigo_auth_token = param ? XSTRDUP((const char *)param) : NULL; + params->sectigo_auth_token = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); -params->sectigo_common_name = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); + params->sectigo_common_name = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_GROUP_NAME); -params->sectigo_group_name = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_GROUP_NAME); + params->sectigo_group_name = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL); -params->sectigo_group_email = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL); + params->sectigo_group_email = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_ID); -params->sectigo_id = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_ID); + params->sectigo_id = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME); -params->sectigo_owner_first_name = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME); + params->sectigo_owner_first_name = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME); -params->sectigo_owner_last_name = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE); -params->sectigo_employee_type = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME); + params->sectigo_owner_last_name = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE); + params->sectigo_employee_type = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM); -params->sectigo_server_platform = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM); + params->sectigo_server_platform = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME); -params->sectigo_project_name = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME); + params->sectigo_project_name = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION); -params->sectigo_business_justification = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION); + params->sectigo_business_justification = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES); -params->sectigo_subject_alt_names = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES); + params->sectigo_subject_alt_names = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES); -params->sectigo_ip_addresses = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES); + params->sectigo_ip_addresses = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERT_TYPE); -params->sectigo_cert_type = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERT_TYPE); + params->sectigo_cert_type = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER); -params->sectigo_owner_phone_number = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER); + params->sectigo_owner_phone_number = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL); -params->sectigo_owner_email = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL); + params->sectigo_owner_email = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_URL); -params->sectigo_url = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_URL); + params->sectigo_url = param ? XSTRDUP((const char *)param) : NULL; -param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE); -params->sectigo_sensitive = param ? *((bool *)param) : false; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE); + params->sectigo_sensitive = param ? *((bool *)param) : false; return SECTIGO_CLIENT_SUCCESS; } - CertifierError sectigo_client_request_certificate(CertifierPropMap * props, const unsigned char * csr, const char * node_address, const char * certifier_id, char ** out_cert) - { Certifier *certifier = get_sectigo_certifier_instance(); CertifierError rc = CERTIFIER_ERROR_INITIALIZER; JSON_Value *root_value = NULL; JSON_Object *root_obj = NULL; char *json_body = NULL; + if (out_cert == NULL) { rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; @@ -143,48 +143,45 @@ const char * node_address, const char * certifier_id, char ** out_cert) const char * source = property_get(props, CERTIFIER_OPT_SECTIGO_SOURCE); const char * certifier_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); -if (!bearer_token) { - log_error("Missing CERTIFIER_OPT_SECTIGO_AUTH_TOKEN"); - rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; - rc.application_error_msg = util_format_error_here("Bearer token is missing"); - goto cleanup; -} -if (!certifier_url) { - log_error("Missing CERTIFIER_OPT_SECTIGO_URL"); - rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; - rc.application_error_msg = util_format_error_here("Certifier URL is missing"); - goto cleanup; -} -if (!source) { - log_error("Missing CERTIFIER_OPT_SECTIGO_SOURCE"); - rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; - rc.application_error_msg = util_format_error_here("Source is missing"); - goto cleanup; -} + if (!bearer_token) { + log_error("Missing CERTIFIER_OPT_SECTIGO_AUTH_TOKEN"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Bearer token is missing"); + goto cleanup; + } + if (!certifier_url) { + log_error("Missing CERTIFIER_OPT_SECTIGO_URL"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Certifier URL is missing"); + goto cleanup; + } + if (!source) { + log_error("Missing CERTIFIER_OPT_SECTIGO_SOURCE"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Source is missing"); + goto cleanup; + } log_debug("Tracking ID is: %s\n", tracking_id); log_debug("Source ID is: %s\n", source); - - - -if (bearer_token != NULL) { - snprintf(auth_header, sizeof(auth_header), "Authorization: %s", bearer_token); -} -snprintf(tracking_header, sizeof(tracking_header), "x-xpki-request-id: %s", tracking_id); -snprintf(source_header, sizeof(source_header), "x-xpki-source: %s", source); - -const char *headers[] = { - "Accept: */*", - "Connection: keep-alive", - "cache-control: no-cache", - "Content-Type: application/json", - source_header, - tracking_header, - "x-xpki-partner-id: comcast", - auth_header, - NULL -}; + if (bearer_token != NULL) { + snprintf(auth_header, sizeof(auth_header), "Authorization: %s", bearer_token); + } + snprintf(tracking_header, sizeof(tracking_header), "x-xpki-request-id: %s", tracking_id); + snprintf(source_header, sizeof(source_header), "x-xpki-source: %s", source); + + const char *headers[] = { + "Accept: */*", + "Connection: keep-alive", + "cache-control: no-cache", + "Content-Type: application/json", + source_header, + tracking_header, + "x-xpki-partner-id: comcast", + auth_header, + NULL + }; if (util_is_empty(source)) { @@ -193,14 +190,14 @@ const char *headers[] = { goto cleanup; } - - CertifierError csr_rc = sectigo_generate_certificate_signing_request(certifier, &serialized_string); + if (csr_rc.application_error_code != 0 || serialized_string == NULL) { - rc.application_error_code = csr_rc.application_error_code; - rc.application_error_msg = csr_rc.application_error_msg; - goto cleanup; -} + rc.application_error_code = csr_rc.application_error_code; + rc.application_error_msg = csr_rc.application_error_msg; + goto cleanup; + } + // Take Mutex if (pthread_mutex_lock(&lock) != 0) { @@ -217,6 +214,7 @@ const char *headers[] = { } get_cert_sectigo_param_t params; xc_sectigo_get_default_cert_param(¶ms); + // Build JSON body root_value = json_value_init_object(); root_obj = json_value_get_object(root_value); @@ -224,59 +222,58 @@ const char *headers[] = { json_object_set_string(root_obj, "certificateSigningRequest", serialized_string); json_object_set_string(root_obj, "commonName", params.sectigo_common_name ? params.sectigo_common_name : ""); -json_object_set_string(root_obj, "groupName", params.sectigo_group_name ? params.sectigo_group_name : ""); -json_object_set_string(root_obj, "groupEmailAddress", params.sectigo_group_email ? params.sectigo_group_email : ""); -json_object_set_string(root_obj, "id", params.sectigo_id ? params.sectigo_id : ""); -json_object_set_string(root_obj, "ownerFirstName", params.sectigo_owner_first_name ? params.sectigo_owner_first_name : ""); -json_object_set_string(root_obj, "ownerLastName", params.sectigo_owner_last_name ? params.sectigo_owner_last_name : ""); -json_object_set_string(root_obj, "employeeType", params.sectigo_employee_type ? params.sectigo_employee_type : ""); -json_object_set_string(root_obj, "serverPlatform", params.sectigo_server_platform ? params.sectigo_server_platform : ""); -json_object_set_string(root_obj, "projectName", params.sectigo_project_name ? params.sectigo_project_name : ""); -json_object_set_string(root_obj, "businessJustification", params.sectigo_business_justification ? params.sectigo_business_justification : ""); -json_object_set_string(root_obj, "certificateType", params.sectigo_cert_type ? params.sectigo_cert_type : ""); -json_object_set_string(root_obj, "ownerPhoneNumber", params.sectigo_owner_phone_number ? params.sectigo_owner_phone_number : ""); -json_object_set_string(root_obj, "ownerEmailAddress", params.sectigo_owner_email ? params.sectigo_owner_email : ""); -json_object_set_string(root_obj, "certifierUrl", params.sectigo_url ? params.sectigo_url : ""); -json_object_set_value(root_obj, "sensitive", json_value_init_boolean(params.sectigo_sensitive)); + json_object_set_string(root_obj, "groupName", params.sectigo_group_name ? params.sectigo_group_name : ""); + json_object_set_string(root_obj, "groupEmailAddress", params.sectigo_group_email ? params.sectigo_group_email : ""); + json_object_set_string(root_obj, "id", params.sectigo_id ? params.sectigo_id : ""); + json_object_set_string(root_obj, "ownerFirstName", params.sectigo_owner_first_name ? params.sectigo_owner_first_name : ""); + json_object_set_string(root_obj, "ownerLastName", params.sectigo_owner_last_name ? params.sectigo_owner_last_name : ""); + json_object_set_string(root_obj, "employeeType", params.sectigo_employee_type ? params.sectigo_employee_type : ""); + json_object_set_string(root_obj, "serverPlatform", params.sectigo_server_platform ? params.sectigo_server_platform : ""); + json_object_set_string(root_obj, "projectName", params.sectigo_project_name ? params.sectigo_project_name : ""); + json_object_set_string(root_obj, "businessJustification", params.sectigo_business_justification ? params.sectigo_business_justification : ""); + json_object_set_string(root_obj, "certificateType", params.sectigo_cert_type ? params.sectigo_cert_type : ""); + json_object_set_string(root_obj, "ownerPhoneNumber", params.sectigo_owner_phone_number ? params.sectigo_owner_phone_number : ""); + json_object_set_string(root_obj, "ownerEmailAddress", params.sectigo_owner_email ? params.sectigo_owner_email : ""); + json_object_set_string(root_obj, "certifierUrl", params.sectigo_url ? params.sectigo_url : ""); + json_object_set_value(root_obj, "sensitive", json_value_init_boolean(params.sectigo_sensitive)); // Always set subjectAltNames and ipAddresses, even if empty -// subjectAltNames as array -JSON_Value *san_array = json_value_init_array(); -JSON_Array *san_json_array = json_value_get_array(san_array); -if (params.sectigo_subject_alt_names && strlen(params.sectigo_subject_alt_names) > 0) { - char *san_copy = XSTRDUP(params.sectigo_subject_alt_names); - char *token = strtok(san_copy, ","); - while (token) { - json_array_append_value(san_json_array, json_value_init_string(token)); - token = strtok(NULL, ","); + // subjectAltNames as array + JSON_Value *san_array = json_value_init_array(); + JSON_Array *san_json_array = json_value_get_array(san_array); + if (params.sectigo_subject_alt_names && strlen(params.sectigo_subject_alt_names) > 0) { + char *san_copy = XSTRDUP(params.sectigo_subject_alt_names); + char *token = strtok(san_copy, ","); + while (token) { + json_array_append_value(san_json_array, json_value_init_string(token)); + token = strtok(NULL, ","); + } + XFREE(san_copy); } - XFREE(san_copy); -} -json_object_set_value(root_obj, "subjectAltNames", san_array); - -// ipAddresses as array -JSON_Value *ip_array = json_value_init_array(); -JSON_Array *ip_json_array = json_value_get_array(ip_array); -if (params.sectigo_ip_addresses && strlen(params.sectigo_ip_addresses) > 0) { - char *ip_copy = XSTRDUP(params.sectigo_ip_addresses); - char *token = strtok(ip_copy, ","); - while (token) { - json_array_append_value(ip_json_array, json_value_init_string(token)); - token = strtok(NULL, ","); + json_object_set_value(root_obj, "subjectAltNames", san_array); + + // ipAddresses as array + JSON_Value *ip_array = json_value_init_array(); + JSON_Array *ip_json_array = json_value_get_array(ip_array); + if (params.sectigo_ip_addresses && strlen(params.sectigo_ip_addresses) > 0) { + char *ip_copy = XSTRDUP(params.sectigo_ip_addresses); + char *token = strtok(ip_copy, ","); + while (token) { + json_array_append_value(ip_json_array, json_value_init_string(token)); + token = strtok(NULL, ","); + } + XFREE(ip_copy); } - XFREE(ip_copy); -} -json_object_set_value(root_obj, "ipAddresses", ip_array); + + json_object_set_value(root_obj, "ipAddresses", ip_array); json_body = json_serialize_to_string(root_value); - resp = http_post(props, certifier_url, headers, json_body); if (resp == NULL) { goto cleanup; } - rc.application_error_code = resp->error; // Check for errors @@ -293,7 +290,6 @@ json_object_set_value(root_obj, "ipAddresses", ip_array); goto cleanup; } - parsed_json_root_value = json_parse_string_with_comments(resp->payload); if (json_value_get_type(parsed_json_root_value) != JSONObject) { @@ -313,22 +309,16 @@ json_object_set_value(root_obj, "ipAddresses", ip_array); goto cleanup; } - - cleanup: - http_free_response(resp); - if (parsed_json_root_value) - { - json_value_free(parsed_json_root_value); - } + if (parsed_json_root_value) json_value_free(parsed_json_root_value); XFREE(serialized_string); - if (json_body) - json_free_serialized_string(json_body); - if (root_value) - json_value_free(root_value); + + if (json_body) json_free_serialized_string(json_body); + if (root_value) json_value_free(root_value); + return rc; } @@ -346,56 +336,59 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params) if (params->sectigo_group_name) json_object_set_string(root_obj, "groupName", params->sectigo_group_name); if (params->sectigo_group_email) - json_object_set_string(root_obj, "groupEmailAddress", params->sectigo_group_email); -if (params->sectigo_id) - json_object_set_string(root_obj, "id", params->sectigo_id); -if (params->sectigo_owner_first_name) - json_object_set_string(root_obj, "ownerFirstName", params->sectigo_owner_first_name); -if (params->sectigo_owner_last_name) - json_object_set_string(root_obj, "ownerLastName", params->sectigo_owner_last_name); -if (params->sectigo_employee_type) - json_object_set_string(root_obj, "employeeType", params->sectigo_employee_type); -if (params->sectigo_server_platform) - json_object_set_string(root_obj, "serverPlatform", params->sectigo_server_platform); -if (params->sectigo_project_name) - json_object_set_string(root_obj, "projectName", params->sectigo_project_name); -if (params->sectigo_business_justification) - json_object_set_string(root_obj, "businessJustification", params->sectigo_business_justification); -// subjectAltNames as array -JSON_Value *san_array = json_value_init_array(); -JSON_Array *san_json_array = json_value_get_array(san_array); -if (params->sectigo_subject_alt_names && strlen(params->sectigo_subject_alt_names) > 0) { - char *san_copy = XSTRDUP(params->sectigo_subject_alt_names); - char *token = strtok(san_copy, ","); - while (token) { - json_array_append_value(san_json_array, json_value_init_string(token)); - token = strtok(NULL, ","); + json_object_set_string(root_obj, "groupEmailAddress", params->sectigo_group_email); + if (params->sectigo_id) + json_object_set_string(root_obj, "id", params->sectigo_id); + if (params->sectigo_owner_first_name) + json_object_set_string(root_obj, "ownerFirstName", params->sectigo_owner_first_name); + if (params->sectigo_owner_last_name) + json_object_set_string(root_obj, "ownerLastName", params->sectigo_owner_last_name); + if (params->sectigo_employee_type) + json_object_set_string(root_obj, "employeeType", params->sectigo_employee_type); + if (params->sectigo_server_platform) + json_object_set_string(root_obj, "serverPlatform", params->sectigo_server_platform); + if (params->sectigo_project_name) + json_object_set_string(root_obj, "projectName", params->sectigo_project_name); + if (params->sectigo_business_justification) + json_object_set_string(root_obj, "businessJustification", params->sectigo_business_justification); + + // subjectAltNames as array + JSON_Value *san_array = json_value_init_array(); + JSON_Array *san_json_array = json_value_get_array(san_array); + if (params->sectigo_subject_alt_names && strlen(params->sectigo_subject_alt_names) > 0) { + char *san_copy = XSTRDUP(params->sectigo_subject_alt_names); + char *token = strtok(san_copy, ","); + while (token) { + json_array_append_value(san_json_array, json_value_init_string(token)); + token = strtok(NULL, ","); + } + XFREE(san_copy); } - XFREE(san_copy); -} -json_object_set_value(root_obj, "subjectAltNames", san_array); - -// ipAddresses as array -JSON_Value *ip_array = json_value_init_array(); -JSON_Array *ip_json_array = json_value_get_array(ip_array); -if (params->sectigo_ip_addresses && strlen(params->sectigo_ip_addresses) > 0) { - char *ip_copy = XSTRDUP(params->sectigo_ip_addresses); - char *token = strtok(ip_copy, ","); - while (token) { - json_array_append_value(ip_json_array, json_value_init_string(token)); - token = strtok(NULL, ","); + json_object_set_value(root_obj, "subjectAltNames", san_array); + + // ipAddresses as array + JSON_Value *ip_array = json_value_init_array(); + JSON_Array *ip_json_array = json_value_get_array(ip_array); + if (params->sectigo_ip_addresses && strlen(params->sectigo_ip_addresses) > 0) { + char *ip_copy = XSTRDUP(params->sectigo_ip_addresses); + char *token = strtok(ip_copy, ","); + while (token) { + json_array_append_value(ip_json_array, json_value_init_string(token)); + token = strtok(NULL, ","); + } + XFREE(ip_copy); } - XFREE(ip_copy); -} -json_object_set_value(root_obj, "ipAddresses", ip_array); -if (params->sectigo_cert_type) - json_object_set_string(root_obj, "certificateType", params->sectigo_cert_type); -if (params->sectigo_owner_phone_number) - json_object_set_string(root_obj, "ownerPhoneNumber", params->sectigo_owner_phone_number); -if (params->sectigo_owner_email) - json_object_set_string(root_obj, "ownerEmailAddress", params->sectigo_owner_email); -if (params->sectigo_url) - json_object_set_string(root_obj, "certifierUrl", params->sectigo_url); + json_object_set_value(root_obj, "ipAddresses", ip_array); + + if (params->sectigo_cert_type) + json_object_set_string(root_obj, "certificateType", params->sectigo_cert_type); + if (params->sectigo_owner_phone_number) + json_object_set_string(root_obj, "ownerPhoneNumber", params->sectigo_owner_phone_number); + if (params->sectigo_owner_email) + json_object_set_string(root_obj, "ownerEmailAddress", params->sectigo_owner_email); + if (params->sectigo_url) + json_object_set_string(root_obj, "certifierUrl", params->sectigo_url); + // Generate CSR and add to body char *csr_pem = NULL; CertifierError csr_rc = sectigo_generate_certificate_signing_request(certifier, &csr_pem); @@ -421,8 +414,6 @@ if (params->sectigo_url) &cert_output ); - - // Cleanup if (csr_pem) XFREE(csr_pem); if (json_body) json_free_serialized_string(json_body); diff --git a/src/xpki_client.c b/src/xpki_client.c index ac233e5..978eab0 100644 --- a/src/xpki_client.c +++ b/src/xpki_client.c @@ -51,6 +51,8 @@ XPKI_AUTH_TYPE map_to_xpki_auth_type(const char * str) { return XPKI_AUTH_SAT; } + + return XPKI_AUTH_X509; // Default to X509 } const char * xpki_auth_type_to_string(XPKI_AUTH_TYPE auth_type) diff --git a/tests/tests.c b/tests/tests.c index 5e86f55..698430b 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -107,7 +107,8 @@ static void mock_http_set_response_success(const char * body, int status) g_mock_http_response.error = 0; } -static void mock_http_set_response_failure(const char * err, int status) +// Add unused attribute marker to suppress warning +__attribute__((unused)) static void mock_http_set_response_failure(const char * err, int status) { g_mock_http_response.payload = NULL; g_mock_http_response.http_code = status; @@ -115,7 +116,7 @@ static void mock_http_set_response_failure(const char * err, int status) g_mock_http_response.error = status; } -static void test_certifier_client_requests(void ** state) +static void test_certifier_client_requests(void) { const char * csr = "CSr"; @@ -163,9 +164,9 @@ static void test_certifier_client_requests(void ** state) certifier_set_property(certifier, CERTIFIER_OPT_PROFILE_NAME, profile_name); certifier_set_property(certifier, CERTIFIER_OPT_PRODUCT_ID, product_id); - int options = certifier_get_property(certifier, CERTIFIER_OPT_OPTIONS); - options |= CERTIFIER_OPT_CERTIFICATE_LITE; - certifier_set_property(certifier, CERTIFIER_OPT_OPTIONS, options); + int options = (int)(size_t)certifier_get_property(certifier, CERTIFIER_OPT_OPTIONS); + options |= CERTIFIER_OPTION_CERTIFICATE_LITE; + certifier_set_property(certifier, CERTIFIER_OPT_OPTIONS, (void *)(size_t)options); CertifierError rc = certifierclient_request_x509_certificate(_certifier_get_properties(certifier), (unsigned char *) csr, node_address, certifier_id, &ret); @@ -181,7 +182,7 @@ static void test_certifier_client_requests(void ** state) } } -static void test_certifier_client_requests1(void ** state) +static void test_certifier_client_requests1(void) { const char * csr = "CSr"; @@ -196,7 +197,7 @@ static void test_certifier_client_requests1(void ** state) const char * source = "test_libledger"; char * ret = NULL; char * cn_prefix = NULL; - int icount = 0, return_code = 0; + int return_code = 0; unsigned int num_days = 0; JSON_Value * root_value = json_value_init_object(); @@ -207,11 +208,11 @@ static void test_certifier_client_requests1(void ** state) return_code = certifier_set_property(certifier, CERTIFIER_OPT_CN_PREFIX, "xcal.tv"); assert_int_equal(0, return_code); - return_code = certifier_set_property(certifier, CERTIFIER_OPT_VALIDITY_DAYS, 730); + return_code = certifier_set_property(certifier, CERTIFIER_OPT_VALIDITY_DAYS, (void *)(size_t)730); assert_int_equal(0, return_code); cn_prefix = certifier_get_property(certifier, CERTIFIER_OPT_CN_PREFIX); - num_days = certifier_get_property(certifier, CERTIFIER_OPT_VALIDITY_DAYS); + num_days = (unsigned int)(size_t)certifier_get_property(certifier, CERTIFIER_OPT_VALIDITY_DAYS); assert_int_equal(730, num_days); if (cn_prefix) { @@ -253,9 +254,9 @@ static void test_certifier_client_requests1(void ** state) certifier_set_property(certifier, CERTIFIER_OPT_PROFILE_NAME, profile_name); certifier_set_property(certifier, CERTIFIER_OPT_PRODUCT_ID, product_id); - int options = certifier_get_property(certifier, CERTIFIER_OPT_OPTIONS); - options |= CERTIFIER_OPT_CERTIFICATE_LITE; - certifier_set_property(certifier, CERTIFIER_OPT_OPTIONS, options); + int options = (int)(size_t)certifier_get_property(certifier, CERTIFIER_OPT_OPTIONS); + options |= CERTIFIER_OPTION_CERTIFICATE_LITE; + certifier_set_property(certifier, CERTIFIER_OPT_OPTIONS, (void *)(size_t)options); CertifierError rc = certifierclient_request_x509_certificate(_certifier_get_properties(certifier), (unsigned char *) csr, cn_prefix, ledger_id, &ret); @@ -275,7 +276,7 @@ static void test_certifier_client_requests1(void ** state) } } -static void test_certifier_create_crt1(void ** state) +static void test_certifier_create_crt1(void) { int rc = 0; char * out_crt = NULL; @@ -294,7 +295,7 @@ static void test_certifier_create_crt1(void ** state) XFREE(out_crt); } -static void test_certifier_create_node_address(void ** state) +static void test_certifier_create_node_address(void) { int rc = 0; char * node_address = NULL; @@ -310,7 +311,7 @@ static void test_certifier_create_node_address(void ** state) XFREE(node_address); } -static void test_certifier_get_version(void ** state) +static void test_certifier_get_version(void) { char * out_version = certifier_get_version(certifier); @@ -373,7 +374,7 @@ static int tearDown(void ** state) #endif -static void test_base64(void ** state) +static void test_base64(void) { char buf[64]; @@ -415,7 +416,7 @@ static void test_base64(void ** state) assert_memory_equal("\x01\x02\xFF\x80\x81\x7F\x42\x42", buf, 8); } -static void test_base58(void ** state) +static void test_base58(void) { char b58[128]; uint8_t input[26]; @@ -449,7 +450,7 @@ static void test_base58(void ** state) assert_string_equal("1112", b58); } -static void test_file_utils(void ** state) +static void test_file_utils(void) { char temp_file[128]; XSTRCPY(temp_file, "/tmp/certifier_test.XXXXXXX"); @@ -472,7 +473,7 @@ static void test_file_utils(void ** state) assert_int_equal(-1, util_delete_file("/tmp/moved_temp")); } -void test_sha256_ripemd_b58(void ** state) +void test_sha256_ripemd_b58(void) { #define NUM_HASH_INPUTS 180 @@ -556,7 +557,7 @@ void test_sha256_ripemd_b58(void ** state) } } -static void test_set_curl_error(void ** state) +static void test_set_curl_error(void) { char errbuf[1024] = { "some error" }; int res = 0; @@ -566,7 +567,7 @@ static void test_set_curl_error(void ** state) XFREE(err); } -static void test_str_utils(void ** state) +static void test_str_utils(void) { char str[128] = { 0 }; @@ -629,7 +630,7 @@ static void test_str_utils(void ** state) assert_true(util_is_empty(line4)); } -static void test_random_val(void ** state) +static void test_random_val(void) { char * str = util_generate_random_value(5, ""); @@ -661,7 +662,7 @@ static void test_random_val(void ** state) assert_true(b_cnt > 32); } -static void test_ecc_key(void ** state) +static void test_ecc_key(void) { // verify free(NULL) is ok @@ -741,7 +742,7 @@ static void test_ecc_key(void ** state) XFREE(csr); } -static void test_verify_signature_1(void ** state) +static void test_verify_signature_1(void) { const char * pub_key_b64 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPGYYPEBOW/v/Kori+9rkwyDLijQ+OyOcXWN/" @@ -764,7 +765,7 @@ static void test_verify_signature_1(void ** state) security_free_eckey(deserialized_ecc_key); } -static void test_verify_signature_2(void ** state) +static void test_verify_signature_2(void) { int i = 0; @@ -871,7 +872,7 @@ static void test_verify_signature_2(void ** state) } } -void test_x509_cert(void ** state) +void test_x509_cert(void) { const char * digicert_pem_pkcs7_blob = "-----BEGIN PKCS7-----\n" @@ -1127,7 +1128,7 @@ void test_x509_cert(void ** state) security_free_cert_list(cert_list); } -static void test_pkcs12(void ** state) +static void test_pkcs12(void) { const char * pkcs12_blob_base64 = "MIII6AIBAzCCCK4GCSqGSIb3DQEHAaCCCJ8EggibMIIIlzCCB2oGCSqGSIb3DQEHAaCCB1sEggdXMIIHUzCCAz8GCyqGSIb3DQEMCgEDoIIC8DCCAuwGCiqGSI" @@ -1172,7 +1173,6 @@ static void test_pkcs12(void ** state) XFILE pkcs12_file = NULL; X509_LIST * certs = NULL; ECC_KEY * key = NULL; - ECC_KEY * dup_key = NULL; X509_CERT * cert = NULL; char * certifier_id = NULL; char * generated_crt = NULL; @@ -1181,12 +1181,8 @@ static void test_pkcs12(void ** state) unsigned char * der_key = NULL; int der_key_len = 0; int ret = 0; - - char * tmp_crt = NULL; - int rc = 0; - const char * expires = "0"; - const char * action = "allow"; + certifier_set_property(certifier, CERTIFIER_OPT_OUTPUT_NODE, "dummy output node"); blob_len = base64_decode(pkcs12_blob, pkcs12_blob_base64); @@ -1387,7 +1383,7 @@ static void test_pkcs12(void ** state) * The Java equivalent test took ~ 5189 ms to complete 1 million iterations. * This took ~ 4852 ms seconds in C (using -Os compiler flag). */ -static void test_sha256_ripemd_b58_performance(void ** state) +static void test_sha256_ripemd_b58_performance(void) { const char * value_prefix = "value12345678890000000000000000000000-0"; @@ -1438,7 +1434,7 @@ static void cleanup_logs(void) } // still a WIP - need more testing -static void test_logging(void ** state) +static void test_logging(void) { int i; @@ -1464,7 +1460,7 @@ static void test_logging(void ** state) cleanup_logs(); } -static void test_options(void ** state) +static void test_options(void) { CertifierPropMap * props = _certifier_get_properties(certifier); From 28a669c381547e98ef907a061f7a092e1e9fbdbb Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Sun, 8 Feb 2026 23:40:10 -0500 Subject: [PATCH 15/30] Bug fix for reading from config file and various refactoring for variable names, indentation, etc. --- src/certifier.c | 62 ++-- src/certifier_api_easy.c | 99 ++--- src/main.c | 258 +++++++------ src/property.c | 683 +++++++++++++++++++---------------- src/sectigo_client.c | 160 ++++---- tests/xc_apis/xc_api_tests.c | 38 +- 6 files changed, 674 insertions(+), 626 deletions(-) diff --git a/src/certifier.c b/src/certifier.c index 09898ef..4d7c904 100644 --- a/src/certifier.c +++ b/src/certifier.c @@ -1008,50 +1008,52 @@ int certifier_set_property(Certifier * certifier, int name, const void * value) int return_code = 0; if (certifier->sectigo_mode) { - // Only set Sectigo properties for Sectigo flows + // Only set Sectigo properties for Sectigo logical flow return_code = sectigo_property_set(certifier->prop_map, name, value); } else { - // Only set XPKI properties for XPKI flows + // Only set XPKI properties for XPKI logical flow return_code = property_set(certifier->prop_map, name, value); } + if (return_code != 0) { return CERTIFIER_ERR_PROPERTY_SET + return_code; } - switch (name) -{ - case CERTIFIER_OPT_CFG_FILENAME: { - log_info("Configuration file changed; loading settings"); - - CertifierPropMap *orig = certifier->prop_map; - int loader_result = 0; - - if (value != NULL) { - if (certifier->sectigo_mode) { - - loader_result = sectigo_load_cfg_file(certifier); - if (loader_result != 0) { - log_warn("Failed to load Sectigo configuration!"); - return CERTIFIER_ERR_PROPERTY_SET + loader_result; - } - } else { - loader_result = certifier_load_cfg_file(certifier); - if (loader_result == 0) { - - property_destroy(orig); + switch (name) + { + case CERTIFIER_OPT_CFG_FILENAME: + { + log_info("Configuration file changed; loading settings"); + + CertifierPropMap *orig = certifier->prop_map; + + if (value != NULL) { + if (certifier->sectigo_mode) { + return_code = sectigo_load_cfg_file(certifier); + if (return_code != 0) { + log_warn("Failed to load Sectigo configuration!"); + return CERTIFIER_ERR_PROPERTY_SET + return_code; + } } else { - property_destroy(certifier->prop_map); - certifier->prop_map = orig; - loader_result = property_set(certifier->prop_map, name, property_get(orig, name)); - log_warn("Failed to load configuration (configuration unmodified)!"); - return CERTIFIER_ERR_PROPERTY_SET + loader_result; + return_code = certifier_load_cfg_file(certifier); + if (return_code == 0) { + + property_destroy(orig); + + } else { + property_destroy(certifier->prop_map); + certifier->prop_map = orig; + return_code = property_set(certifier->prop_map, name, property_get(orig, name)); + log_warn("Failed to load configuration (configuration unmodified)!"); + return CERTIFIER_ERR_PROPERTY_SET + return_code; + } } } + + break; } - break; -} case CERTIFIER_OPT_LOG_FUNCTION: certifier_set_log_callback(certifier, value); diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index b0ea50e..d897717 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -106,10 +106,10 @@ { "auth-token", required_argument, NULL, 'K' }, \ { "group-name", required_argument, NULL, 'G' }, \ { "group-email", required_argument, NULL, 'E' }, \ - { "owner-fname", required_argument, NULL, 'O' }, \ - { "owner-lname", required_argument, NULL, 'J' }, \ + { "owner-first-name", required_argument, NULL, 'O' }, \ + { "owner-last-name", required_argument, NULL, 'J' }, \ { "owner-email", required_argument, NULL, 'Z' }, \ - { "owner-phonenum", required_argument, NULL, 'U' }, \ + { "owner-phone-number", required_argument, NULL, 'U' }, \ { "cert-type", required_argument, NULL, 'T' }, \ { "config", required_argument, NULL, 'l' }, \ { "tracking-id", required_argument, NULL, 'W' }, \ @@ -157,7 +157,7 @@ static size_t get_command_opt_index(command_opt_lut_t * command_opt_lut, size_t return -1; } -static const char * get_command_opt_helper(CERTIFIER_MODE mode) +static const char * get_xpki_command_opt_helper(CERTIFIER_MODE mode) { #define BASE_HELPER \ "Usage: certifierUtil %s [OPTIONS]\n" \ @@ -788,7 +788,6 @@ static int do_sectigo_get_cert(CERTIFIER * easy) return CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; } - return_code = certifier_setup_keys(easy->certifier); if (return_code != 0) { finish_operation(easy, return_code, NULL); @@ -802,10 +801,9 @@ static int do_sectigo_get_cert(CERTIFIER * easy) return rc.application_error_code; } - // Call Sectigo client to request certificate + // Call Sectigo API to request certificate CertifierPropMap * props = certifier_easy_api_get_props(easy->certifier); rc = sectigo_client_request_certificate(props, (unsigned char *)csr_pem, certifier_get_node_address(easy->certifier), NULL, &cert); - XFREE(csr_pem); @@ -861,7 +859,7 @@ int certifier_api_easy_print_helper(CERTIFIER * easy) "renew-cert\n" "print-cert\n" "revoke\n" - "get-sectigo-cert"); + "get-sectigo-cert\n"); } return 0; @@ -956,7 +954,7 @@ static int process_command_line(CERTIFIER * easy) switch (opt) { case 'h': - XFPRINTF(stdout, get_command_opt_helper(easy->mode), easy->argv[0]); + XFPRINTF(stdout, get_xpki_command_opt_helper(easy->mode), easy->argv[0]); exit(1); case 'c': return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_CA_PATH, optarg); @@ -1155,63 +1153,66 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_LOG_LEVEL, (void *) (size_t) 0); break; case 'C': // common-name - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME, optarg); - } + if (optarg) + { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME, optarg); + } break; case 'I': // id - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_ID, optarg); - } + if (optarg) + { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_ID, optarg); + } break; case 'e': // employee-type - if (optarg) { - // Validate allowed values: "fte", "contractor", "associate" - if (strcmp(optarg, "fte") && strcmp(optarg, "contractor") && strcmp(optarg, "associate")) { - log_error("Invalid employee-type: %s. Allowed: fte, contractor, associate.", optarg); - return_code = 1; - break; - } - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, optarg); - } + if (optarg) { + // Validate allowed values: "fte", "contractor", "associate" + if (strcmp(optarg, "fte") && strcmp(optarg, "contractor") && strcmp(optarg, "associate")) { + log_error("Invalid employee-type: %s. Allowed: fte, contractor, associate.", optarg); + return_code = 1; + break; + } + + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, optarg); + } break; case 's': // server-platform - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, optarg); - } + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, optarg); + } break; case 'N': // sensitive - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE, (void *)true); + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE, (void *)true); break; case 'r': // project-name - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, optarg); - } + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, optarg); + } break; case 'b': // business-justification - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, optarg); - } + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, optarg); + } break; case 'A': // subject-alt-names - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, optarg); - } + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, optarg); + } break; case 'x': // ip-addresses - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, optarg); - } + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, optarg); + } break; case 'K': // auth-token - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, optarg); - } + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, optarg); + } break; case 'u': // sectigo url - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_URL, optarg); - } + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_URL, optarg); + } case 'G': // group-name if (optarg) { return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_GROUP_NAME, optarg); @@ -1222,12 +1223,12 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, optarg); } break; - case 'O': // owner-fname + case 'O': // owner-first-name if (optarg) { return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, optarg); } break; - case 'J': // owner-lname + case 'J': // owner-last-name if (optarg) { return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, optarg); } @@ -1248,7 +1249,7 @@ static int process_command_line(CERTIFIER * easy) } break; case 'Y': //source - if(optarg){ + if (optarg){ return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SOURCE, optarg); } case '?': diff --git a/src/main.c b/src/main.c index f52bf8b..d4171b9 100644 --- a/src/main.c +++ b/src/main.c @@ -54,8 +54,8 @@ typedef union typedef union { - get_cert_sectigo_param_t sectigo_get_cert_param; -}sectigo_parameter_t; + sectigo_get_cert_param_t get_cert_param; +} sectigo_parameter_t; XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, int argc, char ** argv); @@ -127,7 +127,6 @@ SECTIGO_MODE sectigo_get_mode(int argc, char ** argv){ return SECTIGO_MODE_NONE; } - XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) { if (mode == XPKI_MODE_PRINT_VERSION) @@ -163,7 +162,8 @@ XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) return XPKI_CLIENT_SUCCESS; } -SECTIGO_CLIENT_ERROR_CODE sectigo_print_helper(SECTIGO_MODE mode){ +SECTIGO_CLIENT_ERROR_CODE sectigo_print_helper(SECTIGO_MODE mode) +{ if (mode == SECTIGO_MODE_PRINT_HELP || mode == SECTIGO_MODE_NONE) { XFPRINTF(stdout, @@ -230,10 +230,10 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_print_helper(SECTIGO_MODE mode){ { "auth-token", required_argument, NULL, 'K' }, \ { "group-name", required_argument, NULL, 'G' }, \ { "group-email", required_argument, NULL, 'E' }, \ - { "owner-fname", required_argument, NULL, 'O' }, \ - { "owner-lname", required_argument, NULL, 'J' }, \ + { "owner-first-name", required_argument, NULL, 'O' }, \ + { "owner-last-name", required_argument, NULL, 'J' }, \ { "owner-email", required_argument, NULL, 'Z' }, \ - { "owner-phonenum", required_argument, NULL, 'U' }, \ + { "owner-phone-number", required_argument, NULL, 'U' }, \ { "cert-type", required_argument, NULL, 'T' }, \ { "config", required_argument, NULL, 'l' }, \ { "tracking-id", required_argument, NULL, 'W' }, \ @@ -256,7 +256,6 @@ typedef struct const struct option * long_opts; } sectigo_command_opt_lut_t; - static size_t get_command_opt_index(command_opt_lut_t * command_opt_lut, size_t n_entries, XPKI_MODE mode) { for (size_t i = 0; i < n_entries; ++i) @@ -269,7 +268,46 @@ static size_t get_command_opt_index(command_opt_lut_t * command_opt_lut, size_t return -1; } -static const char * get_command_opt_helper(XPKI_MODE mode) +static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) +{ + +#define SECTIGO_BASE_HELPER \ + "Usage: certifierUtil sectigo-get-cert [OPTIONS]\n" + +#define SECTIGO_GET_CERT_HELPER \ + "--common-name [value] (-C)\n" \ + "--id [value] (-I)\n" \ + "--employee-type [value] (-e)\n" \ + "--server-platform [value] (-s)\n" \ + "--sensitive (-N)\n" \ + "--project-name [value] (-r)\n" \ + "--business-justification [value] (-b)\n" \ + "--subject-alt-names [value] (-A)\n" \ + "--ip-addresses [value] (-x)\n" \ + "--group-name [value] (-G)\n" \ + "--group-email [value] (-E)\n" \ + "--owner-first-name [value] (-O)\n" \ + "--owner-last-name [value] (-J)\n" \ + "--owner-email [value] (-Z)\n" \ + "--owner-phone-number [value] (-U)\n" \ + "--cert-type [value] (-T)\n" \ + "--auth-token [value] (-K)\n" \ + "--url [value] (-u)\n" \ + "--config [value] (-l)\n" \ + "--source [value] (-Y)\n" + + switch (mode) + { + case SECTIGO_MODE_GET_CERT: + return SECTIGO_BASE_HELPER SECTIGO_GET_CERT_HELPER; + case SECTIGO_MODE_PRINT_HELP: + return SECTIGO_BASE_HELPER; + default: + return ""; + } +} + +static const char * get_xpki_command_opt_helper(XPKI_MODE mode) { #define BASE_HELPER \ "Usage: certifierUtil %s [OPTIONS]\n" \ @@ -316,8 +354,6 @@ static const char * get_command_opt_helper(XPKI_MODE mode) } } - - XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, int argc, char ** argv) { VerifyOrReturnError(xc_parameter != NULL, XPKI_CLIENT_INVALID_ARGUMENT); @@ -371,9 +407,8 @@ XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, in switch (opt) { case 'h': - XFPRINTF(stdout, get_command_opt_helper(mode), argv[0]); + XFPRINTF(stdout, get_xpki_command_opt_helper(mode), argv[0]); exit(0); - break; case 'c': // return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_CA_PATH, optarg); break; @@ -494,7 +529,7 @@ XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, in } else if (optopt == 'D') { - log_info("Missing mandatory custom property option"); + log_info("Missing mandatory custom property option"); error_code = XPKI_CLIENT_INVALID_ARGUMENT; break; } @@ -564,18 +599,18 @@ static const struct option sectigo_get_cert_long_opts[] = { { "business-justification", required_argument, NULL, 'b' }, { "subject-alt-names", required_argument, NULL, 'A' }, { "ip-addresses", required_argument, NULL, 'x' }, - {"url", required_argument, NULL, 'u'}, + { "url", required_argument, NULL, 'u'}, { "auth-token", required_argument, NULL, 'K' }, { "group-name", required_argument, NULL, 'G' }, { "group-email", required_argument, NULL, 'E' }, - { "owner-fname", required_argument, NULL, 'O' }, - { "owner-lname", required_argument, NULL, 'J' }, + { "owner-first-name", required_argument, NULL, 'O' }, + { "owner-last-name", required_argument, NULL, 'J' }, { "owner-email", required_argument, NULL, 'Z' }, - { "owner-phonenum", required_argument, NULL, 'U' }, + { "owner-phone-number", required_argument, NULL, 'U' }, { "cert-type", required_argument, NULL, 'T' }, { "config", required_argument, NULL, 'l' }, { "tracking-id", required_argument, NULL, 'W' }, - {"source", required_argument, NULL, 'Y'}, + { "source", required_argument, NULL, 'Y'}, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } //make default arg '*' for san and ip @@ -589,9 +624,15 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t VerifyOrReturnError(argv != NULL, SECTIGO_CLIENT_INVALID_ARGUMENT); SECTIGO_CLIENT_ERROR_CODE error_code = SECTIGO_CLIENT_SUCCESS; - memset(§igo_parameter->sectigo_get_cert_param, 0, sizeof(get_cert_sectigo_param_t)); - sectigo_parameter->sectigo_get_cert_param.sectigo_subject_alt_names = ""; - sectigo_parameter->sectigo_get_cert_param.sectigo_ip_addresses = ""; + switch (mode) + { + case SECTIGO_MODE_GET_CERT: + ReturnErrorOnFailure(xc_sectigo_get_default_cert_param(§igo_parameter->get_cert_param)); + break; + default: + return SECTIGO_CLIENT_NOT_IMPLEMENTED; + } + for (;;) { int option_index; @@ -606,168 +647,125 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t switch (opt) { case 'h': - XFPRINTF(stdout, - "Usage: certifierUtil sectigo-get-cert [OPTIONS]\n" - "--common-name [value] (-C)\n" - "--id [value] (-I)\n" - "--employee-type [value] (-e)\n" - "--server-platform [value] (-s)\n" - "--sensitive (-N)\n" - "--project-name [value] (-r)\n" - "--business-justification [value] (-b)\n" - "--subject-alt-names [value] (-A)\n" - "--ip-addresses [value] (-x)\n" - "--group-name [value] (-G)\n" - "--group-email [value] (-E)\n" - "--owner-fname [value] (-O)\n" - "--owner-lname [value] (-J)\n" - "--owner-email [value] (-Z)\n" - "--owner-phonenum [value] (-U)\n" - "--cert-type [value] (-T)\n" - "--auth-token [value] (-K)\n" - "--url [value] (-u)\n" - "--config [value] (-l)\n" - "--tracking-id [value] (-W)\n" - "--source [value] (-Y)\n" -); + XFPRINTF(stdout, get_sectigo_command_opt_helper(mode), argv[0]); exit(0); - break; case 'C': - sectigo_parameter->sectigo_get_cert_param.sectigo_common_name = optarg; + sectigo_parameter->get_cert_param.common_name = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_COMMON_NAME, optarg); break; case 'I': - sectigo_parameter->sectigo_get_cert_param.sectigo_id = optarg; + sectigo_parameter->get_cert_param.id = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_ID, optarg); break; case 'e': - sectigo_parameter->sectigo_get_cert_param.sectigo_employee_type = optarg; + sectigo_parameter->get_cert_param.employee_type = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, optarg); break; case 's': - sectigo_parameter->sectigo_get_cert_param.sectigo_server_platform = optarg; + sectigo_parameter->get_cert_param.server_platform = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, optarg); break; case 'N': - sectigo_parameter->sectigo_get_cert_param.sectigo_sensitive = true; + sectigo_parameter->get_cert_param.sensitive = true; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SENSITIVE, optarg); break; case 'r': - sectigo_parameter->sectigo_get_cert_param.sectigo_project_name = optarg; + sectigo_parameter->get_cert_param.project_name = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_PROJECT_NAME, optarg); break; case 'b': - sectigo_parameter->sectigo_get_cert_param.sectigo_business_justification = optarg; + sectigo_parameter->get_cert_param.business_justification = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, optarg); break; case 'A': - sectigo_parameter->sectigo_get_cert_param.sectigo_subject_alt_names = optarg; + sectigo_parameter->get_cert_param.subject_alt_names = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, optarg); break; case 'x': - sectigo_parameter->sectigo_get_cert_param.sectigo_ip_addresses = optarg; + sectigo_parameter->get_cert_param.ip_addresses = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, optarg); break; case 'l': // config file path, handled in sectigo_perform break; case 'G': - sectigo_parameter->sectigo_get_cert_param.sectigo_group_name = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_GROUP_NAME, optarg); - break; - case 'E': - sectigo_parameter->sectigo_get_cert_param.sectigo_group_email = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, optarg); - break; - case 'O': - sectigo_parameter->sectigo_get_cert_param.sectigo_owner_first_name = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, optarg); - break; - case 'J': - sectigo_parameter->sectigo_get_cert_param.sectigo_owner_last_name = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, optarg); - break; - case 'Z': - sectigo_parameter->sectigo_get_cert_param.sectigo_owner_email = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, optarg); - break; - case 'U': - sectigo_parameter->sectigo_get_cert_param.sectigo_owner_phone_number = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, optarg); - break; - case 'T': - sectigo_parameter->sectigo_get_cert_param.sectigo_cert_type = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERT_TYPE, optarg); - break; - case 'K': - sectigo_parameter->sectigo_get_cert_param.sectigo_auth_token = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, optarg); - break; - case 'u': - sectigo_parameter->sectigo_get_cert_param.sectigo_url = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_URL, optarg); - break; - case 'Y': - sectigo_parameter->sectigo_get_cert_param.sectigo_source = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SOURCE, optarg); - break; - case '?': - log_info("Invalid or missing Sectigo option"); - error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; + sectigo_parameter->get_cert_param.group_name = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_GROUP_NAME, optarg); break; - default: - log_info("Unknown Sectigo option: %c", opt); - error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; + case 'E': + sectigo_parameter->get_cert_param.group_email = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, optarg); break; - } + case 'O': + sectigo_parameter->get_cert_param.owner_first_name = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, optarg); + break; + case 'J': + sectigo_parameter->get_cert_param.owner_last_name = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, optarg); + break; + case 'Z': + sectigo_parameter->get_cert_param.owner_email = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, optarg); + break; + case 'U': + sectigo_parameter->get_cert_param.owner_phone_number = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, optarg); + break; + case 'T': + sectigo_parameter->get_cert_param.cert_type = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERT_TYPE, optarg); + break; + case 'K': + sectigo_parameter->get_cert_param.auth_token = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, optarg); + break; + case 'u': + sectigo_parameter->get_cert_param.sectigo_url = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_URL, optarg); + break; + case 'Y': + sectigo_parameter->get_cert_param.source = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SOURCE, optarg); + break; + case '?': + log_info("Invalid or missing Sectigo option"); + error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; + break; + default: + log_info("Unknown Sectigo option: %c", opt); + error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; + break; + } } return error_code; } -SECTIGO_CLIENT_ERROR_CODE sectigo_perform(int argc, char ** argv){ + +SECTIGO_CLIENT_ERROR_CODE sectigo_perform(int argc, char ** argv) +{ SECTIGO_MODE mode = sectigo_get_mode(argc, argv); - const char *config_path = NULL; + if (mode == SECTIGO_MODE_NONE || mode == SECTIGO_MODE_PRINT_HELP) { return sectigo_print_helper(mode); } - if (argc <= 2) { - fprintf(stderr, "Error: No arguments provided after 'sectigo-get-cert'.\n"); - return SECTIGO_CLIENT_INVALID_ARGUMENT; - } + sectigo_parameter_t sectigo_parameter; + ReturnErrorOnFailure(sectigo_process(mode, §igo_parameter, argc - 1, &argv[1])); + switch (mode) { - case SECTIGO_MODE_GET_CERT: - Certifier *certifier = NULL; - for (int i = 1; i < argc - 1; ++i) { - if ((strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--config") == 0) && (i + 1 < argc)) { - config_path = argv[i + 1]; - break; - } - } - if (config_path) { - certifier = get_sectigo_certifier_instance(); - certifier->sectigo_mode = true; - certifier_set_property(certifier, CERTIFIER_OPT_CFG_FILENAME, config_path); - log_debug("Config loaded, certifier pointer: %p", (void*)certifier); - - } - - - return xc_sectigo_get_cert(§igo_parameter.sectigo_get_cert_param); - break; - case SECTIGO_MODE_NONE: - case SECTIGO_MODE_PRINT_HELP: - return sectigo_print_helper(mode); + return xc_sectigo_get_cert(§igo_parameter.get_cert_param); break; default: break; } return SECTIGO_CLIENT_SUCCESS; } + XPKI_CLIENT_ERROR_CODE xpki_perform(int argc, char ** argv) { XPKI_MODE mode = xpki_get_mode(argc, argv); diff --git a/src/property.c b/src/property.c index 9ea0a6c..262f684 100644 --- a/src/property.c +++ b/src/property.c @@ -201,25 +201,24 @@ struct _PropMap X509_CERT * cert_x509_out; char * mtls_filename; char * mtls_p12_filename; - //Sectigo values - char * sectigo_auth_token; - char * sectigo_common_name; - char * sectigo_group_name; - char * sectigo_group_email; - char * sectigo_id; - char * sectigo_owner_first_name; - char * sectigo_owner_last_name; - char * sectigo_employee_type; - char * sectigo_server_platform; - bool sectigo_sensitive; - char * sectigo_project_name; - char * sectigo_business_justification; - char * sectigo_subject_alt_names; - char * sectigo_ip_addresses; - char * sectigo_owner_phone_number; - char * sectigo_owner_email; - char * sectigo_cert_type; - char * sectigo_source; + + //Sectigo properties (common properties like auth_token, source, etc. are above) + char * common_name; + char * group_name; + char * group_email; + char * id; + char * owner_first_name; + char * owner_last_name; + char * employee_type; + char * server_platform; + bool sensitive; + char * project_name; + char * business_justification; + char * subject_alt_names; + char * ip_addresses; + char * owner_phone_number; + char * owner_email; + char * cert_type; char * sectigo_url; }; @@ -370,58 +369,58 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val log_set_level(prop_map->log_level); break; case CERTIFIER_OPT_SECTIGO_AUTH_TOKEN: - prop_map->sectigo_auth_token = XSTRDUP((const char *)value); + prop_map->auth_token = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_COMMON_NAME: - prop_map->sectigo_common_name = XSTRDUP((const char *)value); + prop_map->common_name = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_GROUP_NAME: - prop_map->sectigo_group_name = XSTRDUP((const char *)value); + prop_map->group_name = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_GROUP_EMAIL: - prop_map->sectigo_group_email = XSTRDUP((const char *)value); + prop_map->group_email = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_ID: - prop_map->sectigo_id = XSTRDUP((const char *)value); + prop_map->id = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME: - prop_map->sectigo_owner_first_name = XSTRDUP((const char *)value); + prop_map->owner_first_name = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME: - prop_map->sectigo_owner_last_name = XSTRDUP((const char *)value); + prop_map->owner_last_name = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE: - prop_map->sectigo_employee_type = XSTRDUP((const char *)value); + prop_map->employee_type = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM: - prop_map->sectigo_server_platform = XSTRDUP((const char *)value); + prop_map->server_platform = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_SENSITIVE: - prop_map->sectigo_sensitive = (bool)(size_t)value; + prop_map->sensitive = (bool)(size_t)value; break; case CERTIFIER_OPT_SECTIGO_PROJECT_NAME: - prop_map->sectigo_project_name = XSTRDUP((const char *)value); + prop_map->project_name = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION: - prop_map->sectigo_business_justification = XSTRDUP((const char *)value); + prop_map->business_justification = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES: - prop_map->sectigo_subject_alt_names = XSTRDUP((const char *)value); + prop_map->subject_alt_names = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_IP_ADDRESSES: - prop_map->sectigo_ip_addresses = XSTRDUP((const char *)value); + prop_map->ip_addresses = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_CERT_TYPE: - prop_map->sectigo_cert_type = XSTRDUP((const char *)value); + prop_map->cert_type = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER: - prop_map->sectigo_owner_phone_number = XSTRDUP((const char *)value); + prop_map->owner_phone_number = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_OWNER_EMAIL: - prop_map->sectigo_owner_email = XSTRDUP((const char *)value); + prop_map->owner_email = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_SOURCE: - prop_map->sectigo_source = XSTRDUP((const char *)value); + prop_map->source = XSTRDUP((const char *)value); break; case CERTIFIER_OPT_SECTIGO_URL: prop_map->sectigo_url = XSTRDUP((const char *)value); @@ -894,58 +893,58 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) } case CERTIFIER_OPT_SECTIGO_AUTH_TOKEN: - retval = (void *) prop_map->sectigo_auth_token; + retval = (void *) prop_map->auth_token; break; case CERTIFIER_OPT_SECTIGO_COMMON_NAME: - retval = (void *) prop_map->sectigo_common_name; + retval = (void *) prop_map->common_name; break; case CERTIFIER_OPT_SECTIGO_GROUP_NAME: - retval = (void *) prop_map->sectigo_group_name; + retval = (void *) prop_map->group_name; break; case CERTIFIER_OPT_SECTIGO_GROUP_EMAIL: - retval = (void *) prop_map->sectigo_group_email; + retval = (void *) prop_map->group_email; break; case CERTIFIER_OPT_SECTIGO_ID: - retval = (void *) prop_map->sectigo_id; + retval = (void *) prop_map->id; break; case CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME: - retval = (void *) prop_map->sectigo_owner_first_name; + retval = (void *) prop_map->owner_first_name; break; case CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME: - retval = (void *) prop_map->sectigo_owner_last_name; + retval = (void *) prop_map->owner_last_name; break; case CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE: - retval = (void *) prop_map->sectigo_employee_type; + retval = (void *) prop_map->employee_type; break; case CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM: - retval = (void *) prop_map->sectigo_server_platform; + retval = (void *) prop_map->server_platform; break; case CERTIFIER_OPT_SECTIGO_SENSITIVE: - retval = (void *)(size_t) prop_map->sectigo_sensitive; + retval = (void *)(size_t) prop_map->sensitive; break; case CERTIFIER_OPT_SECTIGO_PROJECT_NAME: - retval = (void *) prop_map->sectigo_project_name; + retval = (void *) prop_map->project_name; break; case CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION: - retval = (void *) prop_map->sectigo_business_justification; + retval = (void *) prop_map->business_justification; break; case CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES: - retval = (void *) prop_map->sectigo_subject_alt_names; + retval = (void *) prop_map->subject_alt_names; break; case CERTIFIER_OPT_SECTIGO_IP_ADDRESSES: - retval = (void *) prop_map->sectigo_ip_addresses; + retval = (void *) prop_map->ip_addresses; break; case CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER: - retval = (void *) prop_map->sectigo_owner_phone_number; + retval = (void *) prop_map->owner_phone_number; break; case CERTIFIER_OPT_SECTIGO_OWNER_EMAIL: - retval = (void *) prop_map->sectigo_owner_email; + retval = (void *) prop_map->owner_email; break; case CERTIFIER_OPT_SECTIGO_CERT_TYPE: - retval = (void *) prop_map->sectigo_cert_type; + retval = (void *) prop_map->cert_type; break; case CERTIFIER_OPT_SECTIGO_SOURCE: - retval = (void *) prop_map->sectigo_source; + retval = (void *) prop_map->source; break; case CERTIFIER_OPT_SECTIGO_URL: retval = (void *) prop_map->sectigo_url; @@ -1127,257 +1126,63 @@ int property_set_defaults(CertifierPropMap * prop_map) return return_code; } -int property_set_sectigo_defaults_from_cfg_file(CertifierPropMap * propMap) -{ - JSON_Value *json; - int ret = 0; - char *file_contents = NULL; - size_t file_contents_len = 0; - - log_info("Loading Sectigo cfg file: %s", propMap->cfg_filename); - - ret = util_slurp(propMap->cfg_filename, &file_contents, &file_contents_len); - if (ret != 0) { - log_error("Failed to read config file: %s", propMap->cfg_filename); - if (file_contents) XFREE(file_contents); - return 1; - } - - file_contents[file_contents_len] = '\0'; - json = json_parse_string_with_comments(file_contents); - XFREE(file_contents); - if (!json) { - log_error("Failed to parse JSON config file: %s", propMap->cfg_filename); - return 1; - } - - JSON_Object *root = json_object(json); - size_t count = json_object_get_count(root); - for (size_t i = 0; i < count; ++i) { - const char *key = json_object_get_name(root, i); - - // Only process keys starting with "libcertifier.sectigo." - if (strncmp(key, "libcertifier.sectigo.", strlen("libcertifier.sectigo.")) != 0) { - continue; - } - - - - // Handle boolean for sensitive - if (strcmp(key, "libcertifier.sectigo.sensitive") == 0) { - int bool_val = json_object_get_boolean(root, key); - propMap->sectigo_sensitive = (bool)bool_val; - continue; - } - - // Handle arrays for subject alt names and ip addresses - if (strcmp(key, "libcertifier.sectigo.subject.alt.names") == 0) { - const char *array_str = json_object_get_string(root, key); - char *csv = NULL; - if (array_str) { - csv = simple_json_array_to_csv(array_str); - } else { - csv = XSTRDUP(""); // Always set to empty string if missing/empty - } - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, csv); - XFREE(csv); - continue; -} -if (strcmp(key, "libcertifier.sectigo.ip.addresses") == 0) { - const char *array_str = json_object_get_string(root, key); - char *csv = NULL; - if (array_str) { - csv = simple_json_array_to_csv(array_str); - } else { - csv = XSTRDUP(""); - } - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, csv); - XFREE(csv); - continue; -} - - const char *value_str = json_object_get_string(root, key); - if (value_str) { - // Map config key to property enum - if (strcmp(key, "libcertifier.sectigo.auth.token") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, value_str); - else if (strcmp(key, "libcertifier.sectigo.common.name") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_COMMON_NAME, value_str); - else if (strcmp(key, "libcertifier.sectigo.group.name") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_GROUP_NAME, value_str); - else if (strcmp(key, "libcertifier.sectigo.group.email") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, value_str); - else if (strcmp(key, "libcertifier.sectigo.id") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_ID, value_str); - else if (strcmp(key, "libcertifier.sectigo.owner.first.name") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, value_str); - else if (strcmp(key, "libcertifier.sectigo.owner.last.name") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, value_str); - else if (strcmp(key, "libcertifier.sectigo.employee.type") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, value_str); - else if (strcmp(key, "libcertifier.sectigo.server.platform") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, value_str); - else if (strcmp(key, "libcertifier.sectigo.project.name") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, value_str); - else if (strcmp(key, "libcertifier.sectigo.business.justification") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, value_str); - else if (strcmp(key, "libcertifier.sectigo.owner.phone.number") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, value_str); - else if (strcmp(key, "libcertifier.sectigo.owner.email") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, value_str); - else if (strcmp(key, "libcertifier.sectigo.cert.type") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERT_TYPE, value_str); - else if (strcmp(key, "libcertifier.sectigo.url") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_URL, value_str); - else if (strcmp(key, "libcertifier.sectigo.source") == 0) - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SOURCE, value_str); - // Add more mappings as needed - } - } - - if (json) json_value_free(json); - return 0; -} - - -int property_set_ext(CertifierPropMap * prop_map) -{ - JSON_Value * json; - const char * ext_key_usage_value = NULL; - int ret = 0; - - char * file_contents = NULL; - size_t file_contents_len = 0; - - const char * default_cfg_filename = get_default_cfg_filename(); - ret = util_slurp(default_cfg_filename, &file_contents, &file_contents_len); - if (ret != 0) - { - log_error("Received code: %i from util_slurp", ret); - if (file_contents != NULL) - { - XFREE(file_contents); - } - return 1; - } - else - { - file_contents[file_contents_len] = '\0'; - json = json_parse_string_with_comments(file_contents); - XFREE(file_contents); - if (json == NULL) - { - log_error("json_parse_string_with_comments returned a NULL value. Perhaps JSON malformed? Received error code: <%i>", - ret); - return 1; - } - } - - ext_key_usage_value = json_object_get_string(json_object(json), "libcertifier.ext.key.usage"); - if (ext_key_usage_value) - { - // log_info("Loaded Extended Key Usage Values: %s", ext_key_usage_value); - property_set(prop_map, CERTIFIER_OPT_EXT_KEY_USAGE, ext_key_usage_value); - } - - if (json) - { - json_value_free(json); - } - - return 0; -} - -int property_set_defaults_from_cfg_file(CertifierPropMap * propMap) +// Helper function to load XPKI-specific fields from JSON object +static int load_xpki_fields_from_json(CertifierPropMap *propMap, JSON_Object *root) { - - JSON_Value * json; - - const char * certifier_url_value = NULL; - const char * profile_name_value = NULL; - const char * auth_type_value = NULL; - const char * password_value = NULL; - const char * system_id_value = NULL; - const char * fabric_id_value = NULL; - const char * node_id_value = NULL; - const char * product_id_value = NULL; - const char * auth_tag_1_value = NULL; + const char *certifier_url_value = NULL; + const char *profile_name_value = NULL; + const char *auth_type_value = NULL; + const char *password_value = NULL; + const char *system_id_value = NULL; + const char *fabric_id_value = NULL; + const char *node_id_value = NULL; + const char *product_id_value = NULL; + const char *auth_tag_1_value = NULL; int http_timeout_value; int http_connect_timeout_value; int http_trace_value; - const char * input_p12_path_value = NULL; - const char * sat_token_value = NULL; - const char * ca_info_value = NULL; - const char * ca_path_value = NULL; - const char * ecc_curve_id_value = NULL; - const char * log_file_value = NULL; + const char *input_p12_path_value = NULL; + const char *sat_token_value = NULL; + const char *ca_info_value = NULL; + const char *ca_path_value = NULL; + const char *ecc_curve_id_value = NULL; + const char *log_file_value = NULL; int log_level_value; int log_max_size_value; int measure_performance_value; int autorenew_interval_value; int validity_days; - const char * source = NULL; + const char *source = NULL; int certificate_lite_value; int certificate_scopes_value; - const char * cn_prefix = NULL; - const char * ext_key_usage_value = NULL; - const char * autorenew_certs_path_list_value = NULL; - const char * mtls_p12_path_value = NULL; - const char * mtls_password_value = NULL; - - int ret = 0; - - char * file_contents = NULL; - size_t file_contents_len = 0; - - log_info("Loading cfg file: %s", propMap->cfg_filename); - - log_debug("About to call: util_slurp with path: %s", propMap->cfg_filename); - ret = util_slurp(propMap->cfg_filename, &file_contents, &file_contents_len); - if (ret != 0) - { - log_error("Received code: %i from util_slurp", ret); - if (file_contents != NULL) - { - XFREE(file_contents); - } - return 1; - } - else - { - file_contents[file_contents_len] = '\0'; - json = json_parse_string_with_comments(file_contents); - XFREE(file_contents); - if (json == NULL) - { - log_error("json_parse_string_with_comments returned a NULL value. Perhaps JSON malformed? Received error code: <%i>", - ret); - return 1; - } - } + const char *cn_prefix = NULL; + const char *ext_key_usage_value = NULL; + const char *autorenew_certs_path_list_value = NULL; + const char *mtls_p12_path_value = NULL; + const char *mtls_password_value = NULL; - certifier_url_value = json_object_get_string(json_object(json), "libcertifier.certifier.url"); + certifier_url_value = json_object_get_string(root, "libcertifier.certifier.url"); if (certifier_url_value) { log_info("Loaded certifier url: %s from config file.", certifier_url_value); property_set(propMap, CERTIFIER_OPT_CERTIFIER_URL, certifier_url_value); } - profile_name_value = json_object_get_string(json_object(json), "libcertifier.profile.name"); + profile_name_value = json_object_get_string(root, "libcertifier.profile.name"); if (profile_name_value) { log_info("Loaded profile name: %s from config file.", profile_name_value); property_set(propMap, CERTIFIER_OPT_PROFILE_NAME, profile_name_value); } - auth_type_value = json_object_get_string(json_object(json), "libcertifier.auth.type"); + auth_type_value = json_object_get_string(root, "libcertifier.auth.type"); if (auth_type_value) { log_info("Loaded crt.type: %s from config file.", auth_type_value); property_set(propMap, CERTIFIER_OPT_AUTH_TYPE, auth_type_value); } - password_value = json_object_get_string(json_object(json), "libcertifier.input.p12.password"); + password_value = json_object_get_string(root, "libcertifier.input.p12.password"); if (password_value) { print_warning("password"); @@ -1385,56 +1190,56 @@ int property_set_defaults_from_cfg_file(CertifierPropMap * propMap) property_set(propMap, CERTIFIER_OPT_INPUT_P12_PASSWORD, password_value); } - system_id_value = json_object_get_string(json_object(json), "libcertifier.system.id"); + system_id_value = json_object_get_string(root, "libcertifier.system.id"); if (system_id_value) { log_info("Loaded system_id_value: %s from config file.", system_id_value); property_set(propMap, CERTIFIER_OPT_SYSTEM_ID, system_id_value); } - fabric_id_value = json_object_get_string(json_object(json), "libcertifier.fabric.id"); + fabric_id_value = json_object_get_string(root, "libcertifier.fabric.id"); if (fabric_id_value) { log_info("Loaded fabric_id_value: %s from config file.", fabric_id_value); property_set(propMap, CERTIFIER_OPT_FABRIC_ID, fabric_id_value); } - node_id_value = json_object_get_string(json_object(json), "libcertifier.node.id"); + node_id_value = json_object_get_string(root, "libcertifier.node.id"); if (node_id_value) { log_info("Loaded node_id_value: %s from config file.", node_id_value); property_set(propMap, CERTIFIER_OPT_NODE_ID, node_id_value); } - product_id_value = json_object_get_string(json_object(json), "libcertifier.product.id"); + product_id_value = json_object_get_string(root, "libcertifier.product.id"); if (product_id_value) { log_info("Loaded product_id_value: %s from config file.", product_id_value); property_set(propMap, CERTIFIER_OPT_PRODUCT_ID, product_id_value); } - auth_tag_1_value = json_object_get_string(json_object(json), "libcertifier.authentication.tag.1"); + auth_tag_1_value = json_object_get_string(root, "libcertifier.authentication.tag.1"); if (auth_tag_1_value) { log_info("Loaded auth_tag_1_value: %s from config file.", auth_tag_1_value); property_set(propMap, CERTIFIER_OPT_AUTH_TAG_1, auth_tag_1_value); } - http_timeout_value = json_object_get_number(json_object(json), "libcertifier.http.timeout"); + http_timeout_value = json_object_get_number(root, "libcertifier.http.timeout"); if (http_timeout_value >= 0) { log_info("Loaded http_timeout_value: %i from cfg file.", http_timeout_value); property_set(propMap, CERTIFIER_OPT_HTTP_TIMEOUT, (void *) (size_t) http_timeout_value); } - http_connect_timeout_value = json_object_get_number(json_object(json), "libcertifier.http.connect.timeout"); + http_connect_timeout_value = json_object_get_number(root, "libcertifier.http.connect.timeout"); if (http_connect_timeout_value >= 0) { log_info("Loaded http_connect_timeout_value: %i from cfg file.", http_connect_timeout_value); property_set(propMap, CERTIFIER_OPT_HTTP_CONNECT_TIMEOUT, (void *) (size_t) http_connect_timeout_value); } - http_trace_value = json_object_get_number(json_object(json), "libcertifier.http.trace"); + http_trace_value = json_object_get_number(root, "libcertifier.http.trace"); if (http_trace_value == 1) { log_info("Loaded http_trace_value: %i from cfg file.", http_trace_value); @@ -1442,77 +1247,77 @@ int property_set_defaults_from_cfg_file(CertifierPropMap * propMap) propMap->options |= (CERTIFIER_OPTION_TRACE_HTTP | CERTIFIER_OPTION_DEBUG_HTTP); } - measure_performance_value = json_object_get_number(json_object(json), "libcertifier.measure.performance"); + measure_performance_value = json_object_get_number(root, "libcertifier.measure.performance"); if (measure_performance_value == 1) { log_info("Loaded measure.performance: %i from cfg file.", measure_performance_value); propMap->options |= CERTIFIER_OPTION_MEASURE_PERFORMANCE; } - autorenew_interval_value = json_object_get_number(json_object(json), "libcertifier.autorenew.interval"); + autorenew_interval_value = json_object_get_number(root, "libcertifier.autorenew.interval"); if (autorenew_interval_value == 1) { log_info("Loaded autorenew.interval: %i from cfg file.", autorenew_interval_value); property_set(propMap, CERTIFIER_OPT_AUTORENEW_INTERVAL, (void *) (size_t) autorenew_interval_value); } - input_p12_path_value = json_object_get_string(json_object(json), "libcertifier.input.p12.path"); + input_p12_path_value = json_object_get_string(root, "libcertifier.input.p12.path"); if (input_p12_path_value) { log_info("Loaded input_p12_path_value: %s from cfg file.", input_p12_path_value); property_set(propMap, CERTIFIER_OPT_INPUT_P12_PATH, input_p12_path_value); } - sat_token_value = json_object_get_string(json_object(json), "libcertifier.sat.token"); + sat_token_value = json_object_get_string(root, "libcertifier.sat.token"); if (sat_token_value) { log_info("Loaded sat_token_value: %s from cfg file.", sat_token_value); property_set(propMap, CERTIFIER_OPT_AUTH_TOKEN, sat_token_value); } - ca_info_value = json_object_get_string(json_object(json), "libcertifier.ca.info"); + ca_info_value = json_object_get_string(root, "libcertifier.ca.info"); if (ca_info_value) { log_info("Loaded ca_info_value: %s from cfg file.", ca_info_value); property_set(propMap, CERTIFIER_OPT_CA_INFO, ca_info_value); } - ca_path_value = json_object_get_string(json_object(json), "libcertifier.ca.path"); + ca_path_value = json_object_get_string(root, "libcertifier.ca.path"); if (ca_path_value) { log_info("Loaded ca_path_value: %s from cfg file.", ca_path_value); property_set(propMap, CERTIFIER_OPT_CA_PATH, ca_path_value); } - validity_days = json_object_get_number(json_object(json), "libcertifier.validity.days"); + validity_days = json_object_get_number(root, "libcertifier.validity.days"); if (validity_days) { log_info("Loaded validity_days: %d", validity_days); property_set(propMap, CERTIFIER_OPT_VALIDITY_DAYS, (void *) (size_t) validity_days); } - ecc_curve_id_value = json_object_get_string(json_object(json), "libcertifier.ecc.curve.id"); + ecc_curve_id_value = json_object_get_string(root, "libcertifier.ecc.curve.id"); if (ecc_curve_id_value) { log_info("Loaded ecc_curve_id_value: %s from cfg file.", ecc_curve_id_value); property_set(propMap, CERTIFIER_OPT_ECC_CURVE_ID, ecc_curve_id_value); } - log_file_value = json_object_get_string(json_object(json), "libcertifier.log.file"); + log_file_value = json_object_get_string(root, "libcertifier.log.file"); if (log_file_value) { log_info("Loaded Log File Value: %s from cfg file.", log_file_value); property_set(propMap, CERTIFIER_OPT_LOG_FILENAME, log_file_value); } - log_level_value = json_object_get_number(json_object(json), "libcertifier.log.level"); + log_level_value = json_object_get_number(root, "libcertifier.log.level"); if (log_level_value >= 0) { log_info("Loaded Log Level value: %i from cfg file.", log_level_value); property_set(propMap, CERTIFIER_OPT_LOG_LEVEL, (void *) (size_t) (log_level_value)); } - log_max_size_value = json_object_get_number(json_object(json), "libcertifier.log.max.size"); + log_max_size_value = json_object_get_number(root, "libcertifier.log.max.size"); if (log_max_size_value >= 0) { log_info("Loaded Log Max Size value: %i from cfg file.", log_max_size_value); @@ -1520,55 +1325,58 @@ int property_set_defaults_from_cfg_file(CertifierPropMap * propMap) } log_set_max_size(propMap->log_max_size); - source = json_object_get_string(json_object(json), "libcertifier.source.id"); + source = json_object_get_string(root, "libcertifier.source.id"); if (source) { log_info("Loaded source.id %s from cfg file.", source); property_set(propMap, CERTIFIER_OPT_SOURCE, source); } - certificate_lite_value = json_object_get_number(json_object(json), "libcertifier.certificate.lite"); + certificate_lite_value = json_object_get_number(root, "libcertifier.certificate.lite"); if (certificate_lite_value == 1) { log_info("Loaded certificate.lite: %i from cfg file.", certificate_lite_value); print_warning("certificate.lite"); propMap->options |= (CERTIFIER_OPTION_CERTIFICATE_LITE); } - certificate_scopes_value = json_object_get_number(json_object(json), "libcertifier.certificate.scopes"); + + certificate_scopes_value = json_object_get_number(root, "libcertifier.certificate.scopes"); if (certificate_scopes_value == 1) { log_info("Loaded certificate.scopes: %i from cfg file.", certificate_scopes_value); print_warning("certificate.scopes"); propMap->options |= (CERTIFIER_OPTION_USE_SCOPES); } - cn_prefix = json_object_get_string(json_object(json), "libcertifier.cn.name"); + + cn_prefix = json_object_get_string(root, "libcertifier.cn.name"); if (cn_prefix != NULL) { log_info("Loaded Common Name value: %s from cfg file.", cn_prefix); property_set(propMap, CERTIFIER_OPT_CN_PREFIX, cn_prefix); } - ext_key_usage_value = json_object_get_string(json_object(json), "libcertifier.ext.key.usage"); + + ext_key_usage_value = json_object_get_string(root, "libcertifier.ext.key.usage"); if (ext_key_usage_value) { log_info("Loaded Extended Key Usage Values: %s from cfg file.", ext_key_usage_value); property_set(propMap, CERTIFIER_OPT_EXT_KEY_USAGE, ext_key_usage_value); } - autorenew_certs_path_list_value = json_object_get_string(json_object(json), "libcertifier.autorenew.certs.path.list"); + autorenew_certs_path_list_value = json_object_get_string(root, "libcertifier.autorenew.certs.path.list"); if (autorenew_certs_path_list_value) { log_info("Loaded autorenew certs path: %s from config file.", autorenew_certs_path_list_value); property_set(propMap, CERTIFIER_OPT_AUTORENEW_CERTS_PATH_LIST, autorenew_certs_path_list_value); } - mtls_p12_path_value = json_object_get_string(json_object(json), "libcertifier.mtls.p12.path"); + mtls_p12_path_value = json_object_get_string(root, "libcertifier.mtls.p12.path"); if (mtls_p12_path_value) { log_info("Loaded mtls_p12_path_value: %s from cfg file.", mtls_p12_path_value); property_set(propMap, CERTIFIER_OPT_MTLS_P12_PATH, mtls_p12_path_value); } - mtls_password_value = json_object_get_string(json_object(json), "libcertifier.mtls.p12.password"); + mtls_password_value = json_object_get_string(root, "libcertifier.mtls.p12.password"); if (mtls_password_value) { print_warning("password"); @@ -1576,6 +1384,236 @@ int property_set_defaults_from_cfg_file(CertifierPropMap * propMap) property_set(propMap, CERTIFIER_OPT_MTLS_P12_PASSWORD, mtls_password_value); } + return 0; +} + +// Helper function to load Sectigo-specific fields from JSON object +static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object *root) +{ + // Iterate through all keys in the JSON object + size_t count = json_object_get_count(root); + for (size_t i = 0; i < count; i++) { + const char *key = json_object_get_name(root, i); + + // Only process keys that start with "libcertifier.sectigo." + if (strncmp(key, "libcertifier.sectigo.", 21) != 0) { + continue; + } + + // Special handling for boolean keys + if (strcmp(key, "libcertifier.sectigo.sensitive") == 0) { + int bool_value = json_object_get_boolean(root, key); + if (bool_value != -1) { // -1 indicates not a boolean + log_info("Loaded sectigo sensitive: %s from config file.", bool_value ? "true" : "false"); + propMap->sensitive = (bool)bool_value; + } + continue; + } + + // Special handling for array keys + if (strcmp(key, "libcertifier.sectigo.subject.alt.names") == 0) { + const char *array_str = json_object_get_string(root, key); + char *csv = NULL; + if (array_str) { + csv = simple_json_array_to_csv(array_str); + } + if (!csv) { + csv = XSTRDUP(""); // Always set to empty string if missing/empty + } + log_info("Loaded sectigo subject alt names: %s from config file.", csv); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, csv); + XFREE(csv); + continue; + } + if (strcmp(key, "libcertifier.sectigo.ip.addresses") == 0) { + const char *array_str = json_object_get_string(root, key); + char *csv = NULL; + if (array_str) { + csv = simple_json_array_to_csv(array_str); + } else { + csv = XSTRDUP(""); + } + log_info("Loaded sectigo IP addresses: %s from config file.", csv); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, csv); + XFREE(csv); + continue; + } + + const char *value_str = json_object_get_string(root, key); + if (value_str) { + // Map config key to property enum + if (strcmp(key, "libcertifier.sectigo.auth.token") == 0) { + log_info("Loaded sectigo auth token from config file."); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.common.name") == 0) { + log_info("Loaded sectigo common name: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_COMMON_NAME, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.group.name") == 0) { + log_info("Loaded sectigo group name: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_GROUP_NAME, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.group.email") == 0) { + log_info("Loaded sectigo group email: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.id") == 0) { + log_info("Loaded sectigo id: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_ID, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.owner.first.name") == 0) { + log_info("Loaded sectigo owner first name: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.owner.last.name") == 0) { + log_info("Loaded sectigo owner last name: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.employee.type") == 0) { + log_info("Loaded sectigo employee type: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.server.platform") == 0) { + log_info("Loaded sectigo server platform: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.project.name") == 0) { + log_info("Loaded sectigo project name: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.business.justification") == 0) { + log_info("Loaded sectigo business justification: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.owner.phone.number") == 0) { + log_info("Loaded sectigo owner phone number: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.owner.email") == 0) { + log_info("Loaded sectigo owner email: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.cert.type") == 0) { + log_info("Loaded sectigo cert type: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERT_TYPE, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.url") == 0) { + log_info("Loaded sectigo URL: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_URL, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.source") == 0) { + log_info("Loaded sectigo source: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SOURCE, value_str); + } + // Add more mappings as needed + } + } + + return 0; +} + +// Config file loader with mode-aware field loading +static int property_set_defaults_from_cfg_file_ex(CertifierPropMap *propMap, bool sectigo_mode) +{ + JSON_Value *json = NULL; + int ret = 0; + char *file_contents = NULL; + size_t file_contents_len = 0; + const char *cfg_filename = propMap->cfg_filename; + + if (!cfg_filename) { + log_warn("No config filename set, skipping defaults from cfg file"); + return 0; + } + + log_info("Loading %s cfg file: %s", sectigo_mode ? "Sectigo" : "XPKI", cfg_filename); + log_debug("property_set_defaults_from_cfg_file_ex called with sectigo_mode=%d", sectigo_mode); + + ret = util_slurp(cfg_filename, &file_contents, &file_contents_len); + if (ret != 0) { + log_error("Failed to read cfg file: %s (error code: %i)", cfg_filename, ret); + if (file_contents) { + XFREE(file_contents); + } + return 1; + } + + file_contents[file_contents_len] = '\0'; + json = json_parse_string_with_comments(file_contents); + XFREE(file_contents); + + if (!json) { + log_error("Failed to parse JSON from cfg file: %s", cfg_filename); + return 1; + } + + JSON_Object *root = json_object(json); + if (!root) { + log_error("JSON root object is NULL"); + json_value_free(json); + return 1; + } + + // Delegate to mode-specific field loader + if (sectigo_mode) { + log_debug("Delegating to load_sectigo_fields_from_json"); + ret = load_sectigo_fields_from_json(propMap, root); + } else { + log_debug("Delegating to load_xpki_fields_from_json"); + ret = load_xpki_fields_from_json(propMap, root); + } + + json_value_free(json); + return ret; +} + +int property_set_sectigo_defaults_from_cfg_file(CertifierPropMap * propMap) +{ + return property_set_defaults_from_cfg_file_ex(propMap, true); +} + + +int property_set_ext(CertifierPropMap * prop_map) +{ + JSON_Value * json; + const char * ext_key_usage_value = NULL; + int ret = 0; + + char * file_contents = NULL; + size_t file_contents_len = 0; + + const char * default_cfg_filename = get_default_cfg_filename(); + ret = util_slurp(default_cfg_filename, &file_contents, &file_contents_len); + if (ret != 0) + { + log_error("Received code: %i from util_slurp", ret); + if (file_contents != NULL) + { + XFREE(file_contents); + } + return 1; + } + else + { + file_contents[file_contents_len] = '\0'; + json = json_parse_string_with_comments(file_contents); + XFREE(file_contents); + if (json == NULL) + { + log_error("json_parse_string_with_comments returned a NULL value. Perhaps JSON malformed? Received error code: <%i>", + ret); + return 1; + } + } + + ext_key_usage_value = json_object_get_string(json_object(json), "libcertifier.ext.key.usage"); + if (ext_key_usage_value) + { + log_info("Loaded Extended Key Usage Values: %s", ext_key_usage_value); + property_set(prop_map, CERTIFIER_OPT_EXT_KEY_USAGE, ext_key_usage_value); + } + if (json) { json_value_free(json); @@ -1584,6 +1622,11 @@ int property_set_defaults_from_cfg_file(CertifierPropMap * propMap) return 0; } +int property_set_defaults_from_cfg_file(CertifierPropMap * propMap) +{ + return property_set_defaults_from_cfg_file_ex(propMap, false); +} + #define FV(field) \ if (field != NULL) \ { \ @@ -1632,23 +1675,23 @@ static void free_prop_map_values(CertifierPropMap * prop_map) security_free_cert(prop_map->cert_x509_out); FV(prop_map->mtls_filename); FV(prop_map->mtls_p12_filename); - FV(prop_map->sectigo_auth_token); - FV(prop_map->sectigo_common_name); - FV(prop_map->sectigo_group_name); - FV(prop_map->sectigo_group_email); - FV(prop_map->sectigo_id); - FV(prop_map->sectigo_owner_first_name); - FV(prop_map->sectigo_owner_last_name); - FV(prop_map->sectigo_employee_type); - FV(prop_map->sectigo_server_platform); - FV(prop_map->sectigo_project_name); - FV(prop_map->sectigo_business_justification); - FV(prop_map->sectigo_subject_alt_names); - FV(prop_map->sectigo_ip_addresses); - FV(prop_map->sectigo_owner_phone_number); - FV(prop_map->sectigo_owner_email); - FV(prop_map->sectigo_cert_type); - FV(prop_map->sectigo_source); + FV(prop_map->auth_token); + FV(prop_map->common_name); + FV(prop_map->group_name); + FV(prop_map->group_email); + FV(prop_map->id); + FV(prop_map->owner_first_name); + FV(prop_map->owner_last_name); + FV(prop_map->employee_type); + FV(prop_map->server_platform); + FV(prop_map->project_name); + FV(prop_map->business_justification); + FV(prop_map->subject_alt_names); + FV(prop_map->ip_addresses); + FV(prop_map->owner_phone_number); + FV(prop_map->owner_email); + FV(prop_map->cert_type); + FV(prop_map->source); FV(prop_map->sectigo_url); } diff --git a/src/sectigo_client.c b/src/sectigo_client.c index f2055dd..b052226 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -40,77 +40,80 @@ Certifier * get_sectigo_certifier_instance() if (certifier == NULL) { - certifier = XCALLOC(1, sizeof(Certifier)); - certifier->sectigo_mode = true; - certifier->prop_map = property_new_sectigo(); + certifier = certifier_new(); certifier_set_property(certifier, CERTIFIER_OPT_LOG_LEVEL, (void *) (size_t) 0); - certifier_set_property(certifier, CERTIFIER_OPT_SECTIGO_URL, "https://certs-dev.xpki.io/api/createCertificate"); + + // Load Sectigo config file if it exists + const char *cfg_filename = certifier_get_property(certifier, CERTIFIER_OPT_CFG_FILENAME); + if (cfg_filename && access(cfg_filename, F_OK) == 0) { + sectigo_load_cfg_file(certifier); + } } return certifier; } -SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(get_cert_sectigo_param_t * params) +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_param_t * params) { Certifier * certifier = get_sectigo_certifier_instance(); - memset(params, 0, sizeof(get_cert_sectigo_param_t)); + memset(params, 0, sizeof(sectigo_get_cert_param_t)); void * param = NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); - params->sectigo_auth_token = param ? XSTRDUP((const char *)param) : NULL; + params->auth_token = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); - params->sectigo_common_name = param ? XSTRDUP((const char *)param) : NULL; + params->common_name = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_GROUP_NAME); - params->sectigo_group_name = param ? XSTRDUP((const char *)param) : NULL; + params->group_name = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL); - params->sectigo_group_email = param ? XSTRDUP((const char *)param) : NULL; + params->group_email = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_ID); - params->sectigo_id = param ? XSTRDUP((const char *)param) : NULL; + params->id = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME); - params->sectigo_owner_first_name = param ? XSTRDUP((const char *)param) : NULL; + params->owner_first_name = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME); - params->sectigo_owner_last_name = param ? XSTRDUP((const char *)param) : NULL; + params->owner_last_name = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE); - params->sectigo_employee_type = param ? XSTRDUP((const char *)param) : NULL; + params->employee_type = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM); - params->sectigo_server_platform = param ? XSTRDUP((const char *)param) : NULL; + params->server_platform = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME); - params->sectigo_project_name = param ? XSTRDUP((const char *)param) : NULL; + params->project_name = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION); - params->sectigo_business_justification = param ? XSTRDUP((const char *)param) : NULL; + params->business_justification = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES); - params->sectigo_subject_alt_names = param ? XSTRDUP((const char *)param) : NULL; + params->subject_alt_names = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES); - params->sectigo_ip_addresses = param ? XSTRDUP((const char *)param) : NULL; + params->ip_addresses = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERT_TYPE); - params->sectigo_cert_type = param ? XSTRDUP((const char *)param) : NULL; + params->cert_type = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER); - params->sectigo_owner_phone_number = param ? XSTRDUP((const char *)param) : NULL; + params->owner_phone_number = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL); - params->sectigo_owner_email = param ? XSTRDUP((const char *)param) : NULL; + params->owner_email = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_URL); params->sectigo_url = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE); - params->sectigo_sensitive = param ? *((bool *)param) : false; + params->sensitive = param ? *((bool *)param) : false; return SECTIGO_CLIENT_SUCCESS; } @@ -141,7 +144,7 @@ const char * node_address, const char * certifier_id, char ** out_cert) const char * tracking_id = property_get(props, CERTIFIER_OPT_TRACKING_ID); const char * bearer_token = property_get(props, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); const char * source = property_get(props, CERTIFIER_OPT_SECTIGO_SOURCE); - const char * certifier_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); + const char * sectigo_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); if (!bearer_token) { log_error("Missing CERTIFIER_OPT_SECTIGO_AUTH_TOKEN"); @@ -149,10 +152,10 @@ const char * node_address, const char * certifier_id, char ** out_cert) rc.application_error_msg = util_format_error_here("Bearer token is missing"); goto cleanup; } - if (!certifier_url) { + if (!sectigo_url) { log_error("Missing CERTIFIER_OPT_SECTIGO_URL"); rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; - rc.application_error_msg = util_format_error_here("Certifier URL is missing"); + rc.application_error_msg = util_format_error_here("Sectigo URL is missing"); goto cleanup; } if (!source) { @@ -212,7 +215,8 @@ const char * node_address, const char * certifier_id, char ** out_cert) rc.application_error_msg = "sectigo_client_request_certificate: pthread_mutex_unlock failed"; goto cleanup; } - get_cert_sectigo_param_t params; + + sectigo_get_cert_param_t params; xc_sectigo_get_default_cert_param(¶ms); // Build JSON body @@ -221,28 +225,28 @@ const char * node_address, const char * certifier_id, char ** out_cert) json_object_set_string(root_obj, "certificateSigningRequest", serialized_string); - json_object_set_string(root_obj, "commonName", params.sectigo_common_name ? params.sectigo_common_name : ""); - json_object_set_string(root_obj, "groupName", params.sectigo_group_name ? params.sectigo_group_name : ""); - json_object_set_string(root_obj, "groupEmailAddress", params.sectigo_group_email ? params.sectigo_group_email : ""); - json_object_set_string(root_obj, "id", params.sectigo_id ? params.sectigo_id : ""); - json_object_set_string(root_obj, "ownerFirstName", params.sectigo_owner_first_name ? params.sectigo_owner_first_name : ""); - json_object_set_string(root_obj, "ownerLastName", params.sectigo_owner_last_name ? params.sectigo_owner_last_name : ""); - json_object_set_string(root_obj, "employeeType", params.sectigo_employee_type ? params.sectigo_employee_type : ""); - json_object_set_string(root_obj, "serverPlatform", params.sectigo_server_platform ? params.sectigo_server_platform : ""); - json_object_set_string(root_obj, "projectName", params.sectigo_project_name ? params.sectigo_project_name : ""); - json_object_set_string(root_obj, "businessJustification", params.sectigo_business_justification ? params.sectigo_business_justification : ""); - json_object_set_string(root_obj, "certificateType", params.sectigo_cert_type ? params.sectigo_cert_type : ""); - json_object_set_string(root_obj, "ownerPhoneNumber", params.sectigo_owner_phone_number ? params.sectigo_owner_phone_number : ""); - json_object_set_string(root_obj, "ownerEmailAddress", params.sectigo_owner_email ? params.sectigo_owner_email : ""); + json_object_set_string(root_obj, "commonName", params.common_name ? params.common_name : ""); + json_object_set_string(root_obj, "groupName", params.group_name ? params.group_name : ""); + json_object_set_string(root_obj, "groupEmailAddress", params.group_email ? params.group_email : ""); + json_object_set_string(root_obj, "id", params.id ? params.id : ""); + json_object_set_string(root_obj, "ownerFirstName", params.owner_first_name ? params.owner_first_name : ""); + json_object_set_string(root_obj, "ownerLastName", params.owner_last_name ? params.owner_last_name : ""); + json_object_set_string(root_obj, "employeeType", params.employee_type ? params.employee_type : ""); + json_object_set_string(root_obj, "serverPlatform", params.server_platform ? params.server_platform : ""); + json_object_set_string(root_obj, "projectName", params.project_name ? params.project_name : ""); + json_object_set_string(root_obj, "businessJustification", params.business_justification ? params.business_justification : ""); + json_object_set_string(root_obj, "certificateType", params.cert_type ? params.cert_type : ""); + json_object_set_string(root_obj, "ownerPhoneNumber", params.owner_phone_number ? params.owner_phone_number : ""); + json_object_set_string(root_obj, "ownerEmailAddress", params.owner_email ? params.owner_email : ""); json_object_set_string(root_obj, "certifierUrl", params.sectigo_url ? params.sectigo_url : ""); - json_object_set_value(root_obj, "sensitive", json_value_init_boolean(params.sectigo_sensitive)); + json_object_set_value(root_obj, "sensitive", json_value_init_boolean(params.sensitive)); // Always set subjectAltNames and ipAddresses, even if empty // subjectAltNames as array JSON_Value *san_array = json_value_init_array(); JSON_Array *san_json_array = json_value_get_array(san_array); - if (params.sectigo_subject_alt_names && strlen(params.sectigo_subject_alt_names) > 0) { - char *san_copy = XSTRDUP(params.sectigo_subject_alt_names); + if (params.subject_alt_names && strlen(params.subject_alt_names) > 0) { + char *san_copy = XSTRDUP(params.subject_alt_names); char *token = strtok(san_copy, ","); while (token) { json_array_append_value(san_json_array, json_value_init_string(token)); @@ -255,8 +259,8 @@ const char * node_address, const char * certifier_id, char ** out_cert) // ipAddresses as array JSON_Value *ip_array = json_value_init_array(); JSON_Array *ip_json_array = json_value_get_array(ip_array); - if (params.sectigo_ip_addresses && strlen(params.sectigo_ip_addresses) > 0) { - char *ip_copy = XSTRDUP(params.sectigo_ip_addresses); + if (params.ip_addresses && strlen(params.ip_addresses) > 0) { + char *ip_copy = XSTRDUP(params.ip_addresses); char *token = strtok(ip_copy, ","); while (token) { json_array_append_value(ip_json_array, json_value_init_string(token)); @@ -268,7 +272,7 @@ const char * node_address, const char * certifier_id, char ** out_cert) json_object_set_value(root_obj, "ipAddresses", ip_array); json_body = json_serialize_to_string(root_value); - resp = http_post(props, certifier_url, headers, json_body); + resp = http_post(props, sectigo_url, headers, json_body); if (resp == NULL) { goto cleanup; @@ -322,7 +326,7 @@ const char * node_address, const char * certifier_id, char ** out_cert) return rc; } -SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params) +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params) { Certifier *certifier = get_sectigo_certifier_instance(); @@ -331,32 +335,32 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params) JSON_Object *root_obj = json_value_get_object(root_value); // Add all parameters to JSON body using passed-in params - if (params->sectigo_common_name) - json_object_set_string(root_obj, "commonName", params->sectigo_common_name); - if (params->sectigo_group_name) - json_object_set_string(root_obj, "groupName", params->sectigo_group_name); - if (params->sectigo_group_email) - json_object_set_string(root_obj, "groupEmailAddress", params->sectigo_group_email); - if (params->sectigo_id) - json_object_set_string(root_obj, "id", params->sectigo_id); - if (params->sectigo_owner_first_name) - json_object_set_string(root_obj, "ownerFirstName", params->sectigo_owner_first_name); - if (params->sectigo_owner_last_name) - json_object_set_string(root_obj, "ownerLastName", params->sectigo_owner_last_name); - if (params->sectigo_employee_type) - json_object_set_string(root_obj, "employeeType", params->sectigo_employee_type); - if (params->sectigo_server_platform) - json_object_set_string(root_obj, "serverPlatform", params->sectigo_server_platform); - if (params->sectigo_project_name) - json_object_set_string(root_obj, "projectName", params->sectigo_project_name); - if (params->sectigo_business_justification) - json_object_set_string(root_obj, "businessJustification", params->sectigo_business_justification); + if (params->common_name) + json_object_set_string(root_obj, "commonName", params->common_name); + if (params->group_name) + json_object_set_string(root_obj, "groupName", params->group_name); + if (params->group_email) + json_object_set_string(root_obj, "groupEmailAddress", params->group_email); + if (params->id) + json_object_set_string(root_obj, "id", params->id); + if (params->owner_first_name) + json_object_set_string(root_obj, "ownerFirstName", params->owner_first_name); + if (params->owner_last_name) + json_object_set_string(root_obj, "ownerLastName", params->owner_last_name); + if (params->employee_type) + json_object_set_string(root_obj, "employeeType", params->employee_type); + if (params->server_platform) + json_object_set_string(root_obj, "serverPlatform", params->server_platform); + if (params->project_name) + json_object_set_string(root_obj, "projectName", params->project_name); + if (params->business_justification) + json_object_set_string(root_obj, "businessJustification", params->business_justification); // subjectAltNames as array JSON_Value *san_array = json_value_init_array(); JSON_Array *san_json_array = json_value_get_array(san_array); - if (params->sectigo_subject_alt_names && strlen(params->sectigo_subject_alt_names) > 0) { - char *san_copy = XSTRDUP(params->sectigo_subject_alt_names); + if (params->subject_alt_names && strlen(params->subject_alt_names) > 0) { + char *san_copy = XSTRDUP(params->subject_alt_names); char *token = strtok(san_copy, ","); while (token) { json_array_append_value(san_json_array, json_value_init_string(token)); @@ -369,8 +373,8 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params) // ipAddresses as array JSON_Value *ip_array = json_value_init_array(); JSON_Array *ip_json_array = json_value_get_array(ip_array); - if (params->sectigo_ip_addresses && strlen(params->sectigo_ip_addresses) > 0) { - char *ip_copy = XSTRDUP(params->sectigo_ip_addresses); + if (params->ip_addresses && strlen(params->ip_addresses) > 0) { + char *ip_copy = XSTRDUP(params->ip_addresses); char *token = strtok(ip_copy, ","); while (token) { json_array_append_value(ip_json_array, json_value_init_string(token)); @@ -380,12 +384,12 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params) } json_object_set_value(root_obj, "ipAddresses", ip_array); - if (params->sectigo_cert_type) - json_object_set_string(root_obj, "certificateType", params->sectigo_cert_type); - if (params->sectigo_owner_phone_number) - json_object_set_string(root_obj, "ownerPhoneNumber", params->sectigo_owner_phone_number); - if (params->sectigo_owner_email) - json_object_set_string(root_obj, "ownerEmailAddress", params->sectigo_owner_email); + if (params->cert_type) + json_object_set_string(root_obj, "certificateType", params->cert_type); + if (params->owner_phone_number) + json_object_set_string(root_obj, "ownerPhoneNumber", params->owner_phone_number); + if (params->owner_email) + json_object_set_string(root_obj, "ownerEmailAddress", params->owner_email); if (params->sectigo_url) json_object_set_string(root_obj, "certifierUrl", params->sectigo_url); @@ -393,7 +397,7 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params) char *csr_pem = NULL; CertifierError csr_rc = sectigo_generate_certificate_signing_request(certifier, &csr_pem); if (csr_rc.application_error_code != 0 || csr_pem == NULL) { - log_error("Failed to generate CSR: %s", csr_rc.application_error_msg); + log_error("Failed to generate CSR: %s\n", csr_rc.application_error_msg); if (csr_pem) XFREE(csr_pem); json_value_free(root_value); return csr_rc.application_error_code; diff --git a/tests/xc_apis/xc_api_tests.c b/tests/xc_apis/xc_api_tests.c index ddcadab..fc988e5 100644 --- a/tests/xc_apis/xc_api_tests.c +++ b/tests/xc_apis/xc_api_tests.c @@ -240,28 +240,28 @@ static void test_get_cert_validity() static void test_get_sectigo_cert() { SECTIGO_CLIENT_ERROR_CODE error; - get_cert_sectigo_param_t params = { 0 }; + sectigo_get_cert_param_t params = { 0 }; // Fill parameters (simulate config or CLI) - params.sectigo_auth_token = "token"; - params.sectigo_common_name = "sectigotest.comcast.com"; - params.sectigo_group_name = "GroupName"; - params.sectigo_group_email = "example@comcast.com"; - params.sectigo_id = "exid"; - params.sectigo_owner_first_name = "First"; - params.sectigo_owner_last_name = "Last"; - params.sectigo_employee_type = "associate"; - params.sectigo_server_platform = "other"; - params.sectigo_sensitive = "false"; - params.sectigo_project_name = "Testing create with SAT"; - params.sectigo_business_justification = "Testing create with SAT"; - params.sectigo_subject_alt_names = "*"; - params.sectigo_ip_addresses = "*"; - params.sectigo_cert_type = "comodo"; - params.sectigo_owner_phone_number = "2670000000"; - params.sectigo_owner_email = "first_last@comcast.com"; + params.auth_token = "token"; + params.common_name = "sectigotest.comcast.com"; + params.group_name = "GroupName"; + params.group_email = "example@comcast.com"; + params.id = "exid"; + params.owner_first_name = "First"; + params.owner_last_name = "Last"; + params.employee_type = "associate"; + params.server_platform = "other"; + params.sensitive = "false"; + params.project_name = "Testing create with SAT"; + params.business_justification = "Testing create with SAT"; + params.subject_alt_names = "*"; + params.ip_addresses = "*"; + params.cert_type = "comodo"; + params.owner_phone_number = "2670000000"; + params.owner_email = "first_last@comcast.com"; params.sectigo_url = "https://certs-dev.xpki.io/api/createCertificate"; - params.sectigo_source = "libcertifier"; + params.source = "libcertifier"; // Call the API error = xc_sectigo_get_cert(¶ms); From 4bbf8ad331e0f41e4f449efaf8e3bc567baca8c2 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Mon, 9 Feb 2026 00:01:34 -0500 Subject: [PATCH 16/30] Dynamic formation of request endpoint. Remove unnecessary cert type property. Only log when properties are loaded meaningfully --- libcertifier.cfg.sample | 1 - src/property.c | 2 +- src/sectigo_client.c | 18 +++++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index 0f8eae5..06a9401 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -40,7 +40,6 @@ "libcertifier.sectigo.business.justification": "Testing", "libcertifier.sectigo.subject.alt.names": [], "libcertifier.sectigo.ip.addresses": [], - "libcertifier.sectigo.cert.type": "comodo", "libcertifier.sectigo.owner.phone.number": "1234567890", "libcertifier.sectigo.owner.email": "owner@example.com", "libcertifier.sectigo.source": "libcertifier" diff --git a/src/property.c b/src/property.c index 262f684..139aae4 100644 --- a/src/property.c +++ b/src/property.c @@ -1440,7 +1440,7 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object } const char *value_str = json_object_get_string(root, key); - if (value_str) { + if (value_str && strlen(value_str) > 0) { // Only process non-empty values // Map config key to property enum if (strcmp(key, "libcertifier.sectigo.auth.token") == 0) { log_info("Loaded sectigo auth token from config file."); diff --git a/src/sectigo_client.c b/src/sectigo_client.c index b052226..f4ef54e 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -144,7 +144,7 @@ const char * node_address, const char * certifier_id, char ** out_cert) const char * tracking_id = property_get(props, CERTIFIER_OPT_TRACKING_ID); const char * bearer_token = property_get(props, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); const char * source = property_get(props, CERTIFIER_OPT_SECTIGO_SOURCE); - const char * sectigo_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); + const char * sectigo_base_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); if (!bearer_token) { log_error("Missing CERTIFIER_OPT_SECTIGO_AUTH_TOKEN"); @@ -152,10 +152,10 @@ const char * node_address, const char * certifier_id, char ** out_cert) rc.application_error_msg = util_format_error_here("Bearer token is missing"); goto cleanup; } - if (!sectigo_url) { + if (!sectigo_base_url) { log_error("Missing CERTIFIER_OPT_SECTIGO_URL"); rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; - rc.application_error_msg = util_format_error_here("Sectigo URL is missing"); + rc.application_error_msg = util_format_error_here("Sectigo base URL is missing"); goto cleanup; } if (!source) { @@ -165,8 +165,16 @@ const char * node_address, const char * certifier_id, char ** out_cert) goto cleanup; } + // Build full URL: base + endpoint + char sectigo_create_cert_url[256]; + char create_cert_endpoint[] = "/api/createCertificate"; + strncpy(sectigo_create_cert_url, sectigo_base_url, sizeof(sectigo_create_cert_url) - 1); + strncpy(sectigo_create_cert_url + strlen(sectigo_base_url), create_cert_endpoint, + sizeof(sectigo_create_cert_url) - 1 - strlen(sectigo_base_url)); + log_debug("Tracking ID is: %s\n", tracking_id); log_debug("Source ID is: %s\n", source); + log_debug("Sectigo URL: %s\n", sectigo_create_cert_url); if (bearer_token != NULL) { snprintf(auth_header, sizeof(auth_header), "Authorization: %s", bearer_token); @@ -235,7 +243,7 @@ const char * node_address, const char * certifier_id, char ** out_cert) json_object_set_string(root_obj, "serverPlatform", params.server_platform ? params.server_platform : ""); json_object_set_string(root_obj, "projectName", params.project_name ? params.project_name : ""); json_object_set_string(root_obj, "businessJustification", params.business_justification ? params.business_justification : ""); - json_object_set_string(root_obj, "certificateType", params.cert_type ? params.cert_type : ""); + json_object_set_string(root_obj, "certificateType", "comodo"); // Always "comodo" json_object_set_string(root_obj, "ownerPhoneNumber", params.owner_phone_number ? params.owner_phone_number : ""); json_object_set_string(root_obj, "ownerEmailAddress", params.owner_email ? params.owner_email : ""); json_object_set_string(root_obj, "certifierUrl", params.sectigo_url ? params.sectigo_url : ""); @@ -272,7 +280,7 @@ const char * node_address, const char * certifier_id, char ** out_cert) json_object_set_value(root_obj, "ipAddresses", ip_array); json_body = json_serialize_to_string(root_value); - resp = http_post(props, sectigo_url, headers, json_body); + resp = http_post(props, sectigo_create_cert_url, headers, json_body); if (resp == NULL) { goto cleanup; From 5dcf053bda2c618d44f7eed4a6c23d7a2ca96c34 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Mon, 9 Feb 2026 00:03:17 -0500 Subject: [PATCH 17/30] Remove Sectigo config defaults --- libcertifier.cfg.sample | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index 06a9401..0ad5346 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -25,23 +25,23 @@ "libcertifier.node.id":"CCCCCCCCCCCCCCCC", "libcertifier.ext.key.usage":"critical,clientAuth,serverAuth", - "libcertifier.sectigo.url": "https://certs.xpki.io/api/createCertificate", + "libcertifier.sectigo.url": "https://certs.xpki.io", "libcertifier.sectigo.auth.token": "", - "libcertifier.sectigo.common.name": "example.com", - "libcertifier.sectigo.group.name": "Example Group", - "libcertifier.sectigo.group.email": "group@example.com", - "libcertifier.sectigo.id": "user123", - "libcertifier.sectigo.owner.first.name": "First", - "libcertifier.sectigo.owner.last.name": "Last", - "libcertifier.sectigo.employee.type": "associate", - "libcertifier.sectigo.server.platform": "Other", + "libcertifier.sectigo.common.name": "", + "libcertifier.sectigo.group.name": "", + "libcertifier.sectigo.group.email": "", + "libcertifier.sectigo.id": "", + "libcertifier.sectigo.owner.first.name": "", + "libcertifier.sectigo.owner.last.name": "", + "libcertifier.sectigo.employee.type": "", + "libcertifier.sectigo.server.platform": "", "libcertifier.sectigo.sensitive": false, - "libcertifier.sectigo.project.name": "ExampleProject", - "libcertifier.sectigo.business.justification": "Testing", + "libcertifier.sectigo.project.name": "", + "libcertifier.sectigo.business.justification": "", "libcertifier.sectigo.subject.alt.names": [], "libcertifier.sectigo.ip.addresses": [], - "libcertifier.sectigo.owner.phone.number": "1234567890", - "libcertifier.sectigo.owner.email": "owner@example.com", - "libcertifier.sectigo.source": "libcertifier" + "libcertifier.sectigo.owner.phone.number": "", + "libcertifier.sectigo.owner.email": "", + "libcertifier.sectigo.source": "" } From 30897392446e06c401807b26e45d813fb6fafdda Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Mon, 9 Feb 2026 07:46:49 -0500 Subject: [PATCH 18/30] Some more renaming and name simplification --- internal_headers/certifier/sectigo_client.h | 42 ++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index 3a7f4fd..a1796cb 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -38,28 +38,28 @@ extern "C" { #define IMPULSE_URL "https://certs-dev.xpki.io/" typedef struct{ -const char * sectigo_auth_token; -const char * sectigo_common_name; -const char * sectigo_group_name; -const char * sectigo_group_email; -const char * sectigo_id; -const char * sectigo_owner_first_name; -const char * sectigo_owner_last_name; -const char * sectigo_employee_type; -const char * sectigo_server_platform; -bool sectigo_sensitive; -const char * sectigo_project_name; -const char * sectigo_business_justification; -const char * sectigo_subject_alt_names; -const char * sectigo_ip_addresses; -const char * sectigo_owner_phone_number; -const char * sectigo_owner_email; -const char * sectigo_cert_type; +const char * auth_token; +const char * common_name; +const char * group_name; +const char * group_email; +const char * id; +const char * owner_first_name; +const char * owner_last_name; +const char * employee_type; +const char * server_platform; +bool sensitive; +const char * project_name; +const char * business_justification; +const char * subject_alt_names; +const char * ip_addresses; +const char * owner_phone_number; +const char * owner_email; +const char * cert_type; const char * sectigo_url; -const char * sectigo_source; +const char * source; -} get_cert_sectigo_param_t; +} sectigo_get_cert_param_t; typedef enum{ @@ -83,9 +83,9 @@ CertifierError sectigo_generate_certificate_signing_request(Certifier *certifier Certifier * get_sectigo_certifier_instance(); -SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(get_cert_sectigo_param_t * params); +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params); -SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(get_cert_sectigo_param_t * params); +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_param_t * params); #ifdef __cplusplus } From fc37cca31272295073a3eb2d6ae3b5f61e59bcfa Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Mon, 9 Feb 2026 09:21:10 -0500 Subject: [PATCH 19/30] Additional log filtering --- src/property.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/property.c b/src/property.c index 139aae4..b6ee4d5 100644 --- a/src/property.c +++ b/src/property.c @@ -1420,7 +1420,9 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object if (!csv) { csv = XSTRDUP(""); // Always set to empty string if missing/empty } - log_info("Loaded sectigo subject alt names: %s from config file.", csv); + if (strlen(csv) > 0) { + log_info("Loaded sectigo subject alt names: %s from config file.", csv); + } sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, csv); XFREE(csv); continue; @@ -1433,7 +1435,9 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object } else { csv = XSTRDUP(""); } - log_info("Loaded sectigo IP addresses: %s from config file.", csv); + if (strlen(csv) > 0) { + log_info("Loaded sectigo IP addresses: %s from config file.", csv); + } sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, csv); XFREE(csv); continue; From 374f8ce181437b0cf8f1c9d5bd033763a3c0841d Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Mon, 9 Feb 2026 14:39:31 -0500 Subject: [PATCH 20/30] Removing deprecated parameters according to updated Sectigo API specification --- docs/cli_usage.adoc | 76 +-------------- docs/configuration.adoc | 7 -- include/certifier/property.h | 7 -- internal_headers/certifier/sectigo_client.h | 7 -- libcertifier.cfg.sample | 9 +- src/certifier_api_easy.c | 55 +---------- src/main.c | 55 ----------- src/property.c | 101 +------------------- src/sectigo_client.c | 79 +-------------- tests/xc_apis/xc_api_tests.c | 9 +- 10 files changed, 14 insertions(+), 391 deletions(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index 05f0a4e..04fbee2 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -113,8 +113,8 @@ Same command with SAT authentication: The certificate can be downloaded through the certificate ID returned as a result of running the command. ---- -./certifierUtil sectigo-get-cert -C -I -e [fte/associate/contractor] -s -N -r -b -A -x -G -E -O -J --Z -U -T -K -u -l -W -Y +./certifierUtil sectigo-get-cert -C -I -r -b -A -G -E -O -J +-Z -K -u -l ---- == *certifierUtil commands* @@ -535,24 +535,6 @@ Disabled by default - Only error messages are shown. -I | User or device ID -| employee-type -| e -| --employee-type + --e -| Employee type - -| server-platform -| s -| --server-platform + --s -| Server platform - -| sensitive -| N -| --sensitive + --N -| Mark as sensitive - | project-name | r | --project-name + @@ -571,12 +553,6 @@ Disabled by default - Only error messages are shown. -A | Subject alternative names (CSV) -| ip-addresses -| x -| --ip-addresses + --x -| IP addresses (CSV) - | group-name | G | --group-name + @@ -589,13 +565,13 @@ Disabled by default - Only error messages are shown. -E | Group email -| owner-fname +| owner-first-name | O -| --owner-fname + +| --owner-first-name + -O | Owner first name -| owner-lname +| owner-last-name | J | --owner-lname + -J @@ -607,12 +583,6 @@ Disabled by default - Only error messages are shown. -Z | Owner email -| owner-phonenum -| U -| --owner-phonenum + --U -| Owner phone number - | cert-type | T | --cert-type + @@ -785,24 +755,6 @@ Note: value type = `bool` | "Last" | Owner's last name -| libcertifier.sectigo.employee.type -| "associate" -| Employee type (e.g., associate, employee, contractor) - -| libcertifier.sectigo.server.platform -| "Other" -| Server platform name. + -Note: Use any of the following options: Tomcat, Redhat Linux, Microsoft IIS 5.x and later, Apache/MODSSL, IBM HTTP server, Java Web Server (Javasoft/SUN), Oracle, SAP Web Application Server, Citrix, Other - -| libcertifier.sectigo.sensitive -| false -| Mark certificate as sensitive. + -Note: value type = `bool` - -| libcertifier.sectigo.project.name -| "ExampleProject" -| Project name - | libcertifier.sectigo.business.justification | "Testing" | Business justification for the request @@ -812,20 +764,6 @@ Note: value type = `bool` | Subject alternative names. + Note: value type = `array of strings` Pass empty array if you don't have. -| libcertifier.sectigo.ip.addresses -| [] -| IP addresses. + -Note: value type = `array of strings` Pass empty array if you don't have. - -| libcertifier.sectigo.cert.type -| "comodo" -| Certificate type. + -Note: Always pass comodo for internet-facing apps - -| libcertifier.sectigo.owner.phone.number -| "1234567890" -| Owner's phone number - | libcertifier.sectigo.owner.email | "owner@example.com" | Owner's email address @@ -834,8 +772,4 @@ Note: Always pass comodo for internet-facing apps | "1234" | Tracking ID for the request -| libcertifier.sectigo.source -| "libcertifier" -| Source identifier for the request - |=== diff --git a/docs/configuration.adoc b/docs/configuration.adoc index 2d5fd66..07191bc 100644 --- a/docs/configuration.adoc +++ b/docs/configuration.adoc @@ -39,17 +39,10 @@ xref:libcertifier.adoc[*Back to Manual*] | libcertifier.sectigo.id | user123 | | libcertifier.sectigo.owner.first.name | First | | libcertifier.sectigo.owner.last.name | Last | -| libcertifier.sectigo.employee.type | associate | -| libcertifier.sectigo.server.platform | Other | -| libcertifier.sectigo.sensitive | false | | libcertifier.sectigo.project.name | ExampleProject | | libcertifier.sectigo.business.justification | Testing | | libcertifier.sectigo.subject.alt.names | [] | -| libcertifier.sectigo.ip.addresses | [] | -| libcertifier.sectigo.cert.type | comodo | -| libcertifier.sectigo.owner.phone.number | 1234567890 | | libcertifier.sectigo.owner.email | owner@example.com | -| libcertifier.sectigo.source | libcertifier | |======= == Extended Key Usage values: diff --git a/include/certifier/property.h b/include/certifier/property.h index 97c59ff..408ebfd 100644 --- a/include/certifier/property.h +++ b/include/certifier/property.h @@ -210,17 +210,10 @@ typedef enum CERTIFIER_OPT CERTIFIER_OPT_SECTIGO_ID, CERTIFIER_OPT_SECTIGO_OWNER_FIRST_NAME, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, - CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, - CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, - CERTIFIER_OPT_SECTIGO_SENSITIVE, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, - CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, - CERTIFIER_OPT_SECTIGO_CERT_TYPE, - CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, - CERTIFIER_OPT_SECTIGO_SOURCE, CERTIFIER_OPT_SECTIGO_URL, } CERTIFIER_OPT; diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index a1796cb..6dbf8f9 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -45,18 +45,11 @@ const char * group_email; const char * id; const char * owner_first_name; const char * owner_last_name; -const char * employee_type; -const char * server_platform; -bool sensitive; const char * project_name; const char * business_justification; const char * subject_alt_names; -const char * ip_addresses; -const char * owner_phone_number; const char * owner_email; -const char * cert_type; const char * sectigo_url; -const char * source; } sectigo_get_cert_param_t; diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index 0ad5346..fa2af6e 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -33,15 +33,8 @@ "libcertifier.sectigo.id": "", "libcertifier.sectigo.owner.first.name": "", "libcertifier.sectigo.owner.last.name": "", - "libcertifier.sectigo.employee.type": "", - "libcertifier.sectigo.server.platform": "", - "libcertifier.sectigo.sensitive": false, "libcertifier.sectigo.project.name": "", "libcertifier.sectigo.business.justification": "", "libcertifier.sectigo.subject.alt.names": [], - "libcertifier.sectigo.ip.addresses": [], - "libcertifier.sectigo.owner.phone.number": "", - "libcertifier.sectigo.owner.email": "", - "libcertifier.sectigo.source": "" - + "libcertifier.sectigo.owner.email": "" } diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index d897717..a7a33fc 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -95,13 +95,9 @@ #define SECTIGO_GET_CERT_LONG_OPTIONS \ { "common-name", required_argument, NULL, 'C' }, \ { "id", required_argument, NULL, 'I' }, \ - { "employee-type", required_argument, NULL, 'e' }, \ - { "server-platform", required_argument, NULL, 's' }, \ - { "sensitive", no_argument, NULL, 'N' }, \ { "project-name", required_argument, NULL, 'r' }, \ { "business-justification", required_argument, NULL, 'b' }, \ { "subject-alt-names", required_argument, NULL, 'A' }, \ - { "ip-addresses", required_argument, NULL, 'x' }, \ {"url", required_argument, NULL, 'u'}, \ { "auth-token", required_argument, NULL, 'K' }, \ { "group-name", required_argument, NULL, 'G' }, \ @@ -109,10 +105,7 @@ { "owner-first-name", required_argument, NULL, 'O' }, \ { "owner-last-name", required_argument, NULL, 'J' }, \ { "owner-email", required_argument, NULL, 'Z' }, \ - { "owner-phone-number", required_argument, NULL, 'U' }, \ - { "cert-type", required_argument, NULL, 'T' }, \ { "config", required_argument, NULL, 'l' }, \ - { "tracking-id", required_argument, NULL, 'W' }, \ { NULL, 0, NULL, 0 } //make default arg '*' for san and ip //only take in choices=['fte', 'contractor', 'associate'] @@ -775,16 +768,13 @@ static int do_sectigo_get_cert(CERTIFIER * easy) // Check for required Sectigo properties const char *common_name = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); - const char *employee_type = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE); - const char *server_platform = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM); const char *project_name = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME); const char *business_justification = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION); - if (util_is_empty(common_name) || util_is_empty(employee_type) || - util_is_empty(server_platform) || util_is_empty(project_name) || - util_is_empty(business_justification)) { + if (util_is_empty(common_name) || util_is_empty(business_justification) || util_is_empty(project_name)) { + finish_operation(easy, CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1, - "Missing required Sectigo flags (common-name, employee-type, server-platform, project-name, business-justification)"); + "Missing required Sectigo flags (common-name, project-name, business-justification)"); return CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; } @@ -1164,26 +1154,6 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_ID, optarg); } break; - case 'e': // employee-type - if (optarg) { - // Validate allowed values: "fte", "contractor", "associate" - if (strcmp(optarg, "fte") && strcmp(optarg, "contractor") && strcmp(optarg, "associate")) { - log_error("Invalid employee-type: %s. Allowed: fte, contractor, associate.", optarg); - return_code = 1; - break; - } - - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, optarg); - } - break; - case 's': // server-platform - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, optarg); - } - break; - case 'N': // sensitive - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE, (void *)true); - break; case 'r': // project-name if (optarg) { return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, optarg); @@ -1199,11 +1169,6 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, optarg); } break; - case 'x': // ip-addresses - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, optarg); - } - break; case 'K': // auth-token if (optarg) { return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, optarg); @@ -1238,20 +1203,6 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, optarg); } break; - case 'Z': // owner-phone-number - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, optarg); - } - break; - case 'U': // cert-type - if (optarg) { - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERT_TYPE, optarg); - } - break; - case 'Y': //source - if (optarg){ - return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SOURCE, optarg); - } case '?': /* Case when user enters the command as * $ ./libCertifier -p diff --git a/src/main.c b/src/main.c index d4171b9..4b98eac 100644 --- a/src/main.c +++ b/src/main.c @@ -219,13 +219,9 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_print_helper(SECTIGO_MODE mode) #define SECTIGO_GET_CERT_LONG_OPTIONS \ { "common-name", required_argument, NULL, 'C' }, \ { "id", required_argument, NULL, 'I' }, \ - { "employee-type", required_argument, NULL, 'e' }, \ - { "server-platform", required_argument, NULL, 's' }, \ - { "sensitive", no_argument, NULL, 'N' }, \ { "project-name", required_argument, NULL, 'r' }, \ { "business-justification", required_argument, NULL, 'b' }, \ { "subject-alt-names", required_argument, NULL, 'A' }, \ - { "ip-addresses", required_argument, NULL, 'x' }, \ {"url", required_argument, NULL, 'u'}, \ { "auth-token", required_argument, NULL, 'K' }, \ { "group-name", required_argument, NULL, 'G' }, \ @@ -233,11 +229,7 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_print_helper(SECTIGO_MODE mode) { "owner-first-name", required_argument, NULL, 'O' }, \ { "owner-last-name", required_argument, NULL, 'J' }, \ { "owner-email", required_argument, NULL, 'Z' }, \ - { "owner-phone-number", required_argument, NULL, 'U' }, \ - { "cert-type", required_argument, NULL, 'T' }, \ { "config", required_argument, NULL, 'l' }, \ - { "tracking-id", required_argument, NULL, 'W' }, \ - {"source", required_argument, NULL, 'Y'} \ { NULL, 0, NULL, 0 } \ //make default arg '*' for san and ip //only take in choices=['fte', 'contractor', 'associate'] @@ -277,24 +269,17 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) #define SECTIGO_GET_CERT_HELPER \ "--common-name [value] (-C)\n" \ "--id [value] (-I)\n" \ - "--employee-type [value] (-e)\n" \ - "--server-platform [value] (-s)\n" \ - "--sensitive (-N)\n" \ "--project-name [value] (-r)\n" \ "--business-justification [value] (-b)\n" \ "--subject-alt-names [value] (-A)\n" \ - "--ip-addresses [value] (-x)\n" \ "--group-name [value] (-G)\n" \ "--group-email [value] (-E)\n" \ "--owner-first-name [value] (-O)\n" \ "--owner-last-name [value] (-J)\n" \ "--owner-email [value] (-Z)\n" \ - "--owner-phone-number [value] (-U)\n" \ - "--cert-type [value] (-T)\n" \ "--auth-token [value] (-K)\n" \ "--url [value] (-u)\n" \ "--config [value] (-l)\n" \ - "--source [value] (-Y)\n" switch (mode) { @@ -592,13 +577,9 @@ static const char * const sectigo_get_cert_short_options = "C:I:e:s:N:r:b:A:x:K: static const struct option sectigo_get_cert_long_opts[] = { { "common-name", required_argument, NULL, 'C' }, { "id", required_argument, NULL, 'I' }, - { "employee-type", required_argument, NULL, 'e' }, - { "server-platform", required_argument, NULL, 's' }, - { "sensitive", no_argument, NULL, 'N' }, { "project-name", required_argument, NULL, 'r' }, { "business-justification", required_argument, NULL, 'b' }, { "subject-alt-names", required_argument, NULL, 'A' }, - { "ip-addresses", required_argument, NULL, 'x' }, { "url", required_argument, NULL, 'u'}, { "auth-token", required_argument, NULL, 'K' }, { "group-name", required_argument, NULL, 'G' }, @@ -606,11 +587,7 @@ static const struct option sectigo_get_cert_long_opts[] = { { "owner-first-name", required_argument, NULL, 'O' }, { "owner-last-name", required_argument, NULL, 'J' }, { "owner-email", required_argument, NULL, 'Z' }, - { "owner-phone-number", required_argument, NULL, 'U' }, - { "cert-type", required_argument, NULL, 'T' }, { "config", required_argument, NULL, 'l' }, - { "tracking-id", required_argument, NULL, 'W' }, - { "source", required_argument, NULL, 'Y'}, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } //make default arg '*' for san and ip @@ -657,22 +634,6 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t sectigo_parameter->get_cert_param.id = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_ID, optarg); break; - case 'e': - sectigo_parameter->get_cert_param.employee_type = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, optarg); - break; - case 's': - sectigo_parameter->get_cert_param.server_platform = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, optarg); - break; - case 'N': - sectigo_parameter->get_cert_param.sensitive = true; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SENSITIVE, optarg); - break; - case 'r': - sectigo_parameter->get_cert_param.project_name = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_PROJECT_NAME, optarg); - break; case 'b': sectigo_parameter->get_cert_param.business_justification = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, optarg); @@ -681,10 +642,6 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t sectigo_parameter->get_cert_param.subject_alt_names = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, optarg); break; - case 'x': - sectigo_parameter->get_cert_param.ip_addresses = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, optarg); - break; case 'l': // config file path, handled in sectigo_perform break; @@ -708,14 +665,6 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t sectigo_parameter->get_cert_param.owner_email = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, optarg); break; - case 'U': - sectigo_parameter->get_cert_param.owner_phone_number = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, optarg); - break; - case 'T': - sectigo_parameter->get_cert_param.cert_type = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERT_TYPE, optarg); - break; case 'K': sectigo_parameter->get_cert_param.auth_token = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_AUTH_TOKEN, optarg); @@ -724,10 +673,6 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t sectigo_parameter->get_cert_param.sectigo_url = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_URL, optarg); break; - case 'Y': - sectigo_parameter->get_cert_param.source = optarg; - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SOURCE, optarg); - break; case '?': log_info("Invalid or missing Sectigo option"); error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; diff --git a/src/property.c b/src/property.c index b6ee4d5..b1a3a7c 100644 --- a/src/property.c +++ b/src/property.c @@ -209,16 +209,10 @@ struct _PropMap char * id; char * owner_first_name; char * owner_last_name; - char * employee_type; - char * server_platform; - bool sensitive; char * project_name; char * business_justification; char * subject_alt_names; - char * ip_addresses; - char * owner_phone_number; char * owner_email; - char * cert_type; char * sectigo_url; }; @@ -389,15 +383,6 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME: prop_map->owner_last_name = XSTRDUP((const char *)value); break; - case CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE: - prop_map->employee_type = XSTRDUP((const char *)value); - break; - case CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM: - prop_map->server_platform = XSTRDUP((const char *)value); - break; - case CERTIFIER_OPT_SECTIGO_SENSITIVE: - prop_map->sensitive = (bool)(size_t)value; - break; case CERTIFIER_OPT_SECTIGO_PROJECT_NAME: prop_map->project_name = XSTRDUP((const char *)value); break; @@ -407,21 +392,9 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES: prop_map->subject_alt_names = XSTRDUP((const char *)value); break; - case CERTIFIER_OPT_SECTIGO_IP_ADDRESSES: - prop_map->ip_addresses = XSTRDUP((const char *)value); - break; - case CERTIFIER_OPT_SECTIGO_CERT_TYPE: - prop_map->cert_type = XSTRDUP((const char *)value); - break; - case CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER: - prop_map->owner_phone_number = XSTRDUP((const char *)value); - break; case CERTIFIER_OPT_SECTIGO_OWNER_EMAIL: prop_map->owner_email = XSTRDUP((const char *)value); break; - case CERTIFIER_OPT_SECTIGO_SOURCE: - prop_map->source = XSTRDUP((const char *)value); - break; case CERTIFIER_OPT_SECTIGO_URL: prop_map->sectigo_url = XSTRDUP((const char *)value); break; @@ -913,39 +886,18 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) case CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME: retval = (void *) prop_map->owner_last_name; break; - case CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE: - retval = (void *) prop_map->employee_type; - break; - case CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM: - retval = (void *) prop_map->server_platform; - break; - case CERTIFIER_OPT_SECTIGO_SENSITIVE: - retval = (void *)(size_t) prop_map->sensitive; - break; case CERTIFIER_OPT_SECTIGO_PROJECT_NAME: retval = (void *) prop_map->project_name; break; - case CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION: + case CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION: retval = (void *) prop_map->business_justification; break; case CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES: retval = (void *) prop_map->subject_alt_names; break; - case CERTIFIER_OPT_SECTIGO_IP_ADDRESSES: - retval = (void *) prop_map->ip_addresses; - break; - case CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER: - retval = (void *) prop_map->owner_phone_number; - break; case CERTIFIER_OPT_SECTIGO_OWNER_EMAIL: retval = (void *) prop_map->owner_email; break; - case CERTIFIER_OPT_SECTIGO_CERT_TYPE: - retval = (void *) prop_map->cert_type; - break; - case CERTIFIER_OPT_SECTIGO_SOURCE: - retval = (void *) prop_map->source; - break; case CERTIFIER_OPT_SECTIGO_URL: retval = (void *) prop_map->sectigo_url; break; @@ -1400,16 +1352,6 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object continue; } - // Special handling for boolean keys - if (strcmp(key, "libcertifier.sectigo.sensitive") == 0) { - int bool_value = json_object_get_boolean(root, key); - if (bool_value != -1) { // -1 indicates not a boolean - log_info("Loaded sectigo sensitive: %s from config file.", bool_value ? "true" : "false"); - propMap->sensitive = (bool)bool_value; - } - continue; - } - // Special handling for array keys if (strcmp(key, "libcertifier.sectigo.subject.alt.names") == 0) { const char *array_str = json_object_get_string(root, key); @@ -1427,21 +1369,6 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object XFREE(csv); continue; } - if (strcmp(key, "libcertifier.sectigo.ip.addresses") == 0) { - const char *array_str = json_object_get_string(root, key); - char *csv = NULL; - if (array_str) { - csv = simple_json_array_to_csv(array_str); - } else { - csv = XSTRDUP(""); - } - if (strlen(csv) > 0) { - log_info("Loaded sectigo IP addresses: %s from config file.", csv); - } - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES, csv); - XFREE(csv); - continue; - } const char *value_str = json_object_get_string(root, key); if (value_str && strlen(value_str) > 0) { // Only process non-empty values @@ -1474,14 +1401,6 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object log_info("Loaded sectigo owner last name: %s from config file.", value_str); sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME, value_str); } - else if (strcmp(key, "libcertifier.sectigo.employee.type") == 0) { - log_info("Loaded sectigo employee type: %s from config file.", value_str); - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE, value_str); - } - else if (strcmp(key, "libcertifier.sectigo.server.platform") == 0) { - log_info("Loaded sectigo server platform: %s from config file.", value_str); - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM, value_str); - } else if (strcmp(key, "libcertifier.sectigo.project.name") == 0) { log_info("Loaded sectigo project name: %s from config file.", value_str); sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_PROJECT_NAME, value_str); @@ -1490,26 +1409,14 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object log_info("Loaded sectigo business justification: %s from config file.", value_str); sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_BUSINESS_JUSTIFICATION, value_str); } - else if (strcmp(key, "libcertifier.sectigo.owner.phone.number") == 0) { - log_info("Loaded sectigo owner phone number: %s from config file.", value_str); - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER, value_str); - } else if (strcmp(key, "libcertifier.sectigo.owner.email") == 0) { log_info("Loaded sectigo owner email: %s from config file.", value_str); sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, value_str); } - else if (strcmp(key, "libcertifier.sectigo.cert.type") == 0) { - log_info("Loaded sectigo cert type: %s from config file.", value_str); - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERT_TYPE, value_str); - } else if (strcmp(key, "libcertifier.sectigo.url") == 0) { log_info("Loaded sectigo URL: %s from config file.", value_str); sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_URL, value_str); } - else if (strcmp(key, "libcertifier.sectigo.source") == 0) { - log_info("Loaded sectigo source: %s from config file.", value_str); - sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SOURCE, value_str); - } // Add more mappings as needed } } @@ -1686,16 +1593,10 @@ static void free_prop_map_values(CertifierPropMap * prop_map) FV(prop_map->id); FV(prop_map->owner_first_name); FV(prop_map->owner_last_name); - FV(prop_map->employee_type); - FV(prop_map->server_platform); FV(prop_map->project_name); FV(prop_map->business_justification); FV(prop_map->subject_alt_names); - FV(prop_map->ip_addresses); - FV(prop_map->owner_phone_number); FV(prop_map->owner_email); - FV(prop_map->cert_type); - FV(prop_map->source); FV(prop_map->sectigo_url); } diff --git a/src/sectigo_client.c b/src/sectigo_client.c index f4ef54e..6339012 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -82,12 +82,6 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_par param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_LAST_NAME); params->owner_last_name = param ? XSTRDUP((const char *)param) : NULL; - param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_EMPLOYEE_TYPE); - params->employee_type = param ? XSTRDUP((const char *)param) : NULL; - - param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SERVER_PLATFORM); - params->server_platform = param ? XSTRDUP((const char *)param) : NULL; - param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_PROJECT_NAME); params->project_name = param ? XSTRDUP((const char *)param) : NULL; @@ -97,24 +91,12 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_par param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES); params->subject_alt_names = param ? XSTRDUP((const char *)param) : NULL; - param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_IP_ADDRESSES); - params->ip_addresses = param ? XSTRDUP((const char *)param) : NULL; - - param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERT_TYPE); - params->cert_type = param ? XSTRDUP((const char *)param) : NULL; - - param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_PHONE_NUMBER); - params->owner_phone_number = param ? XSTRDUP((const char *)param) : NULL; - param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL); params->owner_email = param ? XSTRDUP((const char *)param) : NULL; param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_URL); params->sectigo_url = param ? XSTRDUP((const char *)param) : NULL; - param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SENSITIVE); - params->sensitive = param ? *((bool *)param) : false; - return SECTIGO_CLIENT_SUCCESS; } @@ -143,7 +125,7 @@ const char * node_address, const char * certifier_id, char ** out_cert) http_response * resp = NULL; const char * tracking_id = property_get(props, CERTIFIER_OPT_TRACKING_ID); const char * bearer_token = property_get(props, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); - const char * source = property_get(props, CERTIFIER_OPT_SECTIGO_SOURCE); + const char * source = "libcertifier"; const char * sectigo_base_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); if (!bearer_token) { @@ -158,12 +140,6 @@ const char * node_address, const char * certifier_id, char ** out_cert) rc.application_error_msg = util_format_error_here("Sectigo base URL is missing"); goto cleanup; } - if (!source) { - log_error("Missing CERTIFIER_OPT_SECTIGO_SOURCE"); - rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; - rc.application_error_msg = util_format_error_here("Source is missing"); - goto cleanup; - } // Build full URL: base + endpoint char sectigo_create_cert_url[256]; @@ -173,7 +149,6 @@ const char * node_address, const char * certifier_id, char ** out_cert) sizeof(sectigo_create_cert_url) - 1 - strlen(sectigo_base_url)); log_debug("Tracking ID is: %s\n", tracking_id); - log_debug("Source ID is: %s\n", source); log_debug("Sectigo URL: %s\n", sectigo_create_cert_url); if (bearer_token != NULL) { @@ -194,13 +169,6 @@ const char * node_address, const char * certifier_id, char ** out_cert) NULL }; - if (util_is_empty(source)) - { - rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; - rc.application_error_msg = util_format_error_here("CERTIFIER_OPT_SECTIGO_SOURCE must be set to a non-empty string!"); - goto cleanup; - } - CertifierError csr_rc = sectigo_generate_certificate_signing_request(certifier, &serialized_string); if (csr_rc.application_error_code != 0 || serialized_string == NULL) { @@ -239,15 +207,10 @@ const char * node_address, const char * certifier_id, char ** out_cert) json_object_set_string(root_obj, "id", params.id ? params.id : ""); json_object_set_string(root_obj, "ownerFirstName", params.owner_first_name ? params.owner_first_name : ""); json_object_set_string(root_obj, "ownerLastName", params.owner_last_name ? params.owner_last_name : ""); - json_object_set_string(root_obj, "employeeType", params.employee_type ? params.employee_type : ""); - json_object_set_string(root_obj, "serverPlatform", params.server_platform ? params.server_platform : ""); json_object_set_string(root_obj, "projectName", params.project_name ? params.project_name : ""); json_object_set_string(root_obj, "businessJustification", params.business_justification ? params.business_justification : ""); json_object_set_string(root_obj, "certificateType", "comodo"); // Always "comodo" - json_object_set_string(root_obj, "ownerPhoneNumber", params.owner_phone_number ? params.owner_phone_number : ""); json_object_set_string(root_obj, "ownerEmailAddress", params.owner_email ? params.owner_email : ""); - json_object_set_string(root_obj, "certifierUrl", params.sectigo_url ? params.sectigo_url : ""); - json_object_set_value(root_obj, "sensitive", json_value_init_boolean(params.sensitive)); // Always set subjectAltNames and ipAddresses, even if empty // subjectAltNames as array @@ -264,20 +227,6 @@ const char * node_address, const char * certifier_id, char ** out_cert) } json_object_set_value(root_obj, "subjectAltNames", san_array); - // ipAddresses as array - JSON_Value *ip_array = json_value_init_array(); - JSON_Array *ip_json_array = json_value_get_array(ip_array); - if (params.ip_addresses && strlen(params.ip_addresses) > 0) { - char *ip_copy = XSTRDUP(params.ip_addresses); - char *token = strtok(ip_copy, ","); - while (token) { - json_array_append_value(ip_json_array, json_value_init_string(token)); - token = strtok(NULL, ","); - } - XFREE(ip_copy); - } - - json_object_set_value(root_obj, "ipAddresses", ip_array); json_body = json_serialize_to_string(root_value); resp = http_post(props, sectigo_create_cert_url, headers, json_body); @@ -355,10 +304,6 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params) json_object_set_string(root_obj, "ownerFirstName", params->owner_first_name); if (params->owner_last_name) json_object_set_string(root_obj, "ownerLastName", params->owner_last_name); - if (params->employee_type) - json_object_set_string(root_obj, "employeeType", params->employee_type); - if (params->server_platform) - json_object_set_string(root_obj, "serverPlatform", params->server_platform); if (params->project_name) json_object_set_string(root_obj, "projectName", params->project_name); if (params->business_justification) @@ -378,28 +323,10 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params) } json_object_set_value(root_obj, "subjectAltNames", san_array); - // ipAddresses as array - JSON_Value *ip_array = json_value_init_array(); - JSON_Array *ip_json_array = json_value_get_array(ip_array); - if (params->ip_addresses && strlen(params->ip_addresses) > 0) { - char *ip_copy = XSTRDUP(params->ip_addresses); - char *token = strtok(ip_copy, ","); - while (token) { - json_array_append_value(ip_json_array, json_value_init_string(token)); - token = strtok(NULL, ","); - } - XFREE(ip_copy); - } - json_object_set_value(root_obj, "ipAddresses", ip_array); - - if (params->cert_type) - json_object_set_string(root_obj, "certificateType", params->cert_type); - if (params->owner_phone_number) - json_object_set_string(root_obj, "ownerPhoneNumber", params->owner_phone_number); + json_object_set_string(root_obj, "certificateType", "comodo"); // Always "comodo" + if (params->owner_email) json_object_set_string(root_obj, "ownerEmailAddress", params->owner_email); - if (params->sectigo_url) - json_object_set_string(root_obj, "certifierUrl", params->sectigo_url); // Generate CSR and add to body char *csr_pem = NULL; diff --git a/tests/xc_apis/xc_api_tests.c b/tests/xc_apis/xc_api_tests.c index fc988e5..3e0f889 100644 --- a/tests/xc_apis/xc_api_tests.c +++ b/tests/xc_apis/xc_api_tests.c @@ -250,18 +250,11 @@ static void test_get_sectigo_cert() params.id = "exid"; params.owner_first_name = "First"; params.owner_last_name = "Last"; - params.employee_type = "associate"; - params.server_platform = "other"; - params.sensitive = "false"; params.project_name = "Testing create with SAT"; params.business_justification = "Testing create with SAT"; params.subject_alt_names = "*"; - params.ip_addresses = "*"; - params.cert_type = "comodo"; - params.owner_phone_number = "2670000000"; params.owner_email = "first_last@comcast.com"; - params.sectigo_url = "https://certs-dev.xpki.io/api/createCertificate"; - params.source = "libcertifier"; + params.sectigo_url = "https://certs-dev.xpki.io/api/createCertificate"; // Call the API error = xc_sectigo_get_cert(¶ms); From 1db43f0263dcad93218e4ab1390daff19024a7e6 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Mon, 9 Feb 2026 16:09:45 -0500 Subject: [PATCH 21/30] Add new parameters according to updated Sectigo API specification --- include/certifier/property.h | 3 + .../certifier/property_internal.h | 7 ++ internal_headers/certifier/sectigo_client.h | 29 +++++---- libcertifier.cfg.sample | 5 +- src/certifier_api_easy.c | 26 ++++++++ src/main.c | 20 +++++- src/property.c | 64 ++++++++++++++++++- src/sectigo_client.c | 20 +++++- tests/xc_apis/xc_api_tests.c | 3 + 9 files changed, 158 insertions(+), 19 deletions(-) diff --git a/include/certifier/property.h b/include/certifier/property.h index 408ebfd..e4e9b10 100644 --- a/include/certifier/property.h +++ b/include/certifier/property.h @@ -215,6 +215,9 @@ typedef enum CERTIFIER_OPT CERTIFIER_OPT_SECTIGO_SUBJECT_ALT_NAMES, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, CERTIFIER_OPT_SECTIGO_URL, + CERTIFIER_OPT_SECTIGO_DEVHUB_ID, + CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS, + CERTIFIER_OPT_SECTIGO_KEY_TYPE, } CERTIFIER_OPT; diff --git a/internal_headers/certifier/property_internal.h b/internal_headers/certifier/property_internal.h index 38a0669..d220e28 100644 --- a/internal_headers/certifier/property_internal.h +++ b/internal_headers/certifier/property_internal.h @@ -94,6 +94,13 @@ const char * get_default_ca_path(); const char * get_default_ca_info(); +/** + * Validate if a key type string is a supported Sectigo key type. + * @param key_type The key type string to validate + * @return 1 if valid, 0 otherwise + */ +int is_valid_sectigo_key_type(const char * key_type); + #ifdef __cplusplus } #endif diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index 6dbf8f9..b116781 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -38,20 +38,21 @@ extern "C" { #define IMPULSE_URL "https://certs-dev.xpki.io/" typedef struct{ -const char * auth_token; -const char * common_name; -const char * group_name; -const char * group_email; -const char * id; -const char * owner_first_name; -const char * owner_last_name; -const char * project_name; -const char * business_justification; -const char * subject_alt_names; -const char * owner_email; -const char * sectigo_url; - - + const char * auth_token; + const char * common_name; + const char * group_name; + const char * group_email; + const char * id; + const char * owner_first_name; + const char * owner_last_name; + const char * project_name; + const char * business_justification; + const char * subject_alt_names; + const char * owner_email; + const char * sectigo_url; + const char * devhub_id; + size_t validity_days; + const char * key_type; } sectigo_get_cert_param_t; diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index fa2af6e..dd80ad6 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -33,8 +33,11 @@ "libcertifier.sectigo.id": "", "libcertifier.sectigo.owner.first.name": "", "libcertifier.sectigo.owner.last.name": "", + "libcertifier.sectigo.owner.email": "", "libcertifier.sectigo.project.name": "", "libcertifier.sectigo.business.justification": "", "libcertifier.sectigo.subject.alt.names": [], - "libcertifier.sectigo.owner.email": "" + "libcertifier.sectigo.devhub.id": "", + "libcertifier.sectigo.validity.days": 365, + "libcertifier.sectigo.key.type": "" } diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index a7a33fc..851960d 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -27,6 +27,7 @@ #include "certifier/types.h" #include "certifier/util.h" #include "certifier/sectigo_client.h" +#include "certifier/property_internal.h" #include #include @@ -1203,6 +1204,31 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_OWNER_EMAIL, optarg); } break; + case 'D': // DevHub ID + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_DEVHUB_ID, optarg); + } + break; + case 'V': // Validity Days for Sectigo cert + if (optarg) { + if (atoi(optarg) > 0) + { + return_code = + certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS, (const void *) (size_t) atoi(optarg)); + } + else + { + log_error("Expected input to be of positive integer type"); + return_code = 1; + } + } + break; + case 'W': // Key Type + if (!is_valid_sectigo_key_type(optarg)) { + log_error("Invalid key type. Supported key types: [RSA-2048, RSA-3072, RSA-4096, RSA-8192, ECC-PRIME256V1, ECC-SECP384R1]"); + exit(0); + } + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_KEY_TYPE, optarg); case '?': /* Case when user enters the command as * $ ./libCertifier -p diff --git a/src/main.c b/src/main.c index 4b98eac..1a535d7 100644 --- a/src/main.c +++ b/src/main.c @@ -277,6 +277,9 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) "--owner-first-name [value] (-O)\n" \ "--owner-last-name [value] (-J)\n" \ "--owner-email [value] (-Z)\n" \ + "--devhub-id [value] (-D)\n" \ + "--validity-days [value] (-V)\n" \ + "--key-type [value] (-W)\n" \ "--auth-token [value] (-K)\n" \ "--url [value] (-u)\n" \ "--config [value] (-l)\n" \ @@ -573,7 +576,7 @@ XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, in } // --- Sectigo Option Table --- -static const char * const sectigo_get_cert_short_options = "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:Y:h"; +static const char * const sectigo_get_cert_short_options = "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:V:D:h"; static const struct option sectigo_get_cert_long_opts[] = { { "common-name", required_argument, NULL, 'C' }, { "id", required_argument, NULL, 'I' }, @@ -587,6 +590,9 @@ static const struct option sectigo_get_cert_long_opts[] = { { "owner-first-name", required_argument, NULL, 'O' }, { "owner-last-name", required_argument, NULL, 'J' }, { "owner-email", required_argument, NULL, 'Z' }, + { "devhub-id", required_argument, NULL, 'D' }, + { "validity-days", required_argument, NULL, 'V' }, + { "key-type", required_argument, NULL, 'W' }, { "config", required_argument, NULL, 'l' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } @@ -673,6 +679,18 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t sectigo_parameter->get_cert_param.sectigo_url = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_URL, optarg); break; + case 'D': + sectigo_parameter->get_cert_param.devhub_id = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_DEVHUB_ID, optarg); + break; + case 'V': + sectigo_parameter->get_cert_param.validity_days = atol(optarg); + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS, optarg); + break; + case 'W': + sectigo_parameter->get_cert_param.key_type = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_KEY_TYPE, optarg); + break; case '?': log_info("Invalid or missing Sectigo option"); error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; diff --git a/src/property.c b/src/property.c index b1a3a7c..0ffe906 100644 --- a/src/property.c +++ b/src/property.c @@ -36,6 +36,27 @@ #define DEFAULT_OUTPUT_P12_PATH "output.p12" #define DEFAULT_CFG_FILENAME "libcertifier.cfg" #define DEFAULT_USER_CFG_FILENAME "/usr/local/etc/certifier/libcertifier.cfg" + +// Helper function to validate Sectigo key type +int is_valid_sectigo_key_type(const char *key_type) +{ + if (!key_type) { + return 0; + } + + const char *valid_key_types[] = { + "RSA-2048", "RSA-3072", "RSA-4096", "RSA-8192", + "ECC-PRIME256V1", "ECC-SECP384R1" + }; + + for (int i = 0; i < sizeof(valid_key_types) / sizeof(valid_key_types[0]); i++) { + if (strcmp(key_type, valid_key_types[i]) == 0) { + return 1; + } + } + + return 0; +} #define DEFAULT_GLOBAL_CFG_FILENAME "/etc/certifier/libcertifier.cfg" #define DEFAULT_AUTH_TYPE "X509" #define DEFAULT_CA_INFO "libcertifier-cert.crt" @@ -202,7 +223,7 @@ struct _PropMap char * mtls_filename; char * mtls_p12_filename; - //Sectigo properties (common properties like auth_token, source, etc. are above) + //Sectigo properties (common properties like auth_token, validity days, source, etc. are above) char * common_name; char * group_name; char * group_email; @@ -214,6 +235,8 @@ struct _PropMap char * subject_alt_names; char * owner_email; char * sectigo_url; + char * devhub_id; + char * key_type; }; static void free_prop_map_values(CertifierPropMap * prop_map); @@ -398,6 +421,15 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_URL: prop_map->sectigo_url = XSTRDUP((const char *)value); break; + case CERTIFIER_OPT_SECTIGO_DEVHUB_ID: + prop_map->devhub_id = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS: + prop_map->validity_days = (int)(size_t)value; + break; + case CERTIFIER_OPT_SECTIGO_KEY_TYPE: + prop_map->key_type = XSTRDUP((const char *)value); + break; default: log_warn("sectigo_property_set: unrecognized property [%d]", name); retval = CERTIFIER_ERR_PROPERTY_SET_10; @@ -901,7 +933,15 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) case CERTIFIER_OPT_SECTIGO_URL: retval = (void *) prop_map->sectigo_url; break; - + case CERTIFIER_OPT_SECTIGO_DEVHUB_ID: + retval = (void *) prop_map->devhub_id; + break; + case CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS: + retval = (void *) (size_t) prop_map->validity_days; + break; + case CERTIFIER_OPT_SECTIGO_KEY_TYPE: + retval = (void *) prop_map->key_type; + break; default: log_warn("property_get: unrecognized property [%d]", name); retval = NULL; @@ -1370,6 +1410,12 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object continue; } + if (strcmp(key, "libcertifier.sectigo.validity.days") == 0) { + int validity_days = json_object_get_number(root, key); + log_info("Loaded sectigo validity days: %d from config file.", validity_days); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS, (void *) (size_t) validity_days); + } + const char *value_str = json_object_get_string(root, key); if (value_str && strlen(value_str) > 0) { // Only process non-empty values // Map config key to property enum @@ -1417,6 +1463,18 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object log_info("Loaded sectigo URL: %s from config file.", value_str); sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_URL, value_str); } + else if (strcmp(key, "libcertifier.sectigo.devhub.id") == 0) { + log_info("Loaded sectigo devhub id: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_DEVHUB_ID, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.key.type") == 0) { + if (!is_valid_sectigo_key_type(value_str)) { + log_error("Invalid key type '%s' in config file. Supported: [RSA-2048, RSA-3072, RSA-4096, RSA-8192, ECC-PRIME256V1, ECC-SECP384R1]", value_str); + exit(0); + } + log_info("Loaded sectigo key type: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_KEY_TYPE, value_str); + } // Add more mappings as needed } } @@ -1598,6 +1656,8 @@ static void free_prop_map_values(CertifierPropMap * prop_map) FV(prop_map->subject_alt_names); FV(prop_map->owner_email); FV(prop_map->sectigo_url); + FV(prop_map->devhub_id); + FV(prop_map->key_type); } CertifierPropMap * property_new_sectigo(void) diff --git a/src/sectigo_client.c b/src/sectigo_client.c index 6339012..ce34044 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -97,6 +97,15 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_par param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_URL); params->sectigo_url = param ? XSTRDUP((const char *)param) : NULL; + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_DEVHUB_ID); + params->devhub_id = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS); + params->validity_days = param ? (size_t) param : 365; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_KEY_TYPE); + params->key_type = param ? XSTRDUP((const char *)param) : NULL; + return SECTIGO_CLIENT_SUCCESS; } @@ -211,7 +220,16 @@ const char * node_address, const char * certifier_id, char ** out_cert) json_object_set_string(root_obj, "businessJustification", params.business_justification ? params.business_justification : ""); json_object_set_string(root_obj, "certificateType", "comodo"); // Always "comodo" json_object_set_string(root_obj, "ownerEmailAddress", params.owner_email ? params.owner_email : ""); - // Always set subjectAltNames and ipAddresses, even if empty + json_object_set_string(root_obj, "devhubId", params.devhub_id ? params.devhub_id : ""); + + // Convert validity_days to string + if (params.validity_days > 0) { + char validity_days_str[16]; + snprintf(validity_days_str, sizeof(validity_days_str), "%zu", params.validity_days); + json_object_set_string(root_obj, "validityDays", validity_days_str); + } + + json_object_set_string(root_obj, "keyType", params.key_type ? params.key_type : ""); // subjectAltNames as array JSON_Value *san_array = json_value_init_array(); diff --git a/tests/xc_apis/xc_api_tests.c b/tests/xc_apis/xc_api_tests.c index 3e0f889..738c36e 100644 --- a/tests/xc_apis/xc_api_tests.c +++ b/tests/xc_apis/xc_api_tests.c @@ -255,6 +255,9 @@ static void test_get_sectigo_cert() params.subject_alt_names = "*"; params.owner_email = "first_last@comcast.com"; params.sectigo_url = "https://certs-dev.xpki.io/api/createCertificate"; + params.devhub_id = "12345"; + params.validity_days = 90; + params.key_type = "RSA-8192"; // Call the API error = xc_sectigo_get_cert(¶ms); From 7601dd08ba67ec49f040f1004166e2e20c578819 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Thu, 12 Feb 2026 13:39:49 -0500 Subject: [PATCH 22/30] Fix for passing validity days from command line --- src/main.c | 2 +- src/sectigo_client.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main.c b/src/main.c index 1a535d7..c3b8126 100644 --- a/src/main.c +++ b/src/main.c @@ -685,7 +685,7 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t break; case 'V': sectigo_parameter->get_cert_param.validity_days = atol(optarg); - certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS, optarg); + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS, (void *)(size_t)atol(optarg)); break; case 'W': sectigo_parameter->get_cert_param.key_type = optarg; diff --git a/src/sectigo_client.c b/src/sectigo_client.c index ce34044..51903fa 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -41,6 +41,7 @@ Certifier * get_sectigo_certifier_instance() if (certifier == NULL) { certifier = certifier_new(); + certifier->sectigo_mode = true; certifier_set_property(certifier, CERTIFIER_OPT_LOG_LEVEL, (void *) (size_t) 0); // Load Sectigo config file if it exists @@ -220,16 +221,19 @@ const char * node_address, const char * certifier_id, char ** out_cert) json_object_set_string(root_obj, "businessJustification", params.business_justification ? params.business_justification : ""); json_object_set_string(root_obj, "certificateType", "comodo"); // Always "comodo" json_object_set_string(root_obj, "ownerEmailAddress", params.owner_email ? params.owner_email : ""); - json_object_set_string(root_obj, "devhubId", params.devhub_id ? params.devhub_id : ""); - // Convert validity_days to string - if (params.validity_days > 0) { - char validity_days_str[16]; - snprintf(validity_days_str, sizeof(validity_days_str), "%zu", params.validity_days); - json_object_set_string(root_obj, "validityDays", validity_days_str); + // The following parameters are optional. Only include if set + if (params.devhub_id) { + json_object_set_string(root_obj, "devhubId", params.devhub_id); } - json_object_set_string(root_obj, "keyType", params.key_type ? params.key_type : ""); + if (params.validity_days > 0) { + json_object_set_number(root_obj, "validityDays", (double)params.validity_days); + } + + if (params.key_type) { + json_object_set_string(root_obj, "keyType", params.key_type); + } // subjectAltNames as array JSON_Value *san_array = json_value_init_array(); From fb219db7359657be08851ef48d1cbd0d90048ea0 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Thu, 12 Feb 2026 13:41:14 -0500 Subject: [PATCH 23/30] Remove flag preventing response body (with error message) from being returned --- src/http.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/http.c b/src/http.c index f05f590..7fc5b67 100644 --- a/src/http.c +++ b/src/http.c @@ -57,7 +57,6 @@ static void set_curl_options(CURL * curl, CertifierPropMap * prop_map) http_set_curlopt(curl, CURLOPT_SSL_VERIFYHOST, host_validation); http_set_curlopt(curl, CURLOPT_SSL_VERIFYPEER, peer_validation); - http_set_curlopt(curl, CURLOPT_FAILONERROR, 1L); http_set_curlopt(curl, CURLOPT_TIMEOUT, http_timeout); http_set_curlopt(curl, CURLOPT_CONNECTTIMEOUT, http_connect_timeout); From ba06c9aaa6ce9792aca4a58a4c110d7740334a63 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Mon, 16 Feb 2026 16:47:32 -0500 Subject: [PATCH 24/30] Added Sectigo cert revocation command --- docs/cli_usage.adoc | 40 ++++ docs/configuration.adoc | 23 +- include/certifier/certifier_api_easy.h | 2 + include/certifier/property.h | 4 + internal_headers/certifier/http.h | 2 + .../certifier/property_internal.h | 2 + internal_headers/certifier/sectigo_client.h | 21 +- libcertifier.cfg.sample | 7 +- src/certifier_api_easy.c | 74 ++++++- src/http.c | 16 +- src/main.c | 41 +++- src/property.c | 44 ++++ src/sectigo_client.c | 198 ++++++++++++++++++ tests/tests.c | 11 +- 14 files changed, 461 insertions(+), 24 deletions(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index 04fbee2..1310f9f 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -609,6 +609,46 @@ Disabled by default - Only error messages are shown. |=== +== *certifierUtil sectigo-get-cert options* +|=== +| *Long Option* | *Short Option* | *Examples* | *Description* +| help +| h +| --help + +-h +| Display this summary + +| common-name +| C +| --common-name + +-C +| Certificate common name + +| serial-number +| N +| --serial-number + +-N +| Certificate serial number (required for revocation) + +| certificate-id +| e +| --certificate-id + +-e +| Certificate ID (required for revocation) + +| requestor-email +| s +| --requestor-email + +-s +| Requestor email (required for revocation) + +| revocation-reason +| R +| --revocation-reason + +-R +| Revocation reason +|=== + *Configuration File* Configuration File is a file used to specify internal certifier util parameters such as timeouts, ecc curve types and other miscellaneous items. This file follows the JSON Format and can be manually editted from the `libcertifier.cfg.sample` template file present in the root directory. diff --git a/docs/configuration.adoc b/docs/configuration.adoc index 07191bc..d9d3d5c 100644 --- a/docs/configuration.adoc +++ b/docs/configuration.adoc @@ -33,16 +33,23 @@ xref:libcertifier.adoc[*Back to Manual*] | *Property Name* | *Default Value* | *Description* | libcertifier.sectigo.url | https://certs.xpki.io/api/createCertificate | | libcertifier.sectigo.auth.token | | -| libcertifier.sectigo.common.name | example.com | -| libcertifier.sectigo.group.name | ExampleGroup | -| libcertifier.sectigo.group.email | group@example.com | +| libcertifier.sectigo.common.name | | +| libcertifier.sectigo.group.name | | +| libcertifier.sectigo.group.email | | | libcertifier.sectigo.id | user123 | -| libcertifier.sectigo.owner.first.name | First | -| libcertifier.sectigo.owner.last.name | Last | -| libcertifier.sectigo.project.name | ExampleProject | -| libcertifier.sectigo.business.justification | Testing | +| libcertifier.sectigo.owner.first.name | | +| libcertifier.sectigo.owner.last.name | | +| libcertifier.sectigo.project.name | | +| libcertifier.sectigo.business.justification | | | libcertifier.sectigo.subject.alt.names | [] | -| libcertifier.sectigo.owner.email | owner@example.com | +| libcertifier.sectigo.owner.email | | +| libcertifier.sectigo.devhub.id | | +| libcertifier.sectigo.validity.days | 365 | +| libcertifier.sectigo.key.type | | +| libcertifier.sectigo.serial.number | | +| libcertifier.sectigo.certificate.id | | +| libcertifier.sectigo.requestor.email | | +| libcertifier.sectigo.revocation.request.reason | | |======= == Extended Key Usage values: diff --git a/include/certifier/certifier_api_easy.h b/include/certifier/certifier_api_easy.h index 0037064..5bec8ee 100644 --- a/include/certifier/certifier_api_easy.h +++ b/include/certifier/certifier_api_easy.h @@ -102,6 +102,8 @@ typedef enum CERTIFIER_MODE_PRINT_HELP = 65536, CERTIFIER_MODE_SECTIGO_GET_CERT, + + CERTIFIER_MODE_SECTIGO_REVOKE_CERT, CERTIFIER_MODE_SECTIGO_PRINT_HELP // 131072 is unused diff --git a/include/certifier/property.h b/include/certifier/property.h index e4e9b10..72eaa89 100644 --- a/include/certifier/property.h +++ b/include/certifier/property.h @@ -218,6 +218,10 @@ typedef enum CERTIFIER_OPT CERTIFIER_OPT_SECTIGO_DEVHUB_ID, CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS, CERTIFIER_OPT_SECTIGO_KEY_TYPE, + CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER, + CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, + CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL, + CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON } CERTIFIER_OPT; diff --git a/internal_headers/certifier/http.h b/internal_headers/certifier/http.h index 2ff2324..0f49012 100644 --- a/internal_headers/certifier/http.h +++ b/internal_headers/certifier/http.h @@ -53,6 +53,8 @@ http_response * http_get(const CertifierPropMap * props, const char * url, const http_response * http_post(const CertifierPropMap * props, const char * url, const char * http_headers[], const char * body); +http_response * http_put(const CertifierPropMap * props, const char * url, const char * http_headers[], const char * body); + void http_free_response(http_response * resp); #ifdef __cplusplus diff --git a/internal_headers/certifier/property_internal.h b/internal_headers/certifier/property_internal.h index d220e28..08d58c2 100644 --- a/internal_headers/certifier/property_internal.h +++ b/internal_headers/certifier/property_internal.h @@ -101,6 +101,8 @@ const char * get_default_ca_info(); */ int is_valid_sectigo_key_type(const char * key_type); +int is_valid_sectigo_revocation_reason(const char * reason); + #ifdef __cplusplus } #endif diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index b116781..cf0287b 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -37,7 +37,7 @@ extern "C" { #define IMPULSE_URL "https://certs-dev.xpki.io/" -typedef struct{ +typedef struct { const char * auth_token; const char * common_name; const char * group_name; @@ -55,8 +55,16 @@ typedef struct{ const char * key_type; } sectigo_get_cert_param_t; +typedef struct { + const char * auth_token; + const char * common_name; + const char * serial_number; + const char * certificate_id; + const char * requestor_email; + const char * revocation_request_reason; +} sectigo_revoke_cert_param_t; -typedef enum{ +typedef enum { SECTIGO_CLIENT_SUCCESS = 0, SECTIGO_CLIENT_INVALID_ARGUMENT, SECTIGO_CLIENT_NOT_IMPLEMENTED, @@ -64,8 +72,7 @@ typedef enum{ } SECTIGO_CLIENT_ERROR_CODE; -typedef enum -{ +typedef enum { SECTIGO_AUTH_X509, SECTIGO_AUTH_SAT, } SECTIGO_AUTH_TYPE; @@ -73,14 +80,20 @@ typedef enum CertifierError sectigo_client_request_certificate(CertifierPropMap * props, const unsigned char * csr, const char * node_address, const char * certifier_id, char ** out_cert); +CertifierError sectigo_client_revoke_certificate(CertifierPropMap * props); + CertifierError sectigo_generate_certificate_signing_request(Certifier *certifier, char **out_csr_pem); Certifier * get_sectigo_certifier_instance(); SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params); +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_revoke_cert(sectigo_revoke_cert_param_t * params); + SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_param_t * params); +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_revoke_cert_param(sectigo_revoke_cert_param_t * params); + #ifdef __cplusplus } #endif diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index dd80ad6..d92c040 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -39,5 +39,10 @@ "libcertifier.sectigo.subject.alt.names": [], "libcertifier.sectigo.devhub.id": "", "libcertifier.sectigo.validity.days": 365, - "libcertifier.sectigo.key.type": "" + "libcertifier.sectigo.key.type": "", + "libcertifier.sectigo.serial.number": "", + "libcertifier.sectigo.certificate.id": "", + "libcertifier.sectigo.requestor.email": "", + "libcertifier.sectigo.revocation.request.reason": "" + } diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index 851960d..5ea6191 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -110,6 +110,15 @@ { NULL, 0, NULL, 0 } //make default arg '*' for san and ip //only take in choices=['fte', 'contractor', 'associate'] + +#define SECTIGO_REVOKE_CERT_LONG_OPTIONS \ + { "common-name", required_argument, NULL, 'C' }, \ + { "serial-number", required_argument, NULL, 'N' }, \ + { "certificate-id", required_argument, NULL, 'e' }, \ + { "requestor-email", required_argument, NULL, 's' }, \ + { "revocation-request-reason", required_argument, NULL, 'R' }, \ + { "config", required_argument, NULL, 'l' }, \ + { NULL, 0, NULL, 0 } static void finish_operation(CERTIFIER * easy, int return_code, const char * operation_output); @@ -325,7 +334,8 @@ CERTIFIER_MODE certifier_api_easy_get_mode(CERTIFIER * easy) { "renew-cert", CERTIFIER_MODE_RENEW_CERT }, { "print-cert", CERTIFIER_MODE_PRINT_CERT }, { "revoke", CERTIFIER_MODE_REVOKE_CERT }, - { "sectigo-get-cert", CERTIFIER_MODE_SECTIGO_GET_CERT} + { "sectigo-get-cert", CERTIFIER_MODE_SECTIGO_GET_CERT}, + { "sectigo-revoke-cert", CERTIFIER_MODE_SECTIGO_REVOKE_CERT}, }; for (int i = 0; i < sizeof(command_map) / sizeof(command_map_t); ++i) @@ -810,6 +820,32 @@ static int do_sectigo_get_cert(CERTIFIER * easy) } } +static int do_sectigo_revoke_cert(CERTIFIER * easy) +{ + // Check for required Sectigo properties + const char *common_name = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); + const char *requestor_email = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL); + const char *revocation_reason = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON); + if (util_is_empty(common_name) || util_is_empty(requestor_email) || util_is_empty(revocation_reason)) { + finish_operation(easy, CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1, + "Missing required Sectigo flag: (common-name, requestor-email, revocation-request-reason)"); + return CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + } + + // Call Sectigo API to revoke certificate + CertifierPropMap * props = certifier_easy_api_get_props(easy->certifier); + CertifierError rc = sectigo_client_revoke_certificate(props); + + //Handle result + if (rc.application_error_code == 0) { + finish_operation(easy, 0, "Certificate revoked successfully"); + return 0; + } else { + finish_operation(easy, rc.application_error_code, rc.application_error_msg); + return rc.application_error_code; + } +} + char * certifier_api_easy_get_version(CERTIFIER * easy) { @@ -850,7 +886,9 @@ int certifier_api_easy_print_helper(CERTIFIER * easy) "renew-cert\n" "print-cert\n" "revoke\n" - "get-sectigo-cert\n"); + "sectigo-get-cert\n" + "sectigo-revoke-cert\n" + ); } return 0; @@ -911,6 +949,7 @@ static int process_command_line(CERTIFIER * easy) static const struct option print_cert_long_opts[] = { BASE_LONG_OPTIONS, { NULL, 0, NULL, 0 } }; static const struct option revoke_cert_long_opts[] = { BASE_LONG_OPTIONS, CA_PATH_LONG_OPTION, { NULL, 0, NULL, 0 } }; static const struct option sectigo_get_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_GET_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; + static const struct option sectigo_revoke_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_REVOKE_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; static command_opt_lut_t command_opt_lut[] = { { CERTIFIER_MODE_REGISTER, get_cert_short_options, get_cert_long_opts }, @@ -919,7 +958,8 @@ static int process_command_line(CERTIFIER * easy) { CERTIFIER_MODE_RENEW_CERT, renew_cert_short_options, renew_cert_long_opts }, { CERTIFIER_MODE_PRINT_CERT, print_cert_short_options, print_cert_long_opts }, { CERTIFIER_MODE_REVOKE_CERT, revoke_cert_short_options, revoke_cert_long_opts }, - {CERTIFIER_MODE_SECTIGO_GET_CERT, sectigo_get_cert_short_options, sectigo_get_cert_long_opts} + { CERTIFIER_MODE_SECTIGO_GET_CERT, sectigo_get_cert_short_options, sectigo_get_cert_long_opts}, + { CERTIFIER_MODE_SECTIGO_REVOKE_CERT, sectigo_get_cert_short_options, sectigo_revoke_cert_long_opts} }; char * version_string = certifier_api_easy_get_version(easy); @@ -1229,6 +1269,30 @@ static int process_command_line(CERTIFIER * easy) exit(0); } return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_KEY_TYPE, optarg); + case 'R': // Revocation reason + if (optarg) { + if (optarg == NULL) { + log_error("Invalid revocation reason. Supported reasons: []"); + exit(0); + } + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON, optarg); + } + break; + case 's': // Revocation requestor email + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL, optarg); + } + break; + case 'N': // Serial Number + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER, optarg); + } + break; + case 'e': // Certificate ID + if (optarg) { + return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, optarg); + } + break; case '?': /* Case when user enters the command as * $ ./libCertifier -p @@ -1514,6 +1578,10 @@ switch(easy -> mode){ do_sectigo_get_cert(easy); break; + case CERTIFIER_MODE_SECTIGO_REVOKE_CERT: + do_sectigo_revoke_cert(easy); + break; + default: finish_operation(easy, -1, "Invalid mode"); break; diff --git a/src/http.c b/src/http.c index 7fc5b67..8c7a859 100644 --- a/src/http.c +++ b/src/http.c @@ -135,7 +135,7 @@ static http_response * http_success_response(const char * payload, int http_code return resp; } -static http_response * do_http(const CertifierPropMap * props, const char * url, const char * http_headers[], const char * body) +static http_response * do_http(const CertifierPropMap * props, const char * url, const char * http_headers[], const char * body, const char * http_method) { char errbuf[CURL_ERROR_SIZE] = { 0 }; @@ -176,6 +176,11 @@ static http_response * do_http(const CertifierPropMap * props, const char * url, http_set_curlopt(curl, CURLOPT_URL, url); + if (http_method != NULL) + { + http_set_curlopt(curl, CURLOPT_CUSTOMREQUEST, http_method); + } + // post if ((body != NULL) && (XSTRLEN(body) > 0)) { @@ -236,13 +241,18 @@ int http_destroy() http_response * http_get(const CertifierPropMap * props, const char * url, const char * http_headers[]) { - return do_http(props, url, http_headers, NULL); + return do_http(props, url, http_headers, NULL, "GET"); } http_response * http_post(const CertifierPropMap * props, const char * url, const char * http_headers[], const char * body) { - return do_http(props, url, http_headers, body); + return do_http(props, url, http_headers, body, "POST"); +} + +http_response * http_put(const CertifierPropMap * props, const char * url, const char * http_headers[], const char * body) +{ + return do_http(props, url, http_headers, body, "PUT"); } void http_free_response(http_response * resp) diff --git a/src/main.c b/src/main.c index c3b8126..4549c22 100644 --- a/src/main.c +++ b/src/main.c @@ -41,6 +41,7 @@ typedef enum { SECTIGO_MODE_NONE, SECTIGO_MODE_GET_CERT, + SECTIGO_MODE_REVOKE_CERT, SECTIGO_MODE_PRINT_HELP } SECTIGO_MODE; @@ -54,7 +55,8 @@ typedef union typedef union { - sectigo_get_cert_param_t get_cert_param; + sectigo_get_cert_param_t get_cert_param; + sectigo_revoke_cert_param_t revoke_cert_param; } sectigo_parameter_t; @@ -113,7 +115,9 @@ SECTIGO_MODE sectigo_get_mode(int argc, char ** argv){ } command_map_t; command_map_t command_map[] = { - {"sectigo-help", SECTIGO_MODE_PRINT_HELP}, {"sectigo-get-cert", SECTIGO_MODE_GET_CERT} + {"sectigo-help", SECTIGO_MODE_PRINT_HELP}, + {"sectigo-get-cert", SECTIGO_MODE_GET_CERT}, + {"sectigo-revoke-cert", SECTIGO_MODE_REVOKE_CERT} }; for(int i = 0; i < sizeof(command_map) / sizeof(command_map_t); ++i){ @@ -156,6 +160,7 @@ XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) "print-cert\n" "revoke\n" "sectigo-get-cert\n" + "sectigo-revoke-cert\n" "sectigo-help\n"); } @@ -284,10 +289,20 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) "--url [value] (-u)\n" \ "--config [value] (-l)\n" \ +#define SECTIGO_REVOKE_CERT_HELPER \ + "--common-name [value] (-C)\n" \ + "--serial-number [value] (-N)\n" \ + "--certificate-id [value] (-e)\n" \ + "--requestor-email [value] (-s)\n" \ + "--revocation-request-reason [value] (-R)\n" \ + "--config [value] (-l)\n" \ + switch (mode) { case SECTIGO_MODE_GET_CERT: return SECTIGO_BASE_HELPER SECTIGO_GET_CERT_HELPER; + case SECTIGO_MODE_REVOKE_CERT: + return SECTIGO_BASE_HELPER SECTIGO_REVOKE_CERT_HELPER; case SECTIGO_MODE_PRINT_HELP: return SECTIGO_BASE_HELPER; default: @@ -612,6 +627,9 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t case SECTIGO_MODE_GET_CERT: ReturnErrorOnFailure(xc_sectigo_get_default_cert_param(§igo_parameter->get_cert_param)); break; + case SECTIGO_MODE_REVOKE_CERT: + ReturnErrorOnFailure(xc_sectigo_get_default_revoke_cert_param(§igo_parameter->revoke_cert_param)); + break; default: return SECTIGO_CLIENT_NOT_IMPLEMENTED; } @@ -691,6 +709,22 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t sectigo_parameter->get_cert_param.key_type = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_KEY_TYPE, optarg); break; + case 'R': + sectigo_parameter->revoke_cert_param.revocation_request_reason = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON, optarg); + break; + case 'N': + sectigo_parameter->revoke_cert_param.serial_number = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER, optarg); + break; + case 'e': + sectigo_parameter->revoke_cert_param.certificate_id = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, optarg); + break; + case 's': + sectigo_parameter->revoke_cert_param.requestor_email = optarg; + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL, optarg); + break; case '?': log_info("Invalid or missing Sectigo option"); error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; @@ -723,6 +757,9 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_perform(int argc, char ** argv) case SECTIGO_MODE_GET_CERT: return xc_sectigo_get_cert(§igo_parameter.get_cert_param); break; + case SECTIGO_MODE_REVOKE_CERT: + return xc_sectigo_revoke_cert(§igo_parameter.revoke_cert_param); + break; default: break; } diff --git a/src/property.c b/src/property.c index 0ffe906..692c97e 100644 --- a/src/property.c +++ b/src/property.c @@ -237,6 +237,10 @@ struct _PropMap char * sectigo_url; char * devhub_id; char * key_type; + char * serial_number; + char * certificate_id; + char * revocation_request_reason; + char * requestor_email; }; static void free_prop_map_values(CertifierPropMap * prop_map); @@ -430,6 +434,18 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_KEY_TYPE: prop_map->key_type = XSTRDUP((const char *)value); break; + case CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER: + prop_map->serial_number = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID: + prop_map->certificate_id = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL: + prop_map->requestor_email = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON: + prop_map->revocation_request_reason = XSTRDUP((const char *)value); + break; default: log_warn("sectigo_property_set: unrecognized property [%d]", name); retval = CERTIFIER_ERR_PROPERTY_SET_10; @@ -942,6 +958,18 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) case CERTIFIER_OPT_SECTIGO_KEY_TYPE: retval = (void *) prop_map->key_type; break; + case CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER: + retval = (void *) prop_map->serial_number; + break; + case CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID: + retval = (void *) prop_map->certificate_id; + break; + case CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL: + retval = (void *) prop_map->requestor_email; + break; + case CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON: + retval = (void *) prop_map->revocation_request_reason; + break; default: log_warn("property_get: unrecognized property [%d]", name); retval = NULL; @@ -1475,6 +1503,22 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object log_info("Loaded sectigo key type: %s from config file.", value_str); sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_KEY_TYPE, value_str); } + else if (strcmp(key, "libcertifier.sectigo.serial.number") == 0) { + log_info("Loaded sectigo serial number: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.certificate.id") == 0) { + log_info("Loaded sectigo certificate id: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.requestor.email") == 0) { + log_info("Loaded sectigo requestor email: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.revocation.request.reason") == 0) { + log_info("Loaded sectigo revocation request reason: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON, value_str); + } // Add more mappings as needed } } diff --git a/src/sectigo_client.c b/src/sectigo_client.c index 51903fa..edea03e 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -110,6 +110,35 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_par return SECTIGO_CLIENT_SUCCESS; } +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_revoke_cert_param(sectigo_revoke_cert_param_t * params) +{ + Certifier * certifier = get_sectigo_certifier_instance(); + + memset(params, 0, sizeof(sectigo_revoke_cert_param_t)); + + void * param = NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); + params->auth_token = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); + params->common_name = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER); + params->serial_number = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID); + params->certificate_id = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL); + params->requestor_email = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON); + params->revocation_request_reason = param ? XSTRDUP((const char *)param) : NULL; + + return SECTIGO_CLIENT_SUCCESS; +} + CertifierError sectigo_client_request_certificate(CertifierPropMap * props, const unsigned char * csr, const char * node_address, const char * certifier_id, char ** out_cert) { @@ -305,6 +334,149 @@ const char * node_address, const char * certifier_id, char ** out_cert) return rc; } +CertifierError sectigo_client_revoke_certificate(CertifierPropMap * props) +{ + CertifierError rc = CERTIFIER_ERROR_INITIALIZER; + JSON_Value *root_value = NULL; + JSON_Object *root_obj = NULL; + char *json_body = NULL; + + char auth_header[VERY_LARGE_STRING_SIZE * 4] = ""; + char tracking_header[LARGE_STRING_SIZE] = ""; + char source_header[SMALL_STRING_SIZE] = ""; + http_response * resp = NULL; + const char * tracking_id = property_get(props, CERTIFIER_OPT_TRACKING_ID); + const char * bearer_token = property_get(props, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); + const char * source = "libcertifier"; + const char * sectigo_base_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); + + if (!bearer_token) { + log_error("Missing CERTIFIER_OPT_SECTIGO_AUTH_TOKEN"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Bearer token is missing"); + goto cleanup; + } + if (!sectigo_base_url) { + log_error("Missing CERTIFIER_OPT_SECTIGO_URL"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Sectigo base URL is missing"); + goto cleanup; + } + + // Build full URL: base + endpoint + char sectigo_revoke_cert_url[256]; + char revoke_cert_endpoint[] = "/api/revokeCertificate"; + strncpy(sectigo_revoke_cert_url, sectigo_base_url, sizeof(sectigo_revoke_cert_url) - 1); + strncpy(sectigo_revoke_cert_url + strlen(sectigo_base_url), revoke_cert_endpoint, + sizeof(sectigo_revoke_cert_url) - 1 - strlen(sectigo_base_url)); + log_debug("Tracking ID is: %s\n", tracking_id); + log_debug("Sectigo URL: %s\n", sectigo_revoke_cert_url); + + if (bearer_token != NULL) { + snprintf(auth_header, sizeof(auth_header), "Authorization: %s", bearer_token); + } + snprintf(tracking_header, sizeof(tracking_header), "x-xpki-request-id: %s", tracking_id); + snprintf(source_header, sizeof(source_header), "x-xpki-source: %s", source); + + const char *headers[] = { + "Accept: */*", + "Connection: keep-alive", + "cache-control: no-cache", + "Content-Type: application/json", + source_header, + tracking_header, + "x-xpki-partner-id: comcast", + auth_header, + NULL + }; + + // Take Mutex + if (pthread_mutex_lock(&lock) != 0) + { + rc.application_error_code = 17; + rc.application_error_msg = "sectigo_client_revoke_certificate: pthread_mutex_lock failed"; + goto cleanup; + } + + sectigo_revoke_cert_param_t params; + xc_sectigo_get_default_revoke_cert_param(¶ms); + + // Build JSON body + root_value = json_value_init_object(); + root_obj = json_value_get_object(root_value); + + json_object_set_string(root_obj, "commonName", params.common_name ? params.common_name : ""); + + if (params.requestor_email) { + json_object_set_string(root_obj, "requestorEmail", params.requestor_email); + } + + if (params.revocation_request_reason) { + json_object_set_string(root_obj, "revocationRequestReason", params.revocation_request_reason); + } + + // The following parameters are optional. Only include if set + if (params.serial_number) { + json_object_set_string(root_obj, "serialNumber", params.serial_number); + } + + if (params.certificate_id) { + json_object_set_string(root_obj, "certificateId", params.certificate_id); + } + + json_body = json_serialize_to_string(root_value); + if (!json_body) { + log_error("Failed to serialize JSON body"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Failed to serialize JSON body"); + goto cleanup; + } + + resp = http_put(props, sectigo_revoke_cert_url, headers, json_body); + if (resp == NULL) + { + goto cleanup; + } + + // Give Mutex + if (pthread_mutex_unlock(&lock) != 0) + { + rc.application_error_code = 18; + rc.application_error_msg = "sectigo_client_revoke_certificate: pthread_mutex_unlock failed"; + goto cleanup; + } + + rc.application_error_code = resp->error; + + // Check for errors + if (resp->error != 0) + { + rc.application_error_msg = util_format_curl_error("sectigo_client_revoke_certificate", resp->http_code, resp->error, + resp->error_msg, resp->payload, __FILE__, __LINE__); + goto cleanup; + } + + if (resp->payload == NULL) + { + log_error("ERROR: Failed to populate payload"); + goto cleanup; + } + +// Cleanup +cleanup: + + http_free_response(resp); + + if (json_body) { + json_free_serialized_string(json_body); + } + if (root_value) { + json_value_free(root_value); + } + + return rc; +} + SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params) { Certifier *certifier = get_sectigo_certifier_instance(); @@ -382,3 +554,29 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params) return req_rc.application_error_code; } + +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_revoke_cert(sectigo_revoke_cert_param_t * params) +{ + Certifier *certifier = get_sectigo_certifier_instance(); + + // Build JSON body + JSON_Value *root_value = json_value_init_object(); + JSON_Object *root_obj = json_value_get_object(root_value); + + if (params->common_name) + json_object_set_string(root_obj, "commonName", params->common_name); + if (params->serial_number) + json_object_set_string(root_obj, "serialNumber", params->serial_number); + if (params->certificate_id) + json_object_set_string(root_obj, "certificateId", params->certificate_id); + if (params->requestor_email) + json_object_set_string(root_obj, "requestorEmail", params->requestor_email); + if (params->revocation_request_reason) + json_object_set_string(root_obj, "revocationRequestReason", params->revocation_request_reason); + + // Call the request function + CertifierPropMap *props = certifier_get_prop_map(certifier); + CertifierError req_rc = sectigo_client_revoke_certificate(props); + + return req_rc.application_error_code; +} diff --git a/tests/tests.c b/tests/tests.c index 698430b..3b5d9fc 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -54,7 +54,7 @@ static char * g_mock_http_expected_body = NULL; static http_response g_mock_http_response; // FIXME: use cmocka object mocking for this instead of assert -static http_response * do_http(const char * url, const char * http_headers[], const char * body) +static http_response * do_http(const char * url, const char * http_headers[], const char * body, const char * http_method) { if (g_mock_http_expected_url != NULL) assert_string_equal(g_mock_http_expected_url, url); @@ -72,13 +72,18 @@ static http_response * do_http(const char * url, const char * http_headers[], co http_response * http_get(const CertifierPropMap * props, const char * url, const char * http_headers[]) { - return do_http(url, http_headers, NULL); + return do_http(url, http_headers, NULL, "GET"); } http_response * http_post(const CertifierPropMap * props, const char * url, const char * http_headers[], const char * body) { - return do_http(url, http_headers, body); + return do_http(url, http_headers, body, "POST"); +} + +http_response * http_put(const CertifierPropMap * props, const char * url, const char * http_headers[], const char * body) +{ + return do_http(url, http_headers, body, "PUT"); } void http_free_response(http_response * resp) From 1e741e73e194d3b617790b35609bb95d0821105c Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Tue, 17 Feb 2026 08:14:06 -0500 Subject: [PATCH 25/30] Added Sectigo cert renewal command (and some cleanup) --- include/certifier/certifier_api_easy.h | 2 + internal_headers/certifier/sectigo_client.h | 13 ++ src/certifier_api_easy.c | 47 ++++- src/main.c | 17 ++ src/sectigo_client.c | 199 +++++++++++++++++--- 5 files changed, 255 insertions(+), 23 deletions(-) diff --git a/include/certifier/certifier_api_easy.h b/include/certifier/certifier_api_easy.h index 5bec8ee..cb35905 100644 --- a/include/certifier/certifier_api_easy.h +++ b/include/certifier/certifier_api_easy.h @@ -103,6 +103,8 @@ typedef enum CERTIFIER_MODE_SECTIGO_GET_CERT, + CERTIFIER_MODE_SECTIGO_RENEW_CERT, + CERTIFIER_MODE_SECTIGO_REVOKE_CERT, CERTIFIER_MODE_SECTIGO_PRINT_HELP diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index cf0287b..663faeb 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -55,6 +55,13 @@ typedef struct { const char * key_type; } sectigo_get_cert_param_t; +typedef struct { + const char * auth_token; + const char * common_name; + const char * serial_number; + const char * certificate_id; + const char * requestor_email; +} sectigo_renew_cert_param_t; typedef struct { const char * auth_token; const char * common_name; @@ -80,6 +87,8 @@ typedef enum { CertifierError sectigo_client_request_certificate(CertifierPropMap * props, const unsigned char * csr, const char * node_address, const char * certifier_id, char ** out_cert); +CertifierError sectigo_client_renew_certificate(CertifierPropMap * props); + CertifierError sectigo_client_revoke_certificate(CertifierPropMap * props); CertifierError sectigo_generate_certificate_signing_request(Certifier *certifier, char **out_csr_pem); @@ -88,10 +97,14 @@ Certifier * get_sectigo_certifier_instance(); SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params); +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_renew_cert(sectigo_renew_cert_param_t * params); + SECTIGO_CLIENT_ERROR_CODE xc_sectigo_revoke_cert(sectigo_revoke_cert_param_t * params); SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_param_t * params); +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_renew_cert_param(sectigo_renew_cert_param_t * params); + SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_revoke_cert_param(sectigo_revoke_cert_param_t * params); #ifdef __cplusplus diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index 5ea6191..50780a4 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -111,6 +111,14 @@ //make default arg '*' for san and ip //only take in choices=['fte', 'contractor', 'associate'] +#define SECTIGO_RENEW_CERT_LONG_OPTIONS \ + { "common-name", required_argument, NULL, 'C' }, \ + { "serial-number", required_argument, NULL, 'N' }, \ + { "certificate-id", required_argument, NULL, 'e' }, \ + { "requestor-email", required_argument, NULL, 's' }, \ + { "config", required_argument, NULL, 'l' }, \ + { NULL, 0, NULL, 0 } + #define SECTIGO_REVOKE_CERT_LONG_OPTIONS \ { "common-name", required_argument, NULL, 'C' }, \ { "serial-number", required_argument, NULL, 'N' }, \ @@ -335,6 +343,7 @@ CERTIFIER_MODE certifier_api_easy_get_mode(CERTIFIER * easy) { "print-cert", CERTIFIER_MODE_PRINT_CERT }, { "revoke", CERTIFIER_MODE_REVOKE_CERT }, { "sectigo-get-cert", CERTIFIER_MODE_SECTIGO_GET_CERT}, + { "sectigo-renew-cert", CERTIFIER_MODE_SECTIGO_RENEW_CERT}, { "sectigo-revoke-cert", CERTIFIER_MODE_SECTIGO_REVOKE_CERT}, }; @@ -820,6 +829,33 @@ static int do_sectigo_get_cert(CERTIFIER * easy) } } +static int do_sectigo_renew_cert(CERTIFIER * easy) +{ + // Check for required Sectigo properties + const char *common_name = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); + const char *serial_number = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER); + const char *certificate_id = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID); + const char *requestor_email = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL); + if (util_is_empty(common_name) || (util_is_empty(serial_number) && util_is_empty(certificate_id)) || util_is_empty(requestor_email)) { + finish_operation(easy, CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1, + "Missing required Sectigo flag: (common-name, (serial-number or certificate-id), requestor-email)"); + return CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + } + + // Call Sectigo API to renew certificate + CertifierPropMap * props = certifier_easy_api_get_props(easy->certifier); + CertifierError rc = sectigo_client_renew_certificate(props); + + //Handle result + if (rc.application_error_code == 0) { + finish_operation(easy, 0, "Certificate renewed successfully"); + return 0; + } else { + finish_operation(easy, rc.application_error_code, rc.application_error_msg); + return rc.application_error_code; + } +} + static int do_sectigo_revoke_cert(CERTIFIER * easy) { // Check for required Sectigo properties @@ -887,6 +923,7 @@ int certifier_api_easy_print_helper(CERTIFIER * easy) "print-cert\n" "revoke\n" "sectigo-get-cert\n" + "sectigo-renew-cert\n" "sectigo-revoke-cert\n" ); } @@ -939,6 +976,8 @@ static int process_command_line(CERTIFIER * easy) static const char * const print_cert_short_options = BASE_SHORT_OPTIONS; static const char * const revoke_cert_short_options = BASE_SHORT_OPTIONS; static const char * const sectigo_get_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; + static const char * const sectigo_renew_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; + static const char * const sectigo_revoke_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; static const struct option get_cert_long_opts[] = { BASE_LONG_OPTIONS, GET_CRT_TOKEN_LONG_OPTIONS, GET_CERT_LONG_OPTIONS, VALIDITY_DAYS_LONG_OPTION, @@ -949,6 +988,7 @@ static int process_command_line(CERTIFIER * easy) static const struct option print_cert_long_opts[] = { BASE_LONG_OPTIONS, { NULL, 0, NULL, 0 } }; static const struct option revoke_cert_long_opts[] = { BASE_LONG_OPTIONS, CA_PATH_LONG_OPTION, { NULL, 0, NULL, 0 } }; static const struct option sectigo_get_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_GET_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; + static const struct option sectigo_renew_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_RENEW_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; static const struct option sectigo_revoke_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_REVOKE_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; static command_opt_lut_t command_opt_lut[] = { @@ -959,7 +999,8 @@ static int process_command_line(CERTIFIER * easy) { CERTIFIER_MODE_PRINT_CERT, print_cert_short_options, print_cert_long_opts }, { CERTIFIER_MODE_REVOKE_CERT, revoke_cert_short_options, revoke_cert_long_opts }, { CERTIFIER_MODE_SECTIGO_GET_CERT, sectigo_get_cert_short_options, sectigo_get_cert_long_opts}, - { CERTIFIER_MODE_SECTIGO_REVOKE_CERT, sectigo_get_cert_short_options, sectigo_revoke_cert_long_opts} + { CERTIFIER_MODE_SECTIGO_RENEW_CERT, sectigo_renew_cert_short_options, sectigo_renew_cert_long_opts}, + { CERTIFIER_MODE_SECTIGO_REVOKE_CERT, sectigo_revoke_cert_short_options, sectigo_revoke_cert_long_opts} }; char * version_string = certifier_api_easy_get_version(easy); @@ -1578,6 +1619,10 @@ switch(easy -> mode){ do_sectigo_get_cert(easy); break; + case CERTIFIER_MODE_SECTIGO_RENEW_CERT: + do_sectigo_renew_cert(easy); + break; + case CERTIFIER_MODE_SECTIGO_REVOKE_CERT: do_sectigo_revoke_cert(easy); break; diff --git a/src/main.c b/src/main.c index 4549c22..45e23db 100644 --- a/src/main.c +++ b/src/main.c @@ -41,6 +41,7 @@ typedef enum { SECTIGO_MODE_NONE, SECTIGO_MODE_GET_CERT, + SECTIGO_MODE_RENEW_CERT, SECTIGO_MODE_REVOKE_CERT, SECTIGO_MODE_PRINT_HELP @@ -117,6 +118,7 @@ SECTIGO_MODE sectigo_get_mode(int argc, char ** argv){ command_map_t command_map[] = { {"sectigo-help", SECTIGO_MODE_PRINT_HELP}, {"sectigo-get-cert", SECTIGO_MODE_GET_CERT}, + {"sectigo-renew-cert", SECTIGO_MODE_RENEW_CERT}, {"sectigo-revoke-cert", SECTIGO_MODE_REVOKE_CERT} }; @@ -160,6 +162,7 @@ XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) "print-cert\n" "revoke\n" "sectigo-get-cert\n" + "sectigo-renew-cert\n" "sectigo-revoke-cert\n" "sectigo-help\n"); } @@ -289,6 +292,12 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) "--url [value] (-u)\n" \ "--config [value] (-l)\n" \ +#define SECTIGO_RENEW_CERT_HELPER \ + "--common-name [value] (-C)\n" \ + "--serial-number [value] (-N)\n" \ + "--certificate-id [value] (-e)\n" \ + "--requestor-email [value] (-s)\n" \ + #define SECTIGO_REVOKE_CERT_HELPER \ "--common-name [value] (-C)\n" \ "--serial-number [value] (-N)\n" \ @@ -301,6 +310,8 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) { case SECTIGO_MODE_GET_CERT: return SECTIGO_BASE_HELPER SECTIGO_GET_CERT_HELPER; + case SECTIGO_MODE_RENEW_CERT: + return SECTIGO_BASE_HELPER SECTIGO_RENEW_CERT_HELPER; case SECTIGO_MODE_REVOKE_CERT: return SECTIGO_BASE_HELPER SECTIGO_REVOKE_CERT_HELPER; case SECTIGO_MODE_PRINT_HELP: @@ -627,6 +638,9 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t case SECTIGO_MODE_GET_CERT: ReturnErrorOnFailure(xc_sectigo_get_default_cert_param(§igo_parameter->get_cert_param)); break; + case SECTIGO_MODE_RENEW_CERT: + ReturnErrorOnFailure(xc_sectigo_get_default_renew_cert_param(§igo_parameter->get_cert_param)); + break; case SECTIGO_MODE_REVOKE_CERT: ReturnErrorOnFailure(xc_sectigo_get_default_revoke_cert_param(§igo_parameter->revoke_cert_param)); break; @@ -757,6 +771,9 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_perform(int argc, char ** argv) case SECTIGO_MODE_GET_CERT: return xc_sectigo_get_cert(§igo_parameter.get_cert_param); break; + case SECTIGO_MODE_RENEW_CERT: + return xc_sectigo_renew_cert(§igo_parameter.get_cert_param); + break; case SECTIGO_MODE_REVOKE_CERT: return xc_sectigo_revoke_cert(§igo_parameter.revoke_cert_param); break; diff --git a/src/sectigo_client.c b/src/sectigo_client.c index edea03e..27f43d3 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -110,6 +110,32 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_par return SECTIGO_CLIENT_SUCCESS; } +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_renew_cert_param(sectigo_renew_cert_param_t * params) +{ + Certifier * certifier = get_sectigo_certifier_instance(); + + memset(params, 0, sizeof(sectigo_renew_cert_param_t)); + + void * param = NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); + params->auth_token = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_COMMON_NAME); + params->common_name = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER); + params->serial_number = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID); + params->certificate_id = param ? XSTRDUP((const char *)param) : NULL; + + param = certifier_get_property(certifier, CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL); + params->requestor_email = param ? XSTRDUP((const char *)param) : NULL; + + return SECTIGO_CLIENT_SUCCESS; +} + SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_revoke_cert_param(sectigo_revoke_cert_param_t * params) { Certifier * certifier = get_sectigo_certifier_instance(); @@ -334,6 +360,143 @@ const char * node_address, const char * certifier_id, char ** out_cert) return rc; } +CertifierError sectigo_client_renew_certificate(CertifierPropMap * props) +{ + CertifierError rc = CERTIFIER_ERROR_INITIALIZER; + JSON_Value *root_value = NULL; + JSON_Object *root_obj = NULL; + char *json_body = NULL; + + char auth_header[VERY_LARGE_STRING_SIZE * 4] = ""; + char tracking_header[LARGE_STRING_SIZE] = ""; + char source_header[SMALL_STRING_SIZE] = ""; + http_response * resp = NULL; + const char * tracking_id = property_get(props, CERTIFIER_OPT_TRACKING_ID); + const char * bearer_token = property_get(props, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); + const char * source = "libcertifier"; + const char * sectigo_base_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); + + if (!bearer_token) { + log_error("Missing CERTIFIER_OPT_SECTIGO_AUTH_TOKEN"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Bearer token is missing"); + goto cleanup; + } + if (!sectigo_base_url) { + log_error("Missing CERTIFIER_OPT_SECTIGO_URL"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Sectigo base URL is missing"); + goto cleanup; + } + + // Build full URL: base + endpoint + char sectigo_renew_cert_url[256]; + char renew_cert_endpoint[] = "/api/renewCertificate"; + strncpy(sectigo_renew_cert_url, sectigo_base_url, sizeof(sectigo_renew_cert_url) - 1); + strncpy(sectigo_renew_cert_url + strlen(sectigo_base_url), renew_cert_endpoint, + sizeof(sectigo_renew_cert_url) - 1 - strlen(sectigo_base_url)); + log_debug("Tracking ID is: %s\n", tracking_id); + log_debug("Sectigo URL: %s\n", sectigo_renew_cert_url); + + if (bearer_token != NULL) { + snprintf(auth_header, sizeof(auth_header), "Authorization: %s", bearer_token); + } + snprintf(tracking_header, sizeof(tracking_header), "x-xpki-request-id: %s", tracking_id); + snprintf(source_header, sizeof(source_header), "x-xpki-source: %s", source); + + const char *headers[] = { + "Accept: */*", + "Connection: keep-alive", + "cache-control: no-cache", + "Content-Type: application/json", + source_header, + tracking_header, + "x-xpki-partner-id: comcast", + auth_header, + NULL + }; + + // Take Mutex + if (pthread_mutex_lock(&lock) != 0) + { + rc.application_error_code = 17; + rc.application_error_msg = "sectigo_client_renew_certificate: pthread_mutex_lock failed"; + goto cleanup; + } + + sectigo_renew_cert_param_t params; + xc_sectigo_get_default_renew_cert_param(¶ms); + + // Build JSON body + root_value = json_value_init_object(); + root_obj = json_value_get_object(root_value); + + json_object_set_string(root_obj, "commonName", params.common_name ? params.common_name : ""); + + json_object_set_string(root_obj, "requestorEmail", params.requestor_email); + + // The following parameters are optional (one required). Only include if set + if (params.serial_number) { + json_object_set_string(root_obj, "serialNumber", params.serial_number); + } + + if (params.certificate_id) { + json_object_set_string(root_obj, "certificateId", params.certificate_id); + } + + json_body = json_serialize_to_string(root_value); + if (!json_body) { + log_error("Failed to serialize JSON body"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Failed to serialize JSON body"); + goto cleanup; + } + + resp = http_post(props, sectigo_renew_cert_url, headers, json_body); + if (resp == NULL) + { + goto cleanup; + } + + // Give Mutex + if (pthread_mutex_unlock(&lock) != 0) + { + rc.application_error_code = 18; + rc.application_error_msg = "sectigo_client_renew_certificate: pthread_mutex_unlock failed"; + goto cleanup; + } + + rc.application_error_code = resp->error; + + // Check for errors + if (resp->error != 0) + { + rc.application_error_msg = util_format_curl_error("sectigo_client_renew_certificate", resp->http_code, resp->error, + resp->error_msg, resp->payload, __FILE__, __LINE__); + goto cleanup; + } + + if (resp->payload == NULL) + { + log_error("ERROR: Failed to populate payload"); + goto cleanup; + } + +// Cleanup +cleanup: + + http_free_response(resp); + + if (json_body) { + json_free_serialized_string(json_body); + } + if (root_value) { + json_value_free(root_value); + } + + return rc; +} + CertifierError sectigo_client_revoke_certificate(CertifierPropMap * props) { CertifierError rc = CERTIFIER_ERROR_INITIALIZER; @@ -407,15 +570,11 @@ CertifierError sectigo_client_revoke_certificate(CertifierPropMap * props) json_object_set_string(root_obj, "commonName", params.common_name ? params.common_name : ""); - if (params.requestor_email) { - json_object_set_string(root_obj, "requestorEmail", params.requestor_email); - } + json_object_set_string(root_obj, "requestorEmail", params.requestor_email); - if (params.revocation_request_reason) { - json_object_set_string(root_obj, "revocationRequestReason", params.revocation_request_reason); - } - - // The following parameters are optional. Only include if set + json_object_set_string(root_obj, "revocationRequestReason", params.revocation_request_reason); + + // The following parameters are optional (one required). Only include if set if (params.serial_number) { json_object_set_string(root_obj, "serialNumber", params.serial_number); } @@ -555,24 +714,20 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params) return req_rc.application_error_code; } -SECTIGO_CLIENT_ERROR_CODE xc_sectigo_revoke_cert(sectigo_revoke_cert_param_t * params) +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_renew_cert(sectigo_renew_cert_param_t * params) { Certifier *certifier = get_sectigo_certifier_instance(); - // Build JSON body - JSON_Value *root_value = json_value_init_object(); - JSON_Object *root_obj = json_value_get_object(root_value); + // Call the request function + CertifierPropMap *props = certifier_get_prop_map(certifier); + CertifierError req_rc = sectigo_client_renew_certificate(props); - if (params->common_name) - json_object_set_string(root_obj, "commonName", params->common_name); - if (params->serial_number) - json_object_set_string(root_obj, "serialNumber", params->serial_number); - if (params->certificate_id) - json_object_set_string(root_obj, "certificateId", params->certificate_id); - if (params->requestor_email) - json_object_set_string(root_obj, "requestorEmail", params->requestor_email); - if (params->revocation_request_reason) - json_object_set_string(root_obj, "revocationRequestReason", params->revocation_request_reason); + return req_rc.application_error_code; +} + +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_revoke_cert(sectigo_revoke_cert_param_t * params) +{ + Certifier *certifier = get_sectigo_certifier_instance(); // Call the request function CertifierPropMap *props = certifier_get_prop_map(certifier); From 3b94d859a70006303ab1bded40d247ec22c987b5 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Tue, 17 Feb 2026 15:03:04 -0500 Subject: [PATCH 26/30] Added Sectigo cert search command (and some cleanup) --- docs/cli_usage.adoc | 177 +++++++++++++++++- docs/configuration.adoc | 11 ++ include/certifier/certifier_api_easy.h | 2 + include/certifier/property.h | 13 +- .../certifier/property_internal.h | 2 - internal_headers/certifier/sectigo_client.h | 25 +++ libcertifier.cfg.sample | 14 +- src/certifier_api_easy.c | 54 ++++++ src/http.c | 18 +- src/main.c | 79 +++++++- src/property.c | 126 ++++++++++++- src/sectigo_client.c | 164 +++++++++++++++- 12 files changed, 668 insertions(+), 17 deletions(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index 1310f9f..359f107 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -593,7 +593,7 @@ Disabled by default - Only error messages are shown. | K | --auth-token + -K -| Sectigo API auth token +| Auth token to authenticate with API | url | u @@ -609,7 +609,7 @@ Disabled by default - Only error messages are shown. |=== -== *certifierUtil sectigo-get-cert options* +== *certifierUtil sectigo-search-cert options* |=== | *Long Option* | *Short Option* | *Examples* | *Description* | help @@ -618,6 +618,171 @@ Disabled by default - Only error messages are shown. -h | Display this summary +| auth-token +| K +| --auth-token + +-K +| Auth token to authenticate with API + +| group-name +| G +| --group-name + +-G +| Group name to filter the search results + +| group-email +| E +| --group-email + +-E +| Group email to filter the search results + +| status +| S +| --status + +-S +| Status to filter the search results + +| common-name +| C +| --common-name + +-C +| Common name of certificate to filter the search results + +| offset +| o +| --offset + +-o +| Offset value for paginated results + +| limit +| L +| --limit + +-L +| Limit value for paginated results + +| start-date +| f +| --start-date + +-f +| Start date to filter the search results (Format: YYYY-MM-DD) + +| end-date +| t +| --end-date + +-t +| End date to filter the search results (Format: YYYY-MM-DD) + +| certificate-id +| i +| --certificate-id + +-i +| Certificate ID to filter the search results + +| validity-start-date +| p +| --validity-start-date + +-p +| Validity start date to filter the search results (Format: YYYY-MM-DD) + +| validity-end-date +| q +| --validity-end-date + +-q +| Validity end date to filter the search results (Format: YYYY-MM-DD) + +| cert-order +| c +| --cert-order + +-c +| To fetch the certificate order leaf and the ICA and Root order, pass leaf + +| is-cn-in-san +| a +| --is-cn-in-san + +-a +| To check if the common name is also present in the subject alternative names, pass this flag + +| request-type +| y +| --request-type + +-y +| To fetch certificates based on requests. Ex. ACME, API, WEB, XCM + +| timestamp +| m +| --timestamp + +-m +| To fetch certificates based on timestamp types. Ex. createdTimestamp, approvedTimestamp, signedTimestamp, rejectedTimestamp, revokedTimestamp + +| devhub-id +| D +| --devhub-id + +-D +| To fetch certificates based on DevHub ID + +| key-type +| W +| --key-type + +-W +| To fetch certificate(s) that match this public key type/algorithm. Supported key types: [RSA-2048, RSA-3072, RSA-4096, RSA-8192, ECC-PRIME256V1, ECC-SECP384R1] + +|=== + +== *certifierUtil sectigo-renew-cert options* +|=== +| *Long Option* | *Short Option* | *Examples* | *Description* +| help +| h +| --help + +-h +| Display this summary + +| auth-token +| K +| --auth-token + +-K +| Auth token to authenticate with API + +| common-name +| C +| --common-name + +-C +| Certificate common name (required for renewal) + +| serial-number +| N +| --serial-number + +-N +| Certificate serial number (either this or certificate ID is required for renewal) + +| certificate-id +| i +| --certificate-id + +-i +| Certificate ID (either this or serial number is required for renewal) + +| requestor-email +| s +| --requestor-email + +-s +| Requestor email (required for renewal) +|=== + +== *certifierUtil sectigo-revoke-cert options* +|=== +| *Long Option* | *Short Option* | *Examples* | *Description* +| help +| h +| --help + +-h +| Display this summary + +| auth-token +| K +| --auth-token + +-K +| Auth token to authenticate with API + | common-name | C | --common-name + @@ -628,13 +793,13 @@ Disabled by default - Only error messages are shown. | N | --serial-number + -N -| Certificate serial number (required for revocation) +| Certificate serial number (either this or certificate ID is required for revocation) | certificate-id -| e +| i | --certificate-id + --e -| Certificate ID (required for revocation) +-i +| Certificate ID (either this or serial number is required for revocation) | requestor-email | s diff --git a/docs/configuration.adoc b/docs/configuration.adoc index d9d3d5c..2607818 100644 --- a/docs/configuration.adoc +++ b/docs/configuration.adoc @@ -50,6 +50,17 @@ xref:libcertifier.adoc[*Back to Manual*] | libcertifier.sectigo.certificate.id | | | libcertifier.sectigo.requestor.email | | | libcertifier.sectigo.revocation.request.reason | | +| libcertifier.sectigo.status | | +| libcertifier.sectigo.offset | | +| libcertifier.sectigo.limit | 10 | +| libcertifier.sectigo.start.date | | +| libcertifier.sectigo.end.date | | +| libcertifier.sectigo.validity.start.date | | +| libcertifier.sectigo.validity.end.date | | +| libcertifier.sectigo.cert.order | | +| libcertifier.sectigo.is.cn.in.san | | +| libcertifier.sectigo.request.type | | +| libcertifier.sectigo.timestamp | | |======= == Extended Key Usage values: diff --git a/include/certifier/certifier_api_easy.h b/include/certifier/certifier_api_easy.h index cb35905..fe38562 100644 --- a/include/certifier/certifier_api_easy.h +++ b/include/certifier/certifier_api_easy.h @@ -103,6 +103,8 @@ typedef enum CERTIFIER_MODE_SECTIGO_GET_CERT, + CERTIFIER_MODE_SECTIGO_SEARCH_CERT, + CERTIFIER_MODE_SECTIGO_RENEW_CERT, CERTIFIER_MODE_SECTIGO_REVOKE_CERT, diff --git a/include/certifier/property.h b/include/certifier/property.h index 72eaa89..025747e 100644 --- a/include/certifier/property.h +++ b/include/certifier/property.h @@ -221,7 +221,18 @@ typedef enum CERTIFIER_OPT CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL, - CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON + CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON, + CERTIFIER_OPT_SECTIGO_STATUS, + CERTIFIER_OPT_SECTIGO_OFFSET, + CERTIFIER_OPT_SECTIGO_LIMIT, + CERTIFIER_OPT_SECTIGO_START_DATE, + CERTIFIER_OPT_SECTIGO_END_DATE, + CERTIFIER_OPT_SECTIGO_VALIDITY_START_DATE, + CERTIFIER_OPT_SECTIGO_VALIDITY_END_DATE, + CERTIFIER_OPT_SECTIGO_CERTIFICATE_ORDER, + CERTIFIER_OPT_SECTIGO_IS_CN_IN_SAN, + CERTIFIER_OPT_SECTIGO_REQUEST_TYPE, + CERTIFIER_OPT_SECTIGO_TIMESTAMP, } CERTIFIER_OPT; diff --git a/internal_headers/certifier/property_internal.h b/internal_headers/certifier/property_internal.h index 08d58c2..d220e28 100644 --- a/internal_headers/certifier/property_internal.h +++ b/internal_headers/certifier/property_internal.h @@ -101,8 +101,6 @@ const char * get_default_ca_info(); */ int is_valid_sectigo_key_type(const char * key_type); -int is_valid_sectigo_revocation_reason(const char * reason); - #ifdef __cplusplus } #endif diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index 663faeb..5b0180b 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -55,6 +55,26 @@ typedef struct { const char * key_type; } sectigo_get_cert_param_t; +typedef struct { + const char * auth_token; + const char * group_name; + const char * group_email; + const char * status; + const char * common_name; + const char * offset; + size_t limit; + const char * start_date; + const char * end_date; + size_t validity_start_date; + size_t validity_end_date; + const char * certificate_order; + const char * is_cn_in_san; + const char * request_type; + const char * timestamp; + const char * devhub_id; + const char * key_type; +} sectigo_search_cert_param_t; + typedef struct { const char * auth_token; const char * common_name; @@ -62,6 +82,7 @@ typedef struct { const char * certificate_id; const char * requestor_email; } sectigo_renew_cert_param_t; + typedef struct { const char * auth_token; const char * common_name; @@ -87,6 +108,8 @@ typedef enum { CertifierError sectigo_client_request_certificate(CertifierPropMap * props, const unsigned char * csr, const char * node_address, const char * certifier_id, char ** out_cert); +CertifierError sectigo_client_search_certificates(CertifierPropMap * props); + CertifierError sectigo_client_renew_certificate(CertifierPropMap * props); CertifierError sectigo_client_revoke_certificate(CertifierPropMap * props); @@ -97,6 +120,8 @@ Certifier * get_sectigo_certifier_instance(); SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params); +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_search_cert(sectigo_search_cert_param_t * params); + SECTIGO_CLIENT_ERROR_CODE xc_sectigo_renew_cert(sectigo_renew_cert_param_t * params); SECTIGO_CLIENT_ERROR_CODE xc_sectigo_revoke_cert(sectigo_revoke_cert_param_t * params); diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index d92c040..d68a1ca 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -43,6 +43,16 @@ "libcertifier.sectigo.serial.number": "", "libcertifier.sectigo.certificate.id": "", "libcertifier.sectigo.requestor.email": "", - "libcertifier.sectigo.revocation.request.reason": "" - + "libcertifier.sectigo.revocation.request.reason": "", + "libcertifier.sectigo.status": "", + "libcertifier.sectigo.offset": "", + "libcertifier.sectigo.limit": 10, + "libcertifier.sectigo.start.date": "", + "libcertifier.sectigo.end.date": "", + "libcertifier.sectigo.validity.start.date": "", + "libcertifier.sectigo.validity.end.date": "", + "libcertifier.sectigo.cert.order": "", + "libcertifier.sectigo.is.cn.in.san": "", + "libcertifier.sectigo.request.type": "", + "libcertifier.sectigo.timestamp": "" } diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index 50780a4..29af478 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -111,6 +111,27 @@ //make default arg '*' for san and ip //only take in choices=['fte', 'contractor', 'associate'] +#define SECTIGO_SEARCH_CERT_LONG_OPTIONS \ + { "group-name", required_argument, NULL, 'G' }, \ + { "group-email", required_argument, NULL, 'E' }, \ + { "status", required_argument, NULL, 'S' }, \ + { "common-name", required_argument, NULL, 'C' }, \ + { "offset", required_argument, NULL, 'o' }, \ + { "limit", required_argument, NULL, 'L' }, \ + { "start-date", required_argument, NULL, 'f' }, \ + { "end-date", required_argument, NULL, 't' }, \ + { "certificate-id", required_argument, NULL, 'i' }, \ + { "validity-start-date", required_argument, NULL, 'p' }, \ + { "validity-end-date", required_argument, NULL, 'q' }, \ + { "cert-order", required_argument, NULL, 'c' }, \ + { "is-cn-in-san", required_argument, NULL, 'a' }, \ + { "request-type", required_argument, NULL, 'y' }, \ + { "timestamp", required_argument, NULL, 'm' }, \ + { "devhub-id", required_argument, NULL, 'D' }, \ + { "key-type", required_argument, NULL, 'K' }, \ + { "config", required_argument, NULL, 'l' }, \ + { NULL, 0, NULL, 0 } + #define SECTIGO_RENEW_CERT_LONG_OPTIONS \ { "common-name", required_argument, NULL, 'C' }, \ { "serial-number", required_argument, NULL, 'N' }, \ @@ -343,6 +364,7 @@ CERTIFIER_MODE certifier_api_easy_get_mode(CERTIFIER * easy) { "print-cert", CERTIFIER_MODE_PRINT_CERT }, { "revoke", CERTIFIER_MODE_REVOKE_CERT }, { "sectigo-get-cert", CERTIFIER_MODE_SECTIGO_GET_CERT}, + { "sectigo-search-cert", CERTIFIER_MODE_SECTIGO_SEARCH_CERT}, { "sectigo-renew-cert", CERTIFIER_MODE_SECTIGO_RENEW_CERT}, { "sectigo-revoke-cert", CERTIFIER_MODE_SECTIGO_REVOKE_CERT}, }; @@ -829,6 +851,30 @@ static int do_sectigo_get_cert(CERTIFIER * easy) } } +static int do_sectigo_search_cert(CERTIFIER * easy) +{ + // Check for required Sectigo properties + const char *auth_token = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); + + if (util_is_empty(auth_token)) { + finish_operation(easy, CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1, "Missing required Sectigo flag: auth-token"); + return CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + } + + // Call Sectigo API to search for certificates + CertifierPropMap * props = certifier_easy_api_get_props(easy->certifier); + CertifierError rc = sectigo_client_search_certificates(props); + + //Handle result + if (rc.application_error_code == 0) { + finish_operation(easy, 0, rc.application_error_msg); + return 0; + } else { + finish_operation(easy, rc.application_error_code, rc.application_error_msg); + return rc.application_error_code; + } +} + static int do_sectigo_renew_cert(CERTIFIER * easy) { // Check for required Sectigo properties @@ -923,6 +969,7 @@ int certifier_api_easy_print_helper(CERTIFIER * easy) "print-cert\n" "revoke\n" "sectigo-get-cert\n" + "sectigo-search-cert\n" "sectigo-renew-cert\n" "sectigo-revoke-cert\n" ); @@ -976,6 +1023,7 @@ static int process_command_line(CERTIFIER * easy) static const char * const print_cert_short_options = BASE_SHORT_OPTIONS; static const char * const revoke_cert_short_options = BASE_SHORT_OPTIONS; static const char * const sectigo_get_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; + static const char * const sectigo_search_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; static const char * const sectigo_renew_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; static const char * const sectigo_revoke_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; @@ -988,6 +1036,7 @@ static int process_command_line(CERTIFIER * easy) static const struct option print_cert_long_opts[] = { BASE_LONG_OPTIONS, { NULL, 0, NULL, 0 } }; static const struct option revoke_cert_long_opts[] = { BASE_LONG_OPTIONS, CA_PATH_LONG_OPTION, { NULL, 0, NULL, 0 } }; static const struct option sectigo_get_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_GET_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; + static const struct option sectigo_search_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_SEARCH_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; static const struct option sectigo_renew_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_RENEW_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; static const struct option sectigo_revoke_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_REVOKE_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; @@ -999,6 +1048,7 @@ static int process_command_line(CERTIFIER * easy) { CERTIFIER_MODE_PRINT_CERT, print_cert_short_options, print_cert_long_opts }, { CERTIFIER_MODE_REVOKE_CERT, revoke_cert_short_options, revoke_cert_long_opts }, { CERTIFIER_MODE_SECTIGO_GET_CERT, sectigo_get_cert_short_options, sectigo_get_cert_long_opts}, + { CERTIFIER_MODE_SECTIGO_SEARCH_CERT, sectigo_search_cert_short_options, sectigo_search_cert_long_opts}, { CERTIFIER_MODE_SECTIGO_RENEW_CERT, sectigo_renew_cert_short_options, sectigo_renew_cert_long_opts}, { CERTIFIER_MODE_SECTIGO_REVOKE_CERT, sectigo_revoke_cert_short_options, sectigo_revoke_cert_long_opts} }; @@ -1619,6 +1669,10 @@ switch(easy -> mode){ do_sectigo_get_cert(easy); break; + case CERTIFIER_MODE_SECTIGO_SEARCH_CERT: + do_sectigo_search_cert(easy); + break; + case CERTIFIER_MODE_SECTIGO_RENEW_CERT: do_sectigo_renew_cert(easy); break; diff --git a/src/http.c b/src/http.c index 8c7a859..dff6aa0 100644 --- a/src/http.c +++ b/src/http.c @@ -19,6 +19,7 @@ #include "certifier/http.h" #include "certifier/httpdebug.h" #include "certifier/log.h" +#include "certifier/parson.h" #include "certifier/property.h" #include "certifier/types.h" #include @@ -224,8 +225,23 @@ static http_response * do_http(const CertifierPropMap * props, const char * url, } else { - log_debug("do_http returned: %s", cf->payload); + // Try to parse and pretty-print if it's JSON + JSON_Value *parsed_json = json_parse_string_with_comments(cf->payload); + if (parsed_json != NULL) { + char *pretty_json = json_serialize_to_string_pretty(parsed_json); + if (pretty_json) { + log_debug("do_http returned: %s", pretty_json); + json_free_serialized_string(pretty_json); + } else { + log_debug("do_http returned: %s", cf->payload); + } + json_value_free(parsed_json); + } else { + log_debug("do_http returned: %s", cf->payload); + } return http_success_response(cf->payload, http_code, errbuf, res); + // log_debug("do_http returned: %s", cf->payload); + // return http_success_response(cf->payload, http_code, errbuf, res); } } diff --git a/src/main.c b/src/main.c index 45e23db..8363b96 100644 --- a/src/main.c +++ b/src/main.c @@ -41,6 +41,7 @@ typedef enum { SECTIGO_MODE_NONE, SECTIGO_MODE_GET_CERT, + SECTIGO_MODE_SEARCH_CERT, SECTIGO_MODE_RENEW_CERT, SECTIGO_MODE_REVOKE_CERT, SECTIGO_MODE_PRINT_HELP @@ -57,6 +58,8 @@ typedef union typedef union { sectigo_get_cert_param_t get_cert_param; + sectigo_search_cert_param_t search_cert_param; + sectigo_renew_cert_param_t renew_cert_param; sectigo_revoke_cert_param_t revoke_cert_param; } sectigo_parameter_t; @@ -118,6 +121,7 @@ SECTIGO_MODE sectigo_get_mode(int argc, char ** argv){ command_map_t command_map[] = { {"sectigo-help", SECTIGO_MODE_PRINT_HELP}, {"sectigo-get-cert", SECTIGO_MODE_GET_CERT}, + {"sectigo-search-cert", SECTIGO_MODE_SEARCH_CERT}, {"sectigo-renew-cert", SECTIGO_MODE_RENEW_CERT}, {"sectigo-revoke-cert", SECTIGO_MODE_REVOKE_CERT} }; @@ -162,6 +166,7 @@ XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) "print-cert\n" "revoke\n" "sectigo-get-cert\n" + "sectigo-search-cert\n" "sectigo-renew-cert\n" "sectigo-revoke-cert\n" "sectigo-help\n"); @@ -292,13 +297,37 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) "--url [value] (-u)\n" \ "--config [value] (-l)\n" \ +#define SECTIGO_SEARCH_CERT_HELPER \ + "--auth-token [value] (-K)\n" \ + "--common-name [value] (-C)\n" \ + "--group-name [value] (-G)\n" \ + "--group-email [value] (-E)\n" \ + "--status [value] (-S)\n" \ + "--common-name [value] (-C)\n" \ + "--offset [value] (-o)\n" \ + "--limit [value] (-L)\n" \ + "--start-date [value] (-f)\n" \ + "--end-date [value] (-t)\n" \ + "--certificate-id [value] (-i)\n" \ + "--validity-start-date [value] (-p)\n" \ + "--validity-end-date [value] (-q)\n" \ + "--cert-order [value] (-c)\n" \ + "--is-cn-in-san [value] (-a)\n" \ + "--request-type [value] (-y)\n" \ + "--timestamp [value] (-m)\n" \ + "--devhub-id [value] (-D)\n" \ + "--key-type [value] (-W)\n" \ + "--config [value] (-l)\n" \ + #define SECTIGO_RENEW_CERT_HELPER \ + "--auth-token [value] (-K)\n" \ "--common-name [value] (-C)\n" \ "--serial-number [value] (-N)\n" \ "--certificate-id [value] (-e)\n" \ "--requestor-email [value] (-s)\n" \ #define SECTIGO_REVOKE_CERT_HELPER \ + "--auth-token [value] (-K)\n" \ "--common-name [value] (-C)\n" \ "--serial-number [value] (-N)\n" \ "--certificate-id [value] (-e)\n" \ @@ -310,6 +339,8 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) { case SECTIGO_MODE_GET_CERT: return SECTIGO_BASE_HELPER SECTIGO_GET_CERT_HELPER; + case SECTIGO_MODE_SEARCH_CERT: + return SECTIGO_BASE_HELPER SECTIGO_SEARCH_CERT_HELPER; case SECTIGO_MODE_RENEW_CERT: return SECTIGO_BASE_HELPER SECTIGO_RENEW_CERT_HELPER; case SECTIGO_MODE_REVOKE_CERT: @@ -638,6 +669,9 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t case SECTIGO_MODE_GET_CERT: ReturnErrorOnFailure(xc_sectigo_get_default_cert_param(§igo_parameter->get_cert_param)); break; + case SECTIGO_MODE_SEARCH_CERT: + // No default parameters to set for search cert, so just break + break; case SECTIGO_MODE_RENEW_CERT: ReturnErrorOnFailure(xc_sectigo_get_default_renew_cert_param(§igo_parameter->get_cert_param)); break; @@ -739,12 +773,48 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t sectigo_parameter->revoke_cert_param.requestor_email = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_REQUESTOR_EMAIL, optarg); break; + case 'S': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_STATUS, optarg); + break; + case 'o': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_OFFSET, optarg); + break; + case 'L': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_LIMIT, (void *)(size_t)atol(optarg)); + break; + case 'f': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_START_DATE, optarg); + break; + case 't': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_END_DATE, optarg); + break; + case 'i': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, optarg); + break; + case 'p': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_VALIDITY_START_DATE, optarg); + break; + case 'q': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_VALIDITY_END_DATE, optarg); + break; + case 'c': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERTIFICATE_ORDER, optarg); + break; + case 'a': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_IS_CN_IN_SAN, optarg); + break; + case 'y': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_REQUEST_TYPE, optarg); + break; + case 'm': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_TIMESTAMP, optarg); + break; case '?': - log_info("Invalid or missing Sectigo option"); + log_info("Invalid or missing Sectigo option\n"); error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; break; default: - log_info("Unknown Sectigo option: %c", opt); + log_info("Unknown Sectigo option: %c\n", opt); error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; break; } @@ -771,8 +841,11 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_perform(int argc, char ** argv) case SECTIGO_MODE_GET_CERT: return xc_sectigo_get_cert(§igo_parameter.get_cert_param); break; + case SECTIGO_MODE_SEARCH_CERT: + return xc_sectigo_search_cert(§igo_parameter.search_cert_param); + break; case SECTIGO_MODE_RENEW_CERT: - return xc_sectigo_renew_cert(§igo_parameter.get_cert_param); + return xc_sectigo_renew_cert(§igo_parameter.renew_cert_param); break; case SECTIGO_MODE_REVOKE_CERT: return xc_sectigo_revoke_cert(§igo_parameter.revoke_cert_param); diff --git a/src/property.c b/src/property.c index 692c97e..bf52c17 100644 --- a/src/property.c +++ b/src/property.c @@ -241,6 +241,17 @@ struct _PropMap char * certificate_id; char * revocation_request_reason; char * requestor_email; + char * status; + char * offset; + int limit; + char * start_date; + char * end_date; + char * validity_start_date; + char * validity_end_date; + char * certificate_order; + char * is_cn_in_san; + char * request_type; + char * timestamp; }; static void free_prop_map_values(CertifierPropMap * prop_map); @@ -446,6 +457,39 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON: prop_map->revocation_request_reason = XSTRDUP((const char *)value); break; + case CERTIFIER_OPT_SECTIGO_STATUS: + prop_map->status = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_OFFSET: + prop_map->offset = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_LIMIT: + prop_map->limit = (int)(size_t)value; + break; + case CERTIFIER_OPT_SECTIGO_START_DATE: + prop_map->start_date = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_END_DATE: + prop_map->end_date = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_VALIDITY_START_DATE: + prop_map->validity_start_date = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_VALIDITY_END_DATE: + prop_map->validity_end_date = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_CERTIFICATE_ORDER: + prop_map->certificate_order = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_IS_CN_IN_SAN: + prop_map->is_cn_in_san = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_REQUEST_TYPE: + prop_map->request_type = XSTRDUP((const char *)value); + break; + case CERTIFIER_OPT_SECTIGO_TIMESTAMP: + prop_map->timestamp = XSTRDUP((const char *)value); + break; default: log_warn("sectigo_property_set: unrecognized property [%d]", name); retval = CERTIFIER_ERR_PROPERTY_SET_10; @@ -970,6 +1014,39 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) case CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON: retval = (void *) prop_map->revocation_request_reason; break; + case CERTIFIER_OPT_SECTIGO_STATUS: + retval = (void *) prop_map->status; + break; + case CERTIFIER_OPT_SECTIGO_OFFSET: + retval = (void *) prop_map->offset; + break; + case CERTIFIER_OPT_SECTIGO_LIMIT: + retval = (void *) (size_t) prop_map->limit; + break; + case CERTIFIER_OPT_SECTIGO_START_DATE: + retval = (void *) prop_map->start_date; + break; + case CERTIFIER_OPT_SECTIGO_END_DATE: + retval = (void *) prop_map->end_date; + break; + case CERTIFIER_OPT_SECTIGO_VALIDITY_START_DATE: + retval = (void *) prop_map->validity_start_date; + break; + case CERTIFIER_OPT_SECTIGO_VALIDITY_END_DATE: + retval = (void *) prop_map->validity_end_date; + break; + case CERTIFIER_OPT_SECTIGO_CERTIFICATE_ORDER: + retval = (void *) prop_map->certificate_order; + break; + case CERTIFIER_OPT_SECTIGO_IS_CN_IN_SAN: + retval = (void *) prop_map->is_cn_in_san; + break; + case CERTIFIER_OPT_SECTIGO_REQUEST_TYPE: + retval = (void *) prop_map->request_type; + break; + case CERTIFIER_OPT_SECTIGO_TIMESTAMP: + retval = (void *) prop_map->timestamp; + break; default: log_warn("property_get: unrecognized property [%d]", name); retval = NULL; @@ -1444,6 +1521,12 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_VALIDITY_DAYS, (void *) (size_t) validity_days); } + if (strcmp(key, "libcertifier.sectigo.limit") == 0) { + int limit = json_object_get_number(root, key); + log_info("Loaded sectigo limit: %d from config file.", limit); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_LIMIT, (void *) (size_t) limit); + } + const char *value_str = json_object_get_string(root, key); if (value_str && strlen(value_str) > 0) { // Only process non-empty values // Map config key to property enum @@ -1519,7 +1602,48 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object log_info("Loaded sectigo revocation request reason: %s from config file.", value_str); sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_REVOCATION_REQUEST_REASON, value_str); } - // Add more mappings as needed + else if (strcmp(key, "libcertifier.sectigo.status") == 0) { + log_info("Loaded sectigo status: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_STATUS, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.offset") == 0) { + int offset = json_object_get_number(root, key); + log_info("Loaded sectigo offset: %d from config file.", offset); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_OFFSET, (void *) (size_t) offset); + } + else if (strcmp(key, "libcertifier.sectigo.start.date") == 0) { + log_info("Loaded sectigo start date: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_START_DATE, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.end.date") == 0) { + log_info("Loaded sectigo end date: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_END_DATE, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.validity.start.date") == 0) { + log_info("Loaded sectigo validity start date: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_VALIDITY_START_DATE, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.validity.end.date") == 0) { + log_info("Loaded sectigo validity end date: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_VALIDITY_END_DATE, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.certificate.order") == 0) { + log_info("Loaded sectigo certificate order: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ORDER, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.is.cn.in.san") == 0) { + int is_cn_in_san = json_object_get_number(root, key); + log_info("Loaded sectigo is CN in SAN: %d from config file.", is_cn_in_san); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_IS_CN_IN_SAN, (void *) (size_t) is_cn_in_san); + } + else if (strcmp(key, "libcertifier.sectigo.request.type") == 0) { + log_info("Loaded sectigo request type: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_REQUEST_TYPE, value_str); + } + else if (strcmp(key, "libcertifier.sectigo.timestamp") == 0) { + log_info("Loaded sectigo timestamp: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_TIMESTAMP, value_str); + } } } diff --git a/src/sectigo_client.c b/src/sectigo_client.c index 27f43d3..1bee629 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -53,6 +53,30 @@ Certifier * get_sectigo_certifier_instance() return certifier; } +static void append_query_param(char *url, size_t url_size, const char *key, const char *value, int *first_param) +{ + if (!value || strlen(value) == 0) { + return; + } + + size_t current_len = strlen(url); + snprintf(url + current_len, url_size - current_len, + "%s%s=%s", *first_param ? "?" : "&", key, value); + *first_param = 0; +} + +// For numeric parameters +static void append_query_param_num(char *url, size_t url_size, const char *key, size_t value, int *first_param) +{ + if (value == 0) { + return; + } + + size_t current_len = strlen(url); + snprintf(url + current_len, url_size - current_len, + "%s%s=%zu", *first_param ? "?" : "&", key, value); + *first_param = 0; +} SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_param_t * params) { @@ -360,6 +384,133 @@ const char * node_address, const char * certifier_id, char ** out_cert) return rc; } +CertifierError sectigo_client_search_certificates(CertifierPropMap * props) +{ + CertifierError rc = CERTIFIER_ERROR_INITIALIZER; + + char auth_header[VERY_LARGE_STRING_SIZE * 4] = ""; + char tracking_header[LARGE_STRING_SIZE] = ""; + char source_header[SMALL_STRING_SIZE] = ""; + http_response * resp = NULL; + const char * tracking_id = property_get(props, CERTIFIER_OPT_TRACKING_ID); + const char * bearer_token = property_get(props, CERTIFIER_OPT_SECTIGO_AUTH_TOKEN); + const char * source = "libcertifier"; + const char * sectigo_base_url = property_get(props, CERTIFIER_OPT_SECTIGO_URL); + + if (!bearer_token) { + log_error("Missing CERTIFIER_OPT_SECTIGO_AUTH_TOKEN"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Bearer token is missing"); + goto cleanup; + } + if (!sectigo_base_url) { + log_error("Missing CERTIFIER_OPT_SECTIGO_URL"); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Sectigo base URL is missing"); + goto cleanup; + } + + // Build full URL: base + endpoint + char sectigo_search_cert_url[256]; + char search_cert_endpoint[] = "/api/getCertificates"; + strncpy(sectigo_search_cert_url, sectigo_base_url, sizeof(sectigo_search_cert_url) - 1); + strncpy(sectigo_search_cert_url + strlen(sectigo_base_url), search_cert_endpoint, + sizeof(sectigo_search_cert_url) - 1 - strlen(sectigo_base_url)); + log_debug("Tracking ID is: %s\n", tracking_id); + + if (bearer_token != NULL) { + snprintf(auth_header, sizeof(auth_header), "Authorization: %s", bearer_token); + } + snprintf(tracking_header, sizeof(tracking_header), "x-xpki-request-id: %s", tracking_id); + snprintf(source_header, sizeof(source_header), "x-xpki-source: %s", source); + + const char *headers[] = { + "Accept: */*", + "Connection: keep-alive", + "cache-control: no-cache", + "Content-Type: application/json", + source_header, + tracking_header, + "x-xpki-partner-id: comcast", + auth_header, + NULL + }; + + // Take Mutex + if (pthread_mutex_lock(&lock) != 0) + { + rc.application_error_code = 17; + rc.application_error_msg = "sectigo_client_search_certificates: pthread_mutex_lock failed"; + goto cleanup; + } + + sectigo_search_cert_param_t params; + + int first_param = 1; // Used to determine whether to prepend '?' or '&' for query parameters + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "groupName", property_get(props, CERTIFIER_OPT_SECTIGO_GROUP_NAME), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "groupEmailAddress", property_get(props, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "status", property_get(props, CERTIFIER_OPT_SECTIGO_STATUS), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "commonName", property_get(props, CERTIFIER_OPT_SECTIGO_COMMON_NAME), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "offset", property_get(props, CERTIFIER_OPT_SECTIGO_OFFSET), &first_param); + append_query_param_num(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "limit", (size_t) property_get(props, CERTIFIER_OPT_SECTIGO_LIMIT), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "startDate", property_get(props, CERTIFIER_OPT_SECTIGO_START_DATE), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "endDate", property_get(props, CERTIFIER_OPT_SECTIGO_END_DATE), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "validityStartDate", property_get(props, CERTIFIER_OPT_SECTIGO_VALIDITY_START_DATE), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "validityEndDate", property_get(props, CERTIFIER_OPT_SECTIGO_VALIDITY_END_DATE), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "certOrder", property_get(props, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ORDER), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "isCNinSAN", property_get(props, CERTIFIER_OPT_SECTIGO_IS_CN_IN_SAN), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "requestType", property_get(props, CERTIFIER_OPT_SECTIGO_REQUEST_TYPE), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "timestamp", property_get(props, CERTIFIER_OPT_SECTIGO_TIMESTAMP), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "devhubId", property_get(props, CERTIFIER_OPT_SECTIGO_DEVHUB_ID), &first_param); + append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "keyType", property_get(props, CERTIFIER_OPT_SECTIGO_KEY_TYPE), &first_param); + + // certificateId is numeric for this endpoint, but a string for others, so handle separately + const char *cert_id_str = property_get(props, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID); + if (cert_id_str && strlen(cert_id_str) > 0) { + size_t cert_id_num = (size_t)atol(cert_id_str); + append_query_param_num(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "certificateId", cert_id_num, &first_param); + } + + log_debug("Sectigo URL: %s\n", sectigo_search_cert_url); + + resp = http_get(props, sectigo_search_cert_url, headers); + if (resp == NULL) + { + goto cleanup; + } + + // Give Mutex + if (pthread_mutex_unlock(&lock) != 0) + { + rc.application_error_code = 18; + rc.application_error_msg = "sectigo_client_search_certificates: pthread_mutex_unlock failed"; + goto cleanup; + } + + rc.application_error_code = resp->error; + + // Check for errors + if (resp->error != 0) + { + rc.application_error_msg = util_format_curl_error("sectigo_client_search_certificates", resp->http_code, resp->error, + resp->error_msg, resp->payload, __FILE__, __LINE__); + goto cleanup; + } + + if (resp->payload == NULL) + { + log_error("ERROR: Failed to populate payload"); + goto cleanup; + } + +// Cleanup +cleanup: + + http_free_response(resp); + + return rc; +} + CertifierError sectigo_client_renew_certificate(CertifierPropMap * props) { CertifierError rc = CERTIFIER_ERROR_INITIALIZER; @@ -399,7 +550,7 @@ CertifierError sectigo_client_renew_certificate(CertifierPropMap * props) log_debug("Sectigo URL: %s\n", sectigo_renew_cert_url); if (bearer_token != NULL) { - snprintf(auth_header, sizeof(auth_header), "Authorization: %s", bearer_token); + snprintf(auth_header, sizeof(auth_header), "Authorization: %s", bearer_token); } snprintf(tracking_header, sizeof(tracking_header), "x-xpki-request-id: %s", tracking_id); snprintf(source_header, sizeof(source_header), "x-xpki-source: %s", source); @@ -714,6 +865,17 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params) return req_rc.application_error_code; } +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_search_cert(sectigo_search_cert_param_t * params) +{ + Certifier *certifier = get_sectigo_certifier_instance(); + + // Call the request function + CertifierPropMap *props = certifier_get_prop_map(certifier); + CertifierError req_rc = sectigo_client_search_certificates(props); + + return req_rc.application_error_code; +} + SECTIGO_CLIENT_ERROR_CODE xc_sectigo_renew_cert(sectigo_renew_cert_param_t * params) { Certifier *certifier = get_sectigo_certifier_instance(); From acd9dace0792bf4135a98ffc884fd77fc3464ee0 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Tue, 17 Feb 2026 15:45:08 -0500 Subject: [PATCH 27/30] Cleanup discrepancies between code/docs for command line options --- docs/cli_usage.adoc | 46 +++++++++++++++---- src/certifier_api_easy.c | 3 +- src/main.c | 98 +++++++++++++++++++++++++++++++++++----- 3 files changed, 125 insertions(+), 22 deletions(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index 359f107..294594c 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -573,7 +573,7 @@ Disabled by default - Only error messages are shown. | owner-last-name | J -| --owner-lname + +| --owner-last-name + -J | Owner last name @@ -583,11 +583,23 @@ Disabled by default - Only error messages are shown. -Z | Owner email -| cert-type -| T -| --cert-type + --T -| Certificate type +| devhub-id +| D +| --devhub-id + +-D +| DevHub ID + +| validity-days +| V +| --validity-days + +-V +| Validity days for the certificate + +| key-type +| W +| --key-type + +-W +| Key type for the certificate. Supported key types: [RSA-2048, RSA-3072, RSA-4096, RSA-8192, ECC-PRIME256V1, ECC-SECP384R1] | auth-token | K @@ -606,7 +618,6 @@ Disabled by default - Only error messages are shown. | --config + -l | Path to config file - |=== == *certifierUtil sectigo-search-cert options* @@ -726,6 +737,11 @@ Disabled by default - Only error messages are shown. -W | To fetch certificate(s) that match this public key type/algorithm. Supported key types: [RSA-2048, RSA-3072, RSA-4096, RSA-8192, ECC-PRIME256V1, ECC-SECP384R1] +| config +| l +| --config + +-l +| Path to config file |=== == *certifierUtil sectigo-renew-cert options* @@ -766,6 +782,12 @@ Disabled by default - Only error messages are shown. | --requestor-email + -s | Requestor email (required for renewal) + +| config +| l +| --config + +-l +| Path to config file |=== == *certifierUtil sectigo-revoke-cert options* @@ -807,11 +829,17 @@ Disabled by default - Only error messages are shown. -s | Requestor email (required for revocation) -| revocation-reason +| revocation-request-reason | R -| --revocation-reason + +| --revocation-request-reason + -R | Revocation reason + +| config +| l +| --config + +-l +| Path to config file |=== *Configuration File* diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index 29af478..8ec8248 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -58,7 +58,6 @@ #define GET_CERT_SHORT_OPTIONS "fT:P:o:i:n:F:a:w:" #define VALIDITY_DAYS_SHORT_OPTION "t:" #define CA_PATH_SHORT_OPTION "c:" -#define SECTIGO_GET_CERT_SHORT_OPTIONS "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:S:h" #define BASE_LONG_OPTIONS \ { "help", no_argument, NULL, 'h' }, { "input-p12-path", required_argument, NULL, 'k' }, \ @@ -1379,7 +1378,7 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER, optarg); } break; - case 'e': // Certificate ID + case 'i': // Certificate ID if (optarg) { return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, optarg); } diff --git a/src/main.c b/src/main.c index 8363b96..eaa85a9 100644 --- a/src/main.c +++ b/src/main.c @@ -194,7 +194,6 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_print_helper(SECTIGO_MODE mode) #define GET_CERT_SHORT_OPTIONS "fT:P:o:i:n:F:a:w:" #define VALIDITY_DAYS_SHORT_OPTION "t:" #define CA_PATH_SHORT_OPTION "c:" -#define SECTIGO_GET_CERT_SHORT_OPTIONS "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W" #define BASE_LONG_OPTIONS \ { "help", no_argument, NULL, 'h' }, { "input-p12-path", required_argument, NULL, 'k' }, \ @@ -303,7 +302,6 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) "--group-name [value] (-G)\n" \ "--group-email [value] (-E)\n" \ "--status [value] (-S)\n" \ - "--common-name [value] (-C)\n" \ "--offset [value] (-o)\n" \ "--limit [value] (-L)\n" \ "--start-date [value] (-f)\n" \ @@ -323,14 +321,15 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) "--auth-token [value] (-K)\n" \ "--common-name [value] (-C)\n" \ "--serial-number [value] (-N)\n" \ - "--certificate-id [value] (-e)\n" \ + "--certificate-id [value] (-i)\n" \ "--requestor-email [value] (-s)\n" \ + "--config [value] (-l)\n" \ #define SECTIGO_REVOKE_CERT_HELPER \ "--auth-token [value] (-K)\n" \ "--common-name [value] (-C)\n" \ "--serial-number [value] (-N)\n" \ - "--certificate-id [value] (-e)\n" \ + "--certificate-id [value] (-i)\n" \ "--requestor-email [value] (-s)\n" \ "--revocation-request-reason [value] (-R)\n" \ "--config [value] (-l)\n" \ @@ -633,7 +632,11 @@ XPKI_CLIENT_ERROR_CODE process(XPKI_MODE mode, xc_parameter_t * xc_parameter, in } // --- Sectigo Option Table --- -static const char * const sectigo_get_cert_short_options = "C:I:e:s:N:r:b:A:x:K:u:G:E:O:J:Z:U:T:l:W:V:D:h"; +static const char * const sectigo_get_cert_short_options = "C:I:r:b:A:K:u:G:E:O:J:Z:W:V:D:l:h"; +static const char * const sectigo_search_cert_short_options = "K:C:G:E:S:o:L:f:t:i:p:q:c:a:y:m:D:W:l:h"; +static const char * const sectigo_renew_cert_short_options = "K:C:N:i:s:l:h"; +static const char * const sectigo_revoke_cert_short_options = "K:C:N:i:s:R:l:h"; + static const struct option sectigo_get_cert_long_opts[] = { { "common-name", required_argument, NULL, 'C' }, { "id", required_argument, NULL, 'I' }, @@ -653,10 +656,74 @@ static const struct option sectigo_get_cert_long_opts[] = { { "config", required_argument, NULL, 'l' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } - //make default arg '*' for san and ip - //only take in choices=['fte', 'contractor', 'associate'] }; +static const struct option sectigo_search_cert_long_opts[] = { + { "auth-token", required_argument, NULL, 'K' }, + { "common-name", required_argument, NULL, 'C' }, + { "group-name", required_argument, NULL, 'G' }, + { "group-email", required_argument, NULL, 'E' }, + { "status", required_argument, NULL, 'S' }, + { "offset", required_argument, NULL, 'o' }, + { "limit", required_argument, NULL, 'L' }, + { "start-date", required_argument, NULL, 'f' }, + { "end-date", required_argument, NULL, 't' }, + { "certificate-id", required_argument, NULL, 'i' }, + { "validity-start-date", required_argument, NULL, 'p' }, + { "validity-end-date", required_argument, NULL, 'q' }, + { "cert-order", required_argument, NULL, 'c' }, + { "is-cn-in-san", required_argument, NULL, 'a' }, + { "request-type", required_argument, NULL, 'y' }, + { "timestamp", required_argument, NULL, 'm' }, + { "devhub-id", required_argument, NULL, 'D' }, + { "key-type", required_argument, NULL, 'W' }, + { "config", required_argument, NULL, 'l' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } +}; + +static const struct option sectigo_renew_cert_long_opts[] = { + { "auth-token", required_argument, NULL, 'K' }, + { "common-name", required_argument, NULL, 'C' }, + { "serial-number", required_argument, NULL, 'N' }, + { "certificate-id", required_argument, NULL, 'i' }, + { "requestor-email", required_argument, NULL, 's' }, + { "config", required_argument, NULL, 'l' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } +}; + +static const struct option sectigo_revoke_cert_long_opts[] = { + { "auth-token", required_argument, NULL, 'K' }, + { "common-name", required_argument, NULL, 'C' }, + { "serial-number", required_argument, NULL, 'N' }, + { "certificate-id", required_argument, NULL, 'i' }, + { "requestor-email", required_argument, NULL, 's' }, + { "revocation-request-reason", required_argument, NULL, 'R' }, + { "config", required_argument, NULL, 'l' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } +}; + +static sectigo_command_opt_lut_t sectigo_command_opt_lut[] = { + { SECTIGO_MODE_GET_CERT, sectigo_get_cert_short_options, sectigo_get_cert_long_opts }, + { SECTIGO_MODE_SEARCH_CERT, sectigo_search_cert_short_options, sectigo_search_cert_long_opts }, + { SECTIGO_MODE_RENEW_CERT, sectigo_renew_cert_short_options, sectigo_renew_cert_long_opts }, + { SECTIGO_MODE_REVOKE_CERT, sectigo_revoke_cert_short_options, sectigo_revoke_cert_long_opts }, +}; + +static size_t get_sectigo_command_opt_index(sectigo_command_opt_lut_t * lut, size_t n_entries, SECTIGO_MODE mode) +{ + for (size_t i = 0; i < n_entries; ++i) + { + if (lut[i].mode == mode) + { + return i; + } + } + return 0; // fallback +} + // --- Sectigo Option Parsing --- SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t * sectigo_parameter, int argc, char ** argv) { @@ -684,9 +751,18 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t for (;;) { - int option_index; - int opt = XGETOPT_LONG(argc, argv, sectigo_get_cert_short_options, - sectigo_get_cert_long_opts, &option_index); + int option_index = 0; + int sectigo_opt_index = get_sectigo_command_opt_index( + sectigo_command_opt_lut, + sizeof(sectigo_command_opt_lut) / sizeof(*sectigo_command_opt_lut), + mode + ); + + int opt = XGETOPT_LONG(argc, argv, + sectigo_command_opt_lut[sectigo_opt_index].short_opts, + sectigo_command_opt_lut[sectigo_opt_index].long_opts, + &option_index + ); if (opt == -1 || error_code != SECTIGO_CLIENT_SUCCESS) { @@ -765,7 +841,7 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t sectigo_parameter->revoke_cert_param.serial_number = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER, optarg); break; - case 'e': + case 'i': sectigo_parameter->revoke_cert_param.certificate_id = optarg; certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, optarg); break; From 10738eed1d507d027fddc873b7845335c2c39969 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Wed, 18 Feb 2026 10:40:21 -0500 Subject: [PATCH 28/30] Consolidate help command and change a command line option --- docs/cli_usage.adoc | 14 ++++++-------- include/certifier/certifier_api_easy.h | 1 - src/certifier_api_easy.c | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index 294594c..2d8d314 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -149,8 +149,6 @@ The certificate can be downloaded through the certificate ID returned as a resul |sectigo-get-cert |Requests Certificate from Sectigo -|sectigo-help -|Provides information on implemented Sectigo commands |=== == *certifierUtil get-cert options* @@ -684,9 +682,9 @@ Disabled by default - Only error messages are shown. | End date to filter the search results (Format: YYYY-MM-DD) | certificate-id -| i +| e | --certificate-id + --i +-e | Certificate ID to filter the search results | validity-start-date @@ -772,9 +770,9 @@ Disabled by default - Only error messages are shown. | Certificate serial number (either this or certificate ID is required for renewal) | certificate-id -| i +| e | --certificate-id + --i +-e | Certificate ID (either this or serial number is required for renewal) | requestor-email @@ -818,9 +816,9 @@ Disabled by default - Only error messages are shown. | Certificate serial number (either this or certificate ID is required for revocation) | certificate-id -| i +| e | --certificate-id + --i +-e | Certificate ID (either this or serial number is required for revocation) | requestor-email diff --git a/include/certifier/certifier_api_easy.h b/include/certifier/certifier_api_easy.h index fe38562..91bd449 100644 --- a/include/certifier/certifier_api_easy.h +++ b/include/certifier/certifier_api_easy.h @@ -109,7 +109,6 @@ typedef enum CERTIFIER_MODE_SECTIGO_REVOKE_CERT, - CERTIFIER_MODE_SECTIGO_PRINT_HELP // 131072 is unused } CERTIFIER_MODE; diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index 8ec8248..d975728 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -1378,7 +1378,7 @@ static int process_command_line(CERTIFIER * easy) return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_SERIAL_NUMBER, optarg); } break; - case 'i': // Certificate ID + case 'e': // Certificate ID if (optarg) { return_code = certifier_set_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, optarg); } From 2f055e692012601e6c5b2397c17e92186c9fd548 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Thu, 19 Feb 2026 19:06:35 -0500 Subject: [PATCH 29/30] Added Sectigo OCSP status implementation --- docs/cli_usage.adoc | 22 ++ docs/configuration.adoc | 1 + include/certifier/certifier_api_easy.h | 2 + include/certifier/property.h | 1 + internal_headers/certifier/http.h | 1 + internal_headers/certifier/sectigo_client.h | 8 + internal_headers/certifier/security.h | 2 +- libcertifier.cfg.sample | 3 +- src/certifier.c | 2 +- src/certifier_api_easy.c | 39 ++- src/http.c | 6 +- src/main.c | 34 ++- src/mbedtls.c | 10 +- src/openssl.c | 40 ++- src/property.c | 11 + src/sectigo_client.c | 268 +++++++++++++++++++- tests/tests.c | 6 +- 17 files changed, 427 insertions(+), 29 deletions(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index 2d8d314..14c87cd 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -840,6 +840,28 @@ Disabled by default - Only error messages are shown. | Path to config file |=== +== *certifierUtil sectigo-ocsp-status options* +|=== +| *Long Option* | *Short Option* | *Examples* | *Description* +| help +| h +| --help + +-h +| Display this summary + +| cert-path +| j +| --cert-path + +-j +| Path to the certificate file (PEM format) + +| config +| l +| --config + +-l + +| Path to config file +|=== + *Configuration File* Configuration File is a file used to specify internal certifier util parameters such as timeouts, ecc curve types and other miscellaneous items. This file follows the JSON Format and can be manually editted from the `libcertifier.cfg.sample` template file present in the root directory. diff --git a/docs/configuration.adoc b/docs/configuration.adoc index 2607818..6708027 100644 --- a/docs/configuration.adoc +++ b/docs/configuration.adoc @@ -61,6 +61,7 @@ xref:libcertifier.adoc[*Back to Manual*] | libcertifier.sectigo.is.cn.in.san | | | libcertifier.sectigo.request.type | | | libcertifier.sectigo.timestamp | | +| libcertifier.cert.path | | |======= == Extended Key Usage values: diff --git a/include/certifier/certifier_api_easy.h b/include/certifier/certifier_api_easy.h index 91bd449..216f5db 100644 --- a/include/certifier/certifier_api_easy.h +++ b/include/certifier/certifier_api_easy.h @@ -108,6 +108,8 @@ typedef enum CERTIFIER_MODE_SECTIGO_RENEW_CERT, CERTIFIER_MODE_SECTIGO_REVOKE_CERT, + + CERTIFIER_MODE_SECTIGO_OCSP_STATUS, // 131072 is unused } CERTIFIER_MODE; diff --git a/include/certifier/property.h b/include/certifier/property.h index 025747e..7ee6633 100644 --- a/include/certifier/property.h +++ b/include/certifier/property.h @@ -233,6 +233,7 @@ typedef enum CERTIFIER_OPT CERTIFIER_OPT_SECTIGO_IS_CN_IN_SAN, CERTIFIER_OPT_SECTIGO_REQUEST_TYPE, CERTIFIER_OPT_SECTIGO_TIMESTAMP, + CERTIFIER_OPT_SECTIGO_CERT_PATH } CERTIFIER_OPT; diff --git a/internal_headers/certifier/http.h b/internal_headers/certifier/http.h index 0f49012..f081edd 100644 --- a/internal_headers/certifier/http.h +++ b/internal_headers/certifier/http.h @@ -41,6 +41,7 @@ typedef struct http_response { const char * error_msg; const char * payload; + size_t payload_len; int http_code; int error; } http_response; diff --git a/internal_headers/certifier/sectigo_client.h b/internal_headers/certifier/sectigo_client.h index 5b0180b..b56c7f2 100644 --- a/internal_headers/certifier/sectigo_client.h +++ b/internal_headers/certifier/sectigo_client.h @@ -92,6 +92,10 @@ typedef struct { const char * revocation_request_reason; } sectigo_revoke_cert_param_t; +typedef struct { + const char * certificate_path; +} sectigo_ocsp_status_param_t; + typedef enum { SECTIGO_CLIENT_SUCCESS = 0, SECTIGO_CLIENT_INVALID_ARGUMENT, @@ -114,6 +118,8 @@ CertifierError sectigo_client_renew_certificate(CertifierPropMap * props); CertifierError sectigo_client_revoke_certificate(CertifierPropMap * props); +CertifierError sectigo_client_ocsp_status(CertifierPropMap * props); + CertifierError sectigo_generate_certificate_signing_request(Certifier *certifier, char **out_csr_pem); Certifier * get_sectigo_certifier_instance(); @@ -126,6 +132,8 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_renew_cert(sectigo_renew_cert_param_t * par SECTIGO_CLIENT_ERROR_CODE xc_sectigo_revoke_cert(sectigo_revoke_cert_param_t * params); +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_ocsp_status(sectigo_ocsp_status_param_t * params); + SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_cert_param(sectigo_get_cert_param_t * params); SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_default_renew_cert_param(sectigo_renew_cert_param_t * params); diff --git a/internal_headers/certifier/security.h b/internal_headers/certifier/security.h index bea4030..943572a 100644 --- a/internal_headers/certifier/security.h +++ b/internal_headers/certifier/security.h @@ -199,7 +199,7 @@ X509_CERT * security_cert_list_get(X509_LIST * certs, int which); */ X509_CERT * security_cert_list_pop(X509_LIST * certs, int which); -CertifierError security_load_certs_from_pem(const char * pem, X509_LIST ** out); +CertifierError security_load_certs_from_pem(const char * pem, X509_LIST ** out, bool load_all_certs); void security_print_certs_in_list(X509_LIST * certs, XFILE output); diff --git a/libcertifier.cfg.sample b/libcertifier.cfg.sample index d68a1ca..8983604 100644 --- a/libcertifier.cfg.sample +++ b/libcertifier.cfg.sample @@ -54,5 +54,6 @@ "libcertifier.sectigo.cert.order": "", "libcertifier.sectigo.is.cn.in.san": "", "libcertifier.sectigo.request.type": "", - "libcertifier.sectigo.timestamp": "" + "libcertifier.sectigo.timestamp": "", + "libcertifier.sectigo.cert.path": "" } diff --git a/src/certifier.c b/src/certifier.c index 4d7c904..04a3fa2 100644 --- a/src/certifier.c +++ b/src/certifier.c @@ -393,7 +393,7 @@ static int save_x509certs_to_filesystem(Certifier * certifier, char * x509_certs util_trim(x509_certs); log_info("\nLoading Certs from PKCS7...\n"); - certifier_err_info = security_load_certs_from_pem(x509_certs, &certs); + certifier_err_info = security_load_certs_from_pem(x509_certs, &certs, false); assign_last_error(certifier, &certifier_err_info); rc = certifier_err_info.application_error_code; if (certifier_err_info.application_error_code != 0) diff --git a/src/certifier_api_easy.c b/src/certifier_api_easy.c index d975728..2f8368a 100644 --- a/src/certifier_api_easy.c +++ b/src/certifier_api_easy.c @@ -147,6 +147,11 @@ { "revocation-request-reason", required_argument, NULL, 'R' }, \ { "config", required_argument, NULL, 'l' }, \ { NULL, 0, NULL, 0 } + +#define SECTIGO_OCSP_STATUS_LONG_OPTIONS \ + { "cert-path", required_argument, NULL, 'j' }, \ + { "config", required_argument, NULL, 'l' }, \ + { NULL, 0, NULL, 0 } static void finish_operation(CERTIFIER * easy, int return_code, const char * operation_output); @@ -366,6 +371,7 @@ CERTIFIER_MODE certifier_api_easy_get_mode(CERTIFIER * easy) { "sectigo-search-cert", CERTIFIER_MODE_SECTIGO_SEARCH_CERT}, { "sectigo-renew-cert", CERTIFIER_MODE_SECTIGO_RENEW_CERT}, { "sectigo-revoke-cert", CERTIFIER_MODE_SECTIGO_REVOKE_CERT}, + { "sectigo-ocsp-status", CERTIFIER_MODE_SECTIGO_OCSP_STATUS} }; for (int i = 0; i < sizeof(command_map) / sizeof(command_map_t); ++i) @@ -927,6 +933,29 @@ static int do_sectigo_revoke_cert(CERTIFIER * easy) } } +static int do_sectigo_ocsp_status(CERTIFIER * easy) +{ + // Check for required Sectigo properties + const char *cert_path = certifier_get_property(easy->certifier, CERTIFIER_OPT_SECTIGO_CERT_PATH); + if (util_is_empty(cert_path)) { + finish_operation(easy, CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1, "Missing required Sectigo flag: cert-path"); + return CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + } + + // Call Sectigo API to check OCSP status + CertifierPropMap * props = certifier_easy_api_get_props(easy->certifier); + CertifierError rc = sectigo_client_ocsp_status(props); + + //Handle result + if (rc.application_error_code == 0) { + finish_operation(easy, 0, rc.application_error_msg); + return 0; + } else { + finish_operation(easy, rc.application_error_code, rc.application_error_msg); + return rc.application_error_code; + } +} + char * certifier_api_easy_get_version(CERTIFIER * easy) { @@ -971,6 +1000,7 @@ int certifier_api_easy_print_helper(CERTIFIER * easy) "sectigo-search-cert\n" "sectigo-renew-cert\n" "sectigo-revoke-cert\n" + "sectigo-ocsp-status\n" ); } @@ -1025,6 +1055,7 @@ static int process_command_line(CERTIFIER * easy) static const char * const sectigo_search_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; static const char * const sectigo_renew_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; static const char * const sectigo_revoke_cert_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; + static const char * const sectigo_ocsp_status_short_options = BASE_SHORT_OPTIONS CA_PATH_SHORT_OPTION; static const struct option get_cert_long_opts[] = { BASE_LONG_OPTIONS, GET_CRT_TOKEN_LONG_OPTIONS, GET_CERT_LONG_OPTIONS, VALIDITY_DAYS_LONG_OPTION, @@ -1038,6 +1069,7 @@ static int process_command_line(CERTIFIER * easy) static const struct option sectigo_search_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_SEARCH_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; static const struct option sectigo_renew_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_RENEW_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; static const struct option sectigo_revoke_cert_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_REVOKE_CERT_LONG_OPTIONS, {NULL, 0, NULL, 0}}; + static const struct option sectigo_ocsp_status_long_opts[] = {BASE_LONG_OPTIONS, SECTIGO_OCSP_STATUS_LONG_OPTIONS, {NULL, 0, NULL, 0}}; static command_opt_lut_t command_opt_lut[] = { { CERTIFIER_MODE_REGISTER, get_cert_short_options, get_cert_long_opts }, @@ -1049,7 +1081,8 @@ static int process_command_line(CERTIFIER * easy) { CERTIFIER_MODE_SECTIGO_GET_CERT, sectigo_get_cert_short_options, sectigo_get_cert_long_opts}, { CERTIFIER_MODE_SECTIGO_SEARCH_CERT, sectigo_search_cert_short_options, sectigo_search_cert_long_opts}, { CERTIFIER_MODE_SECTIGO_RENEW_CERT, sectigo_renew_cert_short_options, sectigo_renew_cert_long_opts}, - { CERTIFIER_MODE_SECTIGO_REVOKE_CERT, sectigo_revoke_cert_short_options, sectigo_revoke_cert_long_opts} + { CERTIFIER_MODE_SECTIGO_REVOKE_CERT, sectigo_revoke_cert_short_options, sectigo_revoke_cert_long_opts}, + { CERTIFIER_MODE_SECTIGO_OCSP_STATUS, sectigo_ocsp_status_short_options, sectigo_ocsp_status_long_opts} }; char * version_string = certifier_api_easy_get_version(easy); @@ -1680,6 +1713,10 @@ switch(easy -> mode){ do_sectigo_revoke_cert(easy); break; + case CERTIFIER_MODE_SECTIGO_OCSP_STATUS: + do_sectigo_ocsp_status(easy); + break; + default: finish_operation(easy, -1, "Invalid mode"); break; diff --git a/src/http.c b/src/http.c index dff6aa0..0113597 100644 --- a/src/http.c +++ b/src/http.c @@ -119,11 +119,12 @@ static http_response * http_error_response(const char * msg, int error_code, int resp->error = error_code; resp->error_msg = XSTRDUP(msg); resp->http_code = http_code; + resp->payload_len = 0; } return resp; } -static http_response * http_success_response(const char * payload, int http_code, const char * errbuf, int err_code) +static http_response * http_success_response(const char * payload, size_t payload_len, int http_code, const char * errbuf, int err_code) { http_response * resp = XCALLOC(1, sizeof(http_response)); if (resp != NULL) @@ -132,6 +133,7 @@ static http_response * http_success_response(const char * payload, int http_code resp->error_msg = XSTRDUP(errbuf); resp->http_code = http_code; resp->payload = payload; // struct takes ownership of payload + resp->payload_len = payload_len; } return resp; } @@ -239,7 +241,7 @@ static http_response * do_http(const CertifierPropMap * props, const char * url, } else { log_debug("do_http returned: %s", cf->payload); } - return http_success_response(cf->payload, http_code, errbuf, res); + return http_success_response(cf->payload, cf->size, http_code, errbuf, res); // log_debug("do_http returned: %s", cf->payload); // return http_success_response(cf->payload, http_code, errbuf, res); } diff --git a/src/main.c b/src/main.c index eaa85a9..444f557 100644 --- a/src/main.c +++ b/src/main.c @@ -44,6 +44,7 @@ typedef enum SECTIGO_MODE_SEARCH_CERT, SECTIGO_MODE_RENEW_CERT, SECTIGO_MODE_REVOKE_CERT, + SECTIGO_MODE_OCSP_STATUS, SECTIGO_MODE_PRINT_HELP } SECTIGO_MODE; @@ -61,6 +62,7 @@ typedef union sectigo_search_cert_param_t search_cert_param; sectigo_renew_cert_param_t renew_cert_param; sectigo_revoke_cert_param_t revoke_cert_param; + sectigo_ocsp_status_param_t ocsp_status_param; } sectigo_parameter_t; @@ -123,7 +125,8 @@ SECTIGO_MODE sectigo_get_mode(int argc, char ** argv){ {"sectigo-get-cert", SECTIGO_MODE_GET_CERT}, {"sectigo-search-cert", SECTIGO_MODE_SEARCH_CERT}, {"sectigo-renew-cert", SECTIGO_MODE_RENEW_CERT}, - {"sectigo-revoke-cert", SECTIGO_MODE_REVOKE_CERT} + {"sectigo-revoke-cert", SECTIGO_MODE_REVOKE_CERT}, + {"sectigo-ocsp-status", SECTIGO_MODE_OCSP_STATUS} }; for(int i = 0; i < sizeof(command_map) / sizeof(command_map_t); ++i){ @@ -169,6 +172,7 @@ XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) "sectigo-search-cert\n" "sectigo-renew-cert\n" "sectigo-revoke-cert\n" + "sectigo-ocsp-status\n" "sectigo-help\n"); } @@ -334,6 +338,10 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) "--revocation-request-reason [value] (-R)\n" \ "--config [value] (-l)\n" \ +#define SECTIGO_OCSP_STATUS_HELPER \ + "--cert-path [value] (-j)\n" \ + "--config [value] (-l)\n" \ + switch (mode) { case SECTIGO_MODE_GET_CERT: @@ -344,6 +352,8 @@ static const char * get_sectigo_command_opt_helper(SECTIGO_MODE mode) return SECTIGO_BASE_HELPER SECTIGO_RENEW_CERT_HELPER; case SECTIGO_MODE_REVOKE_CERT: return SECTIGO_BASE_HELPER SECTIGO_REVOKE_CERT_HELPER; + case SECTIGO_MODE_OCSP_STATUS: + return SECTIGO_BASE_HELPER SECTIGO_OCSP_STATUS_HELPER; case SECTIGO_MODE_PRINT_HELP: return SECTIGO_BASE_HELPER; default: @@ -636,6 +646,7 @@ static const char * const sectigo_get_cert_short_options = "C:I:r:b:A:K:u:G:E:O: static const char * const sectigo_search_cert_short_options = "K:C:G:E:S:o:L:f:t:i:p:q:c:a:y:m:D:W:l:h"; static const char * const sectigo_renew_cert_short_options = "K:C:N:i:s:l:h"; static const char * const sectigo_revoke_cert_short_options = "K:C:N:i:s:R:l:h"; +static const char * const sectigo_ocsp_status_short_options = "j:l:h"; static const struct option sectigo_get_cert_long_opts[] = { { "common-name", required_argument, NULL, 'C' }, @@ -705,11 +716,19 @@ static const struct option sectigo_revoke_cert_long_opts[] = { { NULL, 0, NULL, 0 } }; +static const struct option sectigo_ocsp_status_long_opts[] = { + { "cert-path", required_argument, NULL, 'j' }, + { "config", required_argument, NULL, 'l' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } +}; + static sectigo_command_opt_lut_t sectigo_command_opt_lut[] = { { SECTIGO_MODE_GET_CERT, sectigo_get_cert_short_options, sectigo_get_cert_long_opts }, { SECTIGO_MODE_SEARCH_CERT, sectigo_search_cert_short_options, sectigo_search_cert_long_opts }, { SECTIGO_MODE_RENEW_CERT, sectigo_renew_cert_short_options, sectigo_renew_cert_long_opts }, { SECTIGO_MODE_REVOKE_CERT, sectigo_revoke_cert_short_options, sectigo_revoke_cert_long_opts }, + { SECTIGO_MODE_OCSP_STATUS, sectigo_ocsp_status_short_options, sectigo_ocsp_status_long_opts }, }; static size_t get_sectigo_command_opt_index(sectigo_command_opt_lut_t * lut, size_t n_entries, SECTIGO_MODE mode) @@ -737,10 +756,11 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t ReturnErrorOnFailure(xc_sectigo_get_default_cert_param(§igo_parameter->get_cert_param)); break; case SECTIGO_MODE_SEARCH_CERT: - // No default parameters to set for search cert, so just break + case SECTIGO_MODE_OCSP_STATUS: + // No default parameters to set for search cert or OCSP status, so just break break; case SECTIGO_MODE_RENEW_CERT: - ReturnErrorOnFailure(xc_sectigo_get_default_renew_cert_param(§igo_parameter->get_cert_param)); + ReturnErrorOnFailure(xc_sectigo_get_default_renew_cert_param(§igo_parameter->renew_cert_param)); break; case SECTIGO_MODE_REVOKE_CERT: ReturnErrorOnFailure(xc_sectigo_get_default_revoke_cert_param(§igo_parameter->revoke_cert_param)); @@ -864,7 +884,7 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t case 't': certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_END_DATE, optarg); break; - case 'i': + case 'e': certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERTIFICATE_ID, optarg); break; case 'p': @@ -885,6 +905,9 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_process(SECTIGO_MODE mode, sectigo_parameter_t case 'm': certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_TIMESTAMP, optarg); break; + case 'j': + certifier_set_property(get_sectigo_certifier_instance(), CERTIFIER_OPT_SECTIGO_CERT_PATH, optarg); + break; case '?': log_info("Invalid or missing Sectigo option\n"); error_code = SECTIGO_CLIENT_INVALID_ARGUMENT; @@ -926,6 +949,9 @@ SECTIGO_CLIENT_ERROR_CODE sectigo_perform(int argc, char ** argv) case SECTIGO_MODE_REVOKE_CERT: return xc_sectigo_revoke_cert(§igo_parameter.revoke_cert_param); break; + case SECTIGO_MODE_OCSP_STATUS: + return xc_sectigo_ocsp_status(§igo_parameter.ocsp_status_param); + break; default: break; } diff --git a/src/mbedtls.c b/src/mbedtls.c index 3589d37..cf2e0d9 100644 --- a/src/mbedtls.c +++ b/src/mbedtls.c @@ -2422,7 +2422,7 @@ static CertifierError load_certs_from_pkcs7(const char * pkcs7, X509_LIST ** out return result; } -CertifierError load_certs_from_certificate(const char * pem, X509_LIST ** out) +CertifierError load_certs_from_certificate(const char * pem, X509_LIST ** out, bool load_all_certs) { CertifierError result = CERTIFIER_ERROR_INITIALIZER; error_clear(&result); @@ -2433,6 +2433,10 @@ CertifierError load_certs_from_certificate(const char * pem, X509_LIST ** out) return result; } + // Note: mbedtls implementation currently only supports single certificate loading + // The load_all_certs parameter is accepted for API compatibility but not yet implemented + (void)load_all_certs; + X509_LIST * certs = NULL; mbedtls_pem_context pem_ctx; @@ -2488,7 +2492,7 @@ CertifierError load_certs_from_certificate(const char * pem, X509_LIST ** out) return result; } -CertifierError security_load_certs_from_pem(const char * pem, X509_LIST ** out) +CertifierError security_load_certs_from_pem(const char * pem, X509_LIST ** out, bool load_all_certs) { CertifierError result = CERTIFIER_ERROR_INITIALIZER; if (XSTRSTR(pem, "-----BEGIN PKCS7-----")) @@ -2497,7 +2501,7 @@ CertifierError security_load_certs_from_pem(const char * pem, X509_LIST ** out) } else if (XSTRSTR(pem, "-----BEGIN CERTIFICATE-----")) { - result = load_certs_from_certificate(pem, out); + result = load_certs_from_certificate(pem, out, load_all_certs); } else { diff --git a/src/openssl.c b/src/openssl.c index 0d2036c..1182830 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -1241,7 +1241,7 @@ CertifierError load_certs_from_pkcs7(const char * pkcs7, X509_LIST ** out) return result; } -CertifierError load_certs_from_certificate(const char * pem, X509_LIST ** out) +CertifierError load_certs_from_certificate(const char * pem, X509_LIST ** out, bool load_all_certs) { CertifierError result = CERTIFIER_ERROR_INITIALIZER; @@ -1259,20 +1259,38 @@ CertifierError load_certs_from_certificate(const char * pem, X509_LIST ** out) BIO * cert_bio = BIO_new(BIO_s_mem()); BIO_write(cert_bio, pem, cert_len); - cert = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL); - if (!cert) - { - result.application_error_msg = util_format_error(__func__, "Unable to parse certificate!", __FILE__, __LINE__); - goto cleanup; - } - + certs = sk_X509_new_null(); if (certs == NULL) { result.application_error_msg = util_format_error(__func__, "Unable to call sk_X509_new_null!", __FILE__, __LINE__); goto cleanup; } - sk_X509_push(certs, cert); + + if (load_all_certs) + { + // Read all certificates (i.e. for OCSP) + while ((cert = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL)) != NULL) + { + sk_X509_push(certs, cert); + } + } + else + { + // Legacy behavior loading only the first certificate from the chain + cert = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL); + if (cert != NULL) + { + sk_X509_push(certs, cert); + } + } + + // Check if we read at least one certificate + if (sk_X509_num(certs) == 0) + { + result.application_error_msg = util_format_error(__func__, "Unable to parse any certificates!", __FILE__, __LINE__); + goto cleanup; + } cleanup: BIO_free(cert_bio); @@ -1286,7 +1304,7 @@ CertifierError load_certs_from_certificate(const char * pem, X509_LIST ** out) return result; } -CertifierError security_load_certs_from_pem(const char * pem, X509_LIST ** out) +CertifierError security_load_certs_from_pem(const char * pem, X509_LIST ** out, bool load_all_certs) { CertifierError result = CERTIFIER_ERROR_INITIALIZER; if (XSTRSTR(pem, "-----BEGIN PKCS7-----")) @@ -1295,7 +1313,7 @@ CertifierError security_load_certs_from_pem(const char * pem, X509_LIST ** out) } else if (XSTRSTR(pem, "-----BEGIN CERTIFICATE-----")) { - result = load_certs_from_certificate(pem, out); + result = load_certs_from_certificate(pem, out, load_all_certs); } else { diff --git a/src/property.c b/src/property.c index bf52c17..8ce7b1d 100644 --- a/src/property.c +++ b/src/property.c @@ -252,6 +252,7 @@ struct _PropMap char * is_cn_in_san; char * request_type; char * timestamp; + char * cert_path; }; static void free_prop_map_values(CertifierPropMap * prop_map); @@ -490,6 +491,9 @@ int sectigo_property_set(CertifierPropMap * prop_map, int name, const void * val case CERTIFIER_OPT_SECTIGO_TIMESTAMP: prop_map->timestamp = XSTRDUP((const char *)value); break; + case CERTIFIER_OPT_SECTIGO_CERT_PATH: + prop_map->cert_path = XSTRDUP((const char *)value); + break; default: log_warn("sectigo_property_set: unrecognized property [%d]", name); retval = CERTIFIER_ERR_PROPERTY_SET_10; @@ -1047,6 +1051,9 @@ void * property_get(CertifierPropMap * prop_map, CERTIFIER_OPT name) case CERTIFIER_OPT_SECTIGO_TIMESTAMP: retval = (void *) prop_map->timestamp; break; + case CERTIFIER_OPT_SECTIGO_CERT_PATH: + retval = (void *) prop_map->cert_path; + break; default: log_warn("property_get: unrecognized property [%d]", name); retval = NULL; @@ -1644,6 +1651,10 @@ static int load_sectigo_fields_from_json(CertifierPropMap *propMap, JSON_Object log_info("Loaded sectigo timestamp: %s from config file.", value_str); sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_TIMESTAMP, value_str); } + else if (strcmp(key, "libcertifier.sectigo.cert.path") == 0) { + log_info("Loaded sectigo cert path: %s from config file.", value_str); + sectigo_property_set(propMap, CERTIFIER_OPT_SECTIGO_CERT_PATH, value_str); + } } } diff --git a/src/sectigo_client.c b/src/sectigo_client.c index 1bee629..1da3eed 100644 --- a/src/sectigo_client.c +++ b/src/sectigo_client.c @@ -30,9 +30,21 @@ #include "certifier/error.h" #include "certifier/property_internal.h" + +#include +#include +#include +#include +#include + +#include + #include #include #include +#include +#include +#include Certifier * get_sectigo_certifier_instance() { @@ -444,8 +456,6 @@ CertifierError sectigo_client_search_certificates(CertifierPropMap * props) goto cleanup; } - sectigo_search_cert_param_t params; - int first_param = 1; // Used to determine whether to prepend '?' or '&' for query parameters append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "groupName", property_get(props, CERTIFIER_OPT_SECTIGO_GROUP_NAME), &first_param); append_query_param(sectigo_search_cert_url, sizeof(sectigo_search_cert_url), "groupEmailAddress", property_get(props, CERTIFIER_OPT_SECTIGO_GROUP_EMAIL), &first_param); @@ -787,6 +797,249 @@ CertifierError sectigo_client_revoke_certificate(CertifierPropMap * props) return rc; } +CertifierError sectigo_client_ocsp_status(CertifierPropMap * props) +{ + CertifierError rc = CERTIFIER_ERROR_INITIALIZER; + const char *pem_path = property_get(props, CERTIFIER_OPT_SECTIGO_CERT_PATH); + if (!pem_path) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Missing cert_path property"); + return rc; + } + + // Read PEM file into memory + FILE *fp = fopen(pem_path, "rb"); + if (!fp) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + char err_msg[512]; + snprintf(err_msg, sizeof(err_msg), "Unable to open PEM file: %s (errno=%d: %s)", + pem_path, errno, strerror(errno)); + rc.application_error_msg = util_format_error_here(err_msg); + log_error("%s", err_msg); + return rc; + } + log_info("PEM file opened successfully, reading content..."); + fseek(fp, 0, SEEK_END); + long fsize = ftell(fp); + fseek(fp, 0, SEEK_SET); + char *pem_buf = (char *)XMALLOC(fsize + 1); + if (!pem_buf) { + fclose(fp); + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Memory allocation failed"); + return rc; + } + fread(pem_buf, 1, fsize, fp); + pem_buf[fsize] = '\0'; + fclose(fp); + + // Load certs from PEM + log_info("Parsing PEM buffer..."); + X509_LIST *certs = NULL; + rc = security_load_certs_from_pem(pem_buf, &certs, true); + XFREE(pem_buf); + if (rc.application_error_code != 0 || !certs) { + if (!rc.application_error_msg) + rc.application_error_msg = util_format_error_here("Failed to parse PEM certs"); + log_error("Failed to load certs from PEM: error_code=%d", rc.application_error_code); + return rc; + } + + // Extract leaf and intermediate certs + log_info("Extracting leaf and intermediate certificates..."); + int cert_count = sk_X509_num(certs); + X509 *leaf = sk_X509_value(certs, cert_count - 1); + X509 *issuer = cert_count > 1 ? sk_X509_value(certs, cert_count - 2) : NULL; + if (!leaf || !issuer) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("PEM must contain at least leaf and intermediate cert"); + security_free_cert_list(certs); + return rc; + } + + // Extract AIA OCSP URL from leaf cert + log_info("Extracting OCSP URL from AIA extension..."); + STACK_OF(OPENSSL_STRING) *ocsp_urls = X509_get1_ocsp(leaf); + if (!ocsp_urls || sk_OPENSSL_STRING_num(ocsp_urls) == 0) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("No OCSP URL found in AIA extension"); + if (ocsp_urls) X509_email_free(ocsp_urls); // X509_email_free works for OCSP URLs too + security_free_cert_list(certs); + return rc; + } + const char *ocsp_url = sk_OPENSSL_STRING_value(ocsp_urls, 0); + log_info("OCSP URL extracted from AIA: %s", ocsp_url); + + // Build OCSP request + OCSP_CERTID *id = OCSP_cert_to_id(NULL, leaf, issuer); + if (!id) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Failed to create OCSP_CERTID"); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + return rc; + } + OCSP_REQUEST *req = OCSP_REQUEST_new(); + if (!req || !OCSP_request_add0_id(req, id)) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Failed to create OCSP_REQUEST"); + if (req) OCSP_REQUEST_free(req); + OCSP_CERTID_free(id); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + return rc; + } + + // Serialize OCSP request + unsigned char *req_der = NULL; + int req_der_len = i2d_OCSP_REQUEST(req, &req_der); + if (req_der_len <= 0) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Failed to encode OCSP request"); + OCSP_REQUEST_free(req); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + return rc; + } + + // Base64 encode the OCSP request + int base64_len = base64_encode_len(req_der_len); + char *base64_req = (char *)XMALLOC(base64_len + 1); + if (!base64_req) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Memory allocation failed for base64 encoding"); + OPENSSL_free(req_der); + OCSP_REQUEST_free(req); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + return rc; + } + base64_encode(base64_req, req_der, req_der_len); + base64_req[base64_len] = '\0'; + + // URL-encode the base64 string using curl_easy_escape + CURL *curl = curl_easy_init(); + if (!curl) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Failed to initialize CURL for URL encoding"); + XFREE(base64_req); + OPENSSL_free(req_der); + OCSP_REQUEST_free(req); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + return rc; + } + + char *url_encoded = curl_easy_escape(curl, base64_req, 0); + curl_easy_cleanup(curl); + + if (!url_encoded) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("URL encoding failed"); + XFREE(base64_req); + OPENSSL_free(req_der); + OCSP_REQUEST_free(req); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + return rc; + } + + // Build OCSP GET URL + char ocsp_get_url[4096]; + snprintf(ocsp_get_url, sizeof(ocsp_get_url), "%s/%s", ocsp_url, url_encoded); + + // Send OCSP GET request + http_response *resp = NULL; + resp = http_get(props, ocsp_get_url, NULL); + curl_free(url_encoded); // Free the curl-allocated string + XFREE(base64_req); + + if (!resp || !resp->payload) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Failed to get OCSP response"); + if (req_der) OPENSSL_free(req_der); + OCSP_REQUEST_free(req); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + return rc; + } + + // Parse OCSP response (response is binary DER) + const unsigned char *p = (const unsigned char *)resp->payload; + long resp_len = (long)resp->payload_len; + + if (resp->http_code != 200) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + char err_msg[512]; + snprintf(err_msg, sizeof(err_msg), "Invalid OCSP response: HTTP %d", resp->http_code); + rc.application_error_msg = util_format_error_here(err_msg); + if (req_der) OPENSSL_free(req_der); + OCSP_REQUEST_free(req); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + http_free_response(resp); + return rc; + } + + OCSP_RESPONSE *ocsp_resp = d2i_OCSP_RESPONSE(NULL, &p, resp_len); + if (!ocsp_resp) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Failed to parse OCSP response"); + if (req_der) OPENSSL_free(req_der); + OCSP_REQUEST_free(req); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + http_free_response(resp); + return rc; + } + + int status = OCSP_response_status(ocsp_resp); + if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("OCSP response not successful"); + } else { + OCSP_BASICRESP *basic = OCSP_response_get1_basic(ocsp_resp); + if (!basic) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + rc.application_error_msg = util_format_error_here("Failed to parse OCSP_BASICRESP"); + } else { + int cert_status, crl_reason; + ASN1_GENERALIZEDTIME *revtime, *thisupd, *nextupd; + cert_status = OCSP_single_get0_status( + OCSP_resp_get0(basic, 0), &crl_reason, &revtime, &thisupd, &nextupd); + + const char *status_str = OCSP_cert_status_str(cert_status); + char msg[512]; + + if (cert_status == V_OCSP_CERTSTATUS_GOOD) { + rc.application_error_code = 0; + snprintf(msg, sizeof(msg), "Certificate status: %s", status_str); + rc.application_error_msg = util_format_error_here(msg); + log_info("%s", msg); + } else if (cert_status == V_OCSP_CERTSTATUS_REVOKED) { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + snprintf(msg, sizeof(msg), "Certificate status: %s (reason=%d)", status_str, crl_reason); + rc.application_error_msg = util_format_error_here(msg); + log_error("%s", msg); + } else { + rc.application_error_code = CERTIFIER_ERR_EMPTY_OR_INVALID_PARAM_1; + snprintf(msg, sizeof(msg), "Certificate status: %s", status_str); + rc.application_error_msg = util_format_error_here(msg); + log_warn("%s", msg); + } + OCSP_BASICRESP_free(basic); + } + } + + OCSP_RESPONSE_free(ocsp_resp); + if (req_der) OPENSSL_free(req_der); + OCSP_REQUEST_free(req); + X509_email_free(ocsp_urls); + security_free_cert_list(certs); + http_free_response(resp); + return rc; +} + SECTIGO_CLIENT_ERROR_CODE xc_sectigo_get_cert(sectigo_get_cert_param_t * params) { Certifier *certifier = get_sectigo_certifier_instance(); @@ -897,3 +1150,14 @@ SECTIGO_CLIENT_ERROR_CODE xc_sectigo_revoke_cert(sectigo_revoke_cert_param_t * p return req_rc.application_error_code; } + +SECTIGO_CLIENT_ERROR_CODE xc_sectigo_ocsp_status(sectigo_ocsp_status_param_t * params) +{ + Certifier *certifier = get_sectigo_certifier_instance(); + + // Call the request function + CertifierPropMap *props = certifier_get_prop_map(certifier); + CertifierError req_rc = sectigo_client_ocsp_status(props); + + return req_rc.application_error_code; +} diff --git a/tests/tests.c b/tests/tests.c index 3b5d9fc..929d5e7 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -1021,7 +1021,7 @@ void test_x509_cert(void) char * cert3_ou = NULL; // try cert only format - CertifierError rc = security_load_certs_from_pem(ejbca_with_hsm_pem_cert_only_blob, &cert_list); + CertifierError rc = security_load_certs_from_pem(ejbca_with_hsm_pem_cert_only_blob, &cert_list, false); assert_int_equal(0, rc.application_error_code); assert_non_null(cert_list); cert1 = security_cert_list_get(cert_list, 0); @@ -1033,7 +1033,7 @@ void test_x509_cert(void) cert_list = NULL; // try ejbca pkcs7 format - rc = security_load_certs_from_pem(ejbca_with_hsm_pem_pkcs7_blob, &cert_list); + rc = security_load_certs_from_pem(ejbca_with_hsm_pem_pkcs7_blob, &cert_list, false); assert_int_equal(0, rc.application_error_code); assert_non_null(cert_list); cert1 = security_cert_list_get(cert_list, 0); @@ -1045,7 +1045,7 @@ void test_x509_cert(void) cert_list = NULL; // try digicert pkcs7 format (original tests) - rc = security_load_certs_from_pem(digicert_pem_pkcs7_blob, &cert_list); + rc = security_load_certs_from_pem(digicert_pem_pkcs7_blob, &cert_list, false); assert_int_equal(0, rc.application_error_code); assert_non_null(cert_list); From 5a3128cc991aa50f037b19031e40060042e46664 Mon Sep 17 00:00:00 2001 From: Russell Benjamin Date: Thu, 19 Feb 2026 19:13:20 -0500 Subject: [PATCH 30/30] Update docs and some cleanup --- docs/cli_usage.adoc | 25 ++++++++++++++----------- src/main.c | 3 +-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/cli_usage.adoc b/docs/cli_usage.adoc index 14c87cd..bf25585 100644 --- a/docs/cli_usage.adoc +++ b/docs/cli_usage.adoc @@ -108,15 +108,6 @@ Same command with SAT authentication: ./certifierUtil print-cert -k -p ---- -*Fetch Sectigo Certificate* - -The certificate can be downloaded through the certificate ID returned as a result of running the command. - ----- -./certifierUtil sectigo-get-cert -C -I -r -b -A -G -E -O -J --Z -K -u -l ----- - == *certifierUtil commands* |=== @@ -146,8 +137,20 @@ The certificate can be downloaded through the certificate ID returned as a resul | revoke | Revoke Certificate -|sectigo-get-cert -|Requests Certificate from Sectigo +| sectigo-get-cert +| Fetch Certificate from Sectigo + +| sectigo-search-cert +| Search for certificates issued by Sectigo using various filters + +| sectigo-renew-cert +| Renew a Sectigo certificate if not expired, and meets renew requirements + +| sectigo-revoke-cert +| Revoke a Sectigo certificate + +| sectigo-ocsp-status +| Check OCSP status of a Sectigo certificate |=== diff --git a/src/main.c b/src/main.c index 444f557..039da52 100644 --- a/src/main.c +++ b/src/main.c @@ -121,7 +121,6 @@ SECTIGO_MODE sectigo_get_mode(int argc, char ** argv){ } command_map_t; command_map_t command_map[] = { - {"sectigo-help", SECTIGO_MODE_PRINT_HELP}, {"sectigo-get-cert", SECTIGO_MODE_GET_CERT}, {"sectigo-search-cert", SECTIGO_MODE_SEARCH_CERT}, {"sectigo-renew-cert", SECTIGO_MODE_RENEW_CERT}, @@ -173,7 +172,7 @@ XPKI_CLIENT_ERROR_CODE xpki_print_helper(XPKI_MODE mode) "sectigo-renew-cert\n" "sectigo-revoke-cert\n" "sectigo-ocsp-status\n" - "sectigo-help\n"); + ); } return XPKI_CLIENT_SUCCESS;