From cfd1242099d3095bb4e628856fc1e7d4d85d22f0 Mon Sep 17 00:00:00 2001 From: "Chamkura, Preetam" Date: Tue, 29 Jul 2025 09:15:14 -0400 Subject: [PATCH 01/10] 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 0d85fff6f6d333252ec089c168c1df348be345c3 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/10] 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 b76becf8438c615b7e9e41dedfe1166a4242b21b 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/10] 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 4a15d0752c1f0b9743fb97beb0fd6a5c91108d7f 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/10] 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 aa719eb3496306400ede5dafcfe521c57a3d1dd6 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/10] 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 11c1118a6e9cd4f2ca218e8a3bb0acede53ff481 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/10] 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 776b9f055730a0875d6ef214052f04443a5151f4 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/10] 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 29ae39ce76e4e94455c3112927aff6937db0a4f2 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/10] 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 cb48b8bac30a3f147f3a986fc6156cc9ca4183be 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/10] 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 fbee359b2d7d73880701193af0c4c19d01459317 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/10] 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*