Skip to content

Commit

Permalink
Improve -X to allow multiple certificates for chain
Browse files Browse the repository at this point in the history
Ex:
ldid -KCertificates.p12 -XExtractedFromP12.cer -XAppleWWDRCAG3.cer -XAppleIncRootCertificate.cer
  • Loading branch information
CRKatri committed Mar 20, 2024
1 parent 68af298 commit 3d2dbfd
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 47 deletions.
14 changes: 9 additions & 5 deletions docs/ldid.1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
130 changes: 88 additions & 42 deletions ldid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1872,7 +1872,7 @@ class P12Signer : public ldid::Signer {
STACK_OF(X509) *ca_;

public:
P12Signer(BIO *bio) :
P12Signer(BIO *bio, std::vector<std::string> certs) :
value_(d2i_PKCS12_bio(bio, NULL)),
key_(NULL),
cert_(NULL),
Expand All @@ -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);
}
Expand All @@ -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() {
Expand Down Expand Up @@ -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, &params, 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<std::string> 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));
Expand All @@ -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, &params, 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);
}
}
}
}

Expand Down Expand Up @@ -3511,7 +3554,7 @@ int main(int argc, char *argv[]) {
Map entitlements;
Map requirements;
std::string key;
std::string certuri;
std::vector<std::string> certs;
ldid::Signer *signer = new NoSigner();
ldid::Slots slots;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 3d2dbfd

Please sign in to comment.