Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved verify callbacks #307

Merged
merged 1 commit into from
Oct 6, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 119 additions & 58 deletions osslsigncode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1173,14 +1173,14 @@ static void print_cert(X509 *cert, int i)
issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
serialbn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), NULL);
serial = BN_bn2hex(serialbn);
if (i > 0)
printf("\t------------------\n");
printf("\t------------------\n");
printf("\tSigner #%d:\n\t\tSubject: %s\n\t\tIssuer : %s\n\t\tSerial : %s\n\t\tCertificate expiration date:\n",
i, subject, issuer, serial);
printf("\t\t\tnotBefore : ");
print_asn1_time(X509_get0_notBefore(cert));
printf("\t\t\tnotAfter : ");
print_asn1_time(X509_get0_notAfter(cert));
printf("\n");

OPENSSL_free(subject);
OPENSSL_free(issuer);
Expand All @@ -1189,24 +1189,106 @@ static void print_cert(X509 *cert, int i)
}

/*
* Print X509 certificate list from p7->d.sign->cert
* [in] p7: PKCS#7 signature
* [returns] 1 on success
* [in] txt, list
* [returns] 0 on error or 1 on success
*/
static int print_certs(PKCS7 *p7)
static int on_list(const char *txt, const char *list[])
{
X509 *cert;
int i, count;

count = sk_X509_num(p7->d.sign->cert);
printf("\nNumber of certificates: %d\n", count);
for (i=0; i<count; i++) {
cert = sk_X509_value(p7->d.sign->cert, i);
if (!cert)
return 0; /* FAILED */
print_cert(cert, i);
while (*list)
if (!strcmp(txt, *list++))
return 1; /* OK */
return 0; /* FAILED */
}

/*
* Check Windows certificate whitelist:
* https://learn.microsoft.com/en-us/troubleshoot/windows-server/identity/trusted-root-certificates-are-required
* For Microsoft Root Authority, serial number: 00C1008B3C3C8811D13EF663ECDF40,
* fingerprint: "F3:84:06:E5:40:D7:A9:D9:0C:B4:A9:47:92:99:64:0F:FB:6D:F9:E2:24:EC:C7:A0:1C:0D:95:58:D8:DA:D7:7D"
* expiration date: 12/31/2020, intended purposes: All,
* ignore X509_V_ERR_INVALID_CA and X509_V_ERR_CERT_HAS_EXPIRED
* [in] cert: X509 certificate
* [in] error: error code
* [returns] 0 on error or 1 on success
*/
static int trusted_cert(X509 *cert, int error) {
const char *fingerprints[] = {
"F3:84:06:E5:40:D7:A9:D9:0C:B4:A9:47:92:99:64:0F:FB:6D:F9:E2:24:EC:C7:A0:1C:0D:95:58:D8:DA:D7:7D",
NULL
};
u_char mdbuf[EVP_MAX_MD_SIZE], *p;
char *hex = NULL;
int len;
const EVP_MD *md = EVP_get_digestbynid(NID_sha256);
BIO *bhash = BIO_new(BIO_f_md());

if (!BIO_set_md(bhash, md)) {
BIO_free_all(bhash);
return 0; /* FAILED */
}
return 1; /* OK */
BIO_push(bhash, BIO_new(BIO_s_null()));
len = i2d_X509(cert, NULL);
p = OPENSSL_malloc((size_t)len);
i2d_X509(cert, &p);
p -= len;
BIO_write(bhash, p, len);
OPENSSL_free(p);
BIO_gets(bhash, (char *)mdbuf, EVP_MD_size(md));
BIO_free_all(bhash);

hex = OPENSSL_buf2hexstr(mdbuf, (size_t)EVP_MD_size(md));
if (!hex) {
return 0; /* FAILED */
}
if (on_list(hex, fingerprints)) {
printf("\tWarning: Ignoring %s error for Windows certificate whitelist\n",
X509_verify_cert_error_string(error));
OPENSSL_free(hex);
return 1; /* trusted */
}
OPENSSL_free(hex);
return 0; /* untrusted */
}

/*
* X509_STORE_CTX_verify_cb
*/
static int verify_ca_callback(int ok, X509_STORE_CTX *ctx)
{
int error = X509_STORE_CTX_get_error(ctx);
int depth = X509_STORE_CTX_get_error_depth(ctx);

X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
print_cert(current_cert, depth);
if (!ok) {
if (trusted_cert(current_cert, error)) {
return 1;
} else {
printf("\tError: %s\n", X509_verify_cert_error_string(error));
}
}
return ok;
}

static int verify_crl_callback(int ok, X509_STORE_CTX *ctx)
{
int error = X509_STORE_CTX_get_error(ctx);
int depth = X509_STORE_CTX_get_error_depth(ctx);

X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
print_cert(current_cert, depth);
if (!ok) {
if (trusted_cert(current_cert, error)) {
return 1;
} else if (error == X509_V_ERR_CERT_HAS_EXPIRED) {
printf("\tWarning: Ignoring %s error for CRL validation\n",
X509_verify_cert_error_string(error));
return 1;
} else {
printf("\tError: %s\n", X509_verify_cert_error_string(error));
}
}
return ok;
}

/*
Expand All @@ -1233,30 +1315,11 @@ static int x509_store_load_file(X509_STORE *store, char *cafile)
return 0; /* FAILED */
if (!X509_STORE_set1_param(store, param))
return 0; /* FAILED */
X509_STORE_set_verify_cb(store, verify_ca_callback);

return 1; /* OK */
}

/* X509_STORE_CTX_verify_cb */
static int verify_callback(int ok, X509_STORE_CTX *ctx)
{
int error = X509_STORE_CTX_get_error(ctx);
int depth = X509_STORE_CTX_get_error_depth(ctx);

if (!ok && error == X509_V_ERR_CERT_HAS_EXPIRED) {
if (depth == 0) {
printf("\nWarning: Ignoring expired signer certificate for CRL validation\n");
return 1;
} else {
X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
printf("\nError: Expired CA certificate:\n");
print_cert(current_cert, 0);
printf("\n");
}
}
return ok;
}

/*
* [in, out] store: structure for holding information about X.509 certificates and CRLs
* [in] cafile: file contains concatenated CA certificates in PEM format
Expand Down Expand Up @@ -1287,7 +1350,7 @@ static int x509_store_load_crlfile(X509_STORE *store, char *cafile, char *crlfil
return 0; /* FAILED */
if (!X509_STORE_set1_param(store, param))
return 0; /* FAILED */
X509_STORE_set_verify_cb(store, verify_callback);
X509_STORE_set_verify_cb(store, verify_crl_callback);

return 1; /* OK */
}
Expand Down Expand Up @@ -1326,6 +1389,7 @@ static int verify_crl(char *cafile, char *crlfile, STACK_OF(X509_CRL) *crls,
if (crls)
X509_STORE_CTX_set0_crls(ctx, crls);

printf("\nCertificate Revocation List verified by:\n");
if (X509_verify_cert(ctx) <= 0) {
int error = X509_STORE_CTX_get_error(ctx);
printf("\nX509_verify_cert: certificate verify error: %s\n",
Expand Down Expand Up @@ -1567,6 +1631,7 @@ static int verify_timestamp(FILE_FORMAT_CTX *ctx, PKCS7 *p7, CMS_ContentInfo *ti
}

/* verify a CMS SignedData structure */
printf("\nTimestamp verified by:\n");
if (!CMS_verify(timestamp, NULL, store, 0, NULL, 0)) {
printf("\nCMS_verify error\n");
X509_STORE_free(store);
Expand Down Expand Up @@ -1680,6 +1745,7 @@ static int verify_authenticode(FILE_FORMAT_CTX *ctx, PKCS7 *p7, time_t time, X50
bio = BIO_new_mem_buf(p7->d.sign->contents->d.other->value.sequence->data,
p7->d.sign->contents->d.other->value.sequence->length);
}
printf("\nSigning Certificate Chain:\n");
if (!PKCS7_verify(p7, NULL, store, bio, NULL, 0)) {
printf("\nPKCS7_verify error\n");
X509_STORE_free(store);
Expand Down Expand Up @@ -1812,6 +1878,7 @@ static int print_cms_timestamp(CMS_ContentInfo *timestamp, time_t time)
{
STACK_OF(CMS_SignerInfo) *sinfos;
CMS_SignerInfo *si;
X509_ATTRIBUTE *attr;
int md_nid;
ASN1_INTEGER *serialno;
char *issuer_name, *serial;
Expand All @@ -1825,19 +1892,28 @@ static int print_cms_timestamp(CMS_ContentInfo *timestamp, time_t time)
si = sk_CMS_SignerInfo_value(sinfos, 0);
if (si == NULL)
return 0; /* FAILED */
printf("\nThe signature is timestamped: ");
printf("\nCountersignatures:\n\tTimestamp time: ");
print_time_t(time);

/* PKCS#9 signing time - Policy OID: 1.2.840.113549.1.9.5 */
attr = CMS_signed_get_attr(si, CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1));
if (attr == NULL)
return 0; /* FAILED */
printf("\tSigning time: ");
print_time_t(time_t_get_asn1_time(X509_ATTRIBUTE_get0_data(attr, 0, V_ASN1_UTCTIME, NULL)));

CMS_SignerInfo_get0_algs(si, NULL, NULL, &pdig, NULL);
if (pdig == NULL || pdig->algorithm == NULL)
return 0; /* FAILED */
md_nid = OBJ_obj2nid(pdig->algorithm);
printf("Hash Algorithm: %s\n", (md_nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(md_nid));
printf("\tHash Algorithm: %s\n", (md_nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(md_nid));

if (!CMS_SignerInfo_get0_signer_id(si, NULL, &issuer, &serialno) || !issuer)
return 0; /* FAILED */
issuer_name = X509_NAME_oneline(issuer, NULL, 0);
serialbn = ASN1_INTEGER_to_BN(serialno, NULL);
serial = BN_bn2hex(serialbn);
printf("Timestamp Verified by:\n\t\tIssuer : %s\n\t\tSerial : %s\n", issuer_name, serial);
printf("\tIssuer: %s\n\tSerial: %s\n", issuer_name, serial);
OPENSSL_free(issuer_name);
BN_free(serialbn);
OPENSSL_free(serial);
Expand Down Expand Up @@ -1871,7 +1947,7 @@ static time_t time_t_timestamp_get_attributes(CMS_ContentInfo **timestamp, PKCS7
if (!si)
return INVALID_TIME; /* FAILED */
md_nid = OBJ_obj2nid(si->digest_alg->algorithm);
printf("\nMessage digest algorithm: %s\n",
printf("Message digest algorithm: %s\n",
(md_nid == NID_undef) ? "UNKNOWN" : OBJ_nid2sn(md_nid));
printf("\nAuthenticated attributes:\n");
auth_attr = PKCS7_get_signed_attributes(si); /* cont[0] */
Expand Down Expand Up @@ -2336,8 +2412,6 @@ static int verify_signature(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
printf("Signer's certificate:\n");
print_cert(signer, 0);

if (!print_certs(p7))
printf("Print certs error\n");
time = time_t_timestamp_get_attributes(&timestamp, p7, ctx->options->verbose);
if (ctx->options->leafhash != NULL) {
leafok = verify_leaf_hash(signer, ctx->options->leafhash);
Expand All @@ -2358,7 +2432,7 @@ static int verify_signature(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
printf("TSA's CRL file: %s\n", ctx->options->tsa_crlfile);
if (timestamp) {
if (ctx->options->ignore_timestamp) {
printf("\nTimestamp Server Signature verification is disabled\n\n");
printf("\nTimestamp Server Signature verification is disabled\n");
time = INVALID_TIME;
} else {
int timeok = verify_timestamp(ctx, p7, timestamp, time);
Expand Down Expand Up @@ -2620,19 +2694,6 @@ static void free_options(GLOBAL_OPTIONS *options)
options->crls = NULL;
}


/*
* [in] txt, list
* [returns] 0 on error or 1 on success
*/
static int on_list(const char *txt, const char *list[])
{
while (*list)
if (!strcmp(txt, *list++))
return 1; /* OK */
return 0; /* FAILED */
}

/*
* [in] argv0, cmd
* [returns] none
Expand Down
Loading