From 3d2dbfd45e6bb27e3cfbe101e4f4f9ebe0700d58 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Tue, 19 Mar 2024 22:59:19 -0400 Subject: [PATCH] Improve -X to allow multiple certificates for chain Ex: ldid -KCertificates.p12 -XExtractedFromP12.cer -XAppleWWDRCAG3.cer -XAppleIncRootCertificate.cer --- docs/ldid.1 | 14 ++++-- ldid.cpp | 130 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 97 insertions(+), 47 deletions(-) diff --git a/docs/ldid.1 b/docs/ldid.1 index 7ec2278..6ce4e95 100644 --- a/docs/ldid.1 +++ b/docs/ldid.1 @@ -163,11 +163,15 @@ target is a bundle directory, and not a specific Mach-O file. can be used on any bundle, not just the root .app, including frameworks, appexes, and more. .It Fl X Ns Ar file -Use the certificate in -.Ar file . -Only used if the private key is a -.Ar pkcs11: -URI, and must also be a +Adds +.Ar file +as a certificate to be used when signing. +The first +.Ar file +must be the certificate for the signing key, each additional will be added as part of the chain. +Must be either +.Ar DER +encoded certificate or .Ar pkcs11: URI. .El diff --git a/ldid.cpp b/ldid.cpp index 3fe5745..e75d82b 100644 --- a/ldid.cpp +++ b/ldid.cpp @@ -1872,7 +1872,7 @@ class P12Signer : public ldid::Signer { STACK_OF(X509) *ca_; public: - P12Signer(BIO *bio) : + P12Signer(BIO *bio, std::vector certs) : value_(d2i_PKCS12_bio(bio, NULL)), key_(NULL), cert_(NULL), @@ -1893,7 +1893,7 @@ class P12Signer : public ldid::Signer { fprintf(stderr, "ldid: An error occured while parsing: %s\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } - if (key_ == NULL || cert_ == NULL) { + if (key_ == NULL || (cert_ == NULL && certs.empty())) { fprintf(stderr, "ldid: An error occured while parsing: %s\nYour p12 cert might not be valid\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } @@ -1904,6 +1904,22 @@ class P12Signer : public ldid::Signer { fprintf(stderr, "ldid: An error occured while parsing: %s\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } + + if (!certs.empty()) { + cert_ = d2i_X509_bio(Buffer(Map(certs[0], false)), NULL); + certs.erase(certs.begin()); + _foreach (certid, certs) { + X509 *cert = d2i_X509_bio(Buffer(Map(certid, false)), NULL); + if (cert == NULL) { + fprintf(stderr, "ldid: An error occured while parsing: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + if (sk_X509_push(ca_, cert) == 0) { + fprintf(stderr, "ldid: An error occured while loading: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + } + } } ~P12Signer() { @@ -1937,16 +1953,63 @@ class P11Signer : public ldid::Signer { EVP_PKEY *key_; X509 *cert_; STACK_OF(X509) *ca_; + bool supportLoadCert = false; + + X509 *loadcert(std::string cert_id) { + if (cert_id.compare(0, 7, "pkcs11:") == 0) { + const char *cmd_name = "LOAD_CERT_CTRL"; + struct { + const char *cert_id; + X509 *cert; + } params; + + params.cert_id = cert_id.c_str(); + params.cert = NULL; + + if (!supportLoadCert) { + if (ENGINE_ctrl(e_, ENGINE_CTRL_GET_CMD_FROM_NAME, 0, (void *)cmd_name, NULL) == 0) { + fprintf(stderr, "ldid: Engine does not support loading certificate: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + supportLoadCert = true; + } + + if (ENGINE_ctrl_cmd(e_, cmd_name, 0, ¶ms, NULL, 1) == 0) { + fprintf(stderr, "ldid: Engine cannot load certificate: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + + if (params.cert == NULL) { + fprintf(stderr, "ldid: An error occured while loading: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + + return params.cert; + } else { + X509 *cert = d2i_X509_bio(Buffer(Map(cert_id, false)), NULL); + if (cert == NULL) { + fprintf(stderr, "ldid: An error occured while loading: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + + return cert; + } + } public: P11Signer(std::string uri) - : P11Signer(uri, uri) {} + : P11Signer(uri, {}) {} - P11Signer(std::string keyuri, std::string certuri) : + P11Signer(std::string keyuri, std::vector certs) : key_(NULL), cert_(NULL), - ca_(NULL) + ca_(sk_X509_new_null()) { + if (ca_ == NULL) { + fprintf(stderr, "ldid: An error occured while loading: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + e_ = ENGINE_by_id("pkcs11"); if (!e_) { fprintf(stderr, "ldid: An error occured while loading pkcs11 engine: %s\n", ERR_error_string(ERR_get_error(), NULL)); @@ -1965,37 +2028,17 @@ class P11Signer : public ldid::Signer { exit(1); } - const char *cmd_name = "LOAD_CERT_CTRL"; - struct { - const char *cert_id; - X509 *cert; - } params; - - params.cert_id = certuri.c_str(); - params.cert = NULL; - - if (ENGINE_ctrl(e_, ENGINE_CTRL_GET_CMD_FROM_NAME, 0, (void *)cmd_name, NULL) == 0) { - fprintf(stderr, "ldid: Engine does not support loading certificate: %s\n", ERR_error_string(ERR_get_error(), NULL)); - exit(1); - } - - if (ENGINE_ctrl_cmd(e_, cmd_name, 0, ¶ms, NULL, 1) == 0) { - fprintf(stderr, "ldid: Engine cannot load certificate: %s\n", ERR_error_string(ERR_get_error(), NULL)); - exit(1); - } - - cert_ = params.cert; - - if (cert_ == NULL) { - fprintf(stderr, "ldid: An error occured while loading: %s\n", ERR_error_string(ERR_get_error(), NULL)); - exit(1); - } - - if (ca_ == NULL) - ca_ = sk_X509_new_null(); - if (ca_ == NULL) { - fprintf(stderr, "ldid: An error occured while loading: %s\n", ERR_error_string(ERR_get_error(), NULL)); - exit(1); + if (certs.empty()) { + cert_ = loadcert(keyuri); + } else { + cert_ = loadcert(certs[0]); + certs.erase(certs.begin()); + _foreach (certid, certs) { + if (sk_X509_push(ca_, loadcert(certid)) == 0) { + fprintf(stderr, "ldid: An error occured while loading: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + } } } @@ -3511,7 +3554,7 @@ int main(int argc, char *argv[]) { Map entitlements; Map requirements; std::string key; - std::string certuri; + std::vector certs; ldid::Signer *signer = new NoSigner(); ldid::Slots slots; @@ -3722,7 +3765,7 @@ int main(int argc, char *argv[]) { case 'X': if (argv[argi][2] != '\0') - certuri = argv[argi] + 2; + certs.push_back(argv[argi] + 2); break; case 'T': break; @@ -3750,12 +3793,15 @@ int main(int argc, char *argv[]) { return 0; if (!key.empty()) { + if (key.compare(0, 7, "pkcs11:") == 0) { #if SMARTCARD - if (key.compare(0, 7, "pkcs11:") == 0) - signer = new P11Signer(key, certuri.empty() ? key : certuri); - else + signer = new P11Signer(key, certs); +#else + fprintf(stderr, "ldid: Smartcard support is not enabled\n"); + exit(1); #endif - signer = new P12Signer(Buffer(Map(key, O_RDONLY))); + } else + signer = new P12Signer(Buffer(Map(key, O_RDONLY, PROT_READ, MAP_PRIVATE)), certs); } size_t filei(0), filee(0);