diff --git a/NEWS.md b/NEWS.md index f05cf21..8970994 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,7 @@ - added CAT file verification and listing each member of the CAT file by using the "-verbose" option - added new command "extract-data" to extract a PKCS#7 data content to be signed +- PKCS9_SEQUENCE_NUMBER authenticated attribute support ### 2.7 (2023.09.19) diff --git a/cab.c b/cab.c index 3ee7e5e..d9a2962 100644 --- a/cab.c +++ b/cab.c @@ -506,6 +506,12 @@ static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) printf("Unable to extract existing signature\n"); return NULL; /* FAILED */ } + ctx->options->nested_number = nested_signatures_number_get(cursig); + if (ctx->options->nested_number < 0) { + printf("Unable to get number of nested signatures\n"); + PKCS7_free(cursig); + return NULL; /* FAILED */ + } if (ctx->options->cmd == CMD_ADD) p7 = cursig; } diff --git a/helpers.c b/helpers.c index c455211..ec6fcc9 100644 --- a/helpers.c +++ b/helpers.c @@ -14,6 +14,7 @@ static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx); static int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx); static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx); +static int pkcs7_signer_info_add_sequence_number(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx); static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer); static int X509_compare(const X509 *const *a, const X509 *const *b); @@ -237,6 +238,10 @@ PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx) printf("Couldn't allocate memory for opus info\n"); return NULL; /* FAILED */ } + if ((ctx->options->nested_number >= 0) && + !pkcs7_signer_info_add_sequence_number(si, ctx)) { + return NULL; /* FAILED */ + } /* create X509 chain sorted in ascending order by their DER encoding */ chain = X509_chain_get_sorted(ctx, signer); if (chain == NULL) { @@ -719,6 +724,25 @@ static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX V_ASN1_SEQUENCE, purpose); } +/* + * [in, out] si: PKCS7_SIGNER_INFO structure + * [in] ctx: structure holds input and output data + * [returns] 0 on error or 1 on success + */ +static int pkcs7_signer_info_add_sequence_number(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx) +{ + ASN1_INTEGER *number = ASN1_INTEGER_new(); + + if (!number) + return 0; /* FAILED */ + if (!ASN1_INTEGER_set(number, ctx->options->nested_number + 1)) { + ASN1_INTEGER_free(number); + return 0; /* FAILED */ + } + return PKCS7_add_signed_attribute(si, OBJ_txt2nid(PKCS9_SEQUENCE_NUMBER), + V_ASN1_INTEGER, number); +} + /* * Create certificate chain sorted in ascending order by their DER encoding. * [in] ctx: structure holds input and output data @@ -794,6 +818,37 @@ static int X509_compare(const X509 *const *a, const X509 *const *b) return ret; } +/* + * Return the number of objects in SPC_NESTED_SIGNATURE_OBJID attribute + * [in] p7: existing PKCS#7 signature (Primary Signature) + * [returns] -1 on error or the number of nested signatures + */ +int nested_signatures_number_get(PKCS7 *p7) +{ + int i; + STACK_OF(X509_ATTRIBUTE) *unauth_attr; + PKCS7_SIGNER_INFO *si; + STACK_OF(PKCS7_SIGNER_INFO) *signer_info = PKCS7_get_signer_info(p7); + + if (!signer_info) + return -1; /* FAILED */ + si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0); + if (!si) + return -1; /* FAILED */ + unauth_attr = PKCS7_get_attributes(si); /* cont[1] */ + if (!unauth_attr) + return 0; /* OK, no unauthenticated attributes */ + for (i=0; ioptions->nested_number = nested_signatures_number_get(cursig); + if (ctx->options->nested_number < 0) { + printf("Unable to get number of nested signatures\n"); + PKCS7_free(cursig); + return NULL; /* FAILED */ + } if (ctx->options->cmd == CMD_ADD) p7 = cursig; } diff --git a/osslsigncode.c b/osslsigncode.c index 610100c..0aa693b 100644 --- a/osslsigncode.c +++ b/osslsigncode.c @@ -2037,8 +2037,10 @@ static time_t time_t_timestamp_get_attributes(CMS_ContentInfo **timestamp, PKCS7 md_nid = OBJ_obj2nid(si->digest_alg->algorithm); printf("Message digest algorithm: %s\n", (md_nid == NID_undef) ? "UNKNOWN" : OBJ_nid2sn(md_nid)); + + /* Unauthenticated attributes */ + auth_attr = PKCS7_get_signed_attributes(si); /* cont[0] */ printf("\nAuthenticated attributes:\n"); - auth_attr = PKCS7_get_signed_attributes(si); /* cont[0] */ for (i=0; itime = INVALID_TIME; options->jp = -1; options->index = -1; + options->nested_number = -1; #if OPENSSL_VERSION_NUMBER>=0x30000000L /* Use legacy PKCS#12 container with RC2-40-CBC private key and certificate encryption algorithm */ options->legacy = 1; @@ -4194,7 +4230,8 @@ int main(int argc, char **argv) || !OBJ_create(SPC_SP_OPUS_INFO_OBJID, NULL, NULL) || !OBJ_create(SPC_NESTED_SIGNATURE_OBJID, NULL, NULL) || !OBJ_create(SPC_UNAUTHENTICATED_DATA_BLOB_OBJID, NULL, NULL) - || !OBJ_create(SPC_RFC3161_OBJID, NULL, NULL)) + || !OBJ_create(SPC_RFC3161_OBJID, NULL, NULL) + || !OBJ_create(PKCS9_SEQUENCE_NUMBER, NULL, NULL)) DO_EXIT_0("Failed to create objects\n"); /* commands and options initialization */ diff --git a/osslsigncode.h b/osslsigncode.h index 6619e7d..ec28355 100644 --- a/osslsigncode.h +++ b/osslsigncode.h @@ -187,6 +187,7 @@ #define PKCS9_MESSAGE_DIGEST "1.2.840.113549.1.9.4" #define PKCS9_SIGNING_TIME "1.2.840.113549.1.9.5" #define PKCS9_COUNTER_SIGNATURE "1.2.840.113549.1.9.6" +#define PKCS9_SEQUENCE_NUMBER "1.2.840.113549.1.9.25.4" /* WIN_CERTIFICATE structure declared in Wintrust.h */ #define WIN_CERT_REVISION_2_0 0x0200 @@ -291,6 +292,7 @@ typedef struct { char *tsa_certfile; char *tsa_keyfile; time_t tsa_time; + int nested_number; } GLOBAL_OPTIONS; /* diff --git a/pe.c b/pe.c index 9be0625..e883205 100644 --- a/pe.c +++ b/pe.c @@ -423,6 +423,12 @@ static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) printf("Unable to extract existing signature\n"); return NULL; /* FAILED */ } + ctx->options->nested_number = nested_signatures_number_get(cursig); + if (ctx->options->nested_number < 0) { + printf("Unable to get number of nested signatures\n"); + PKCS7_free(cursig); + return NULL; /* FAILED */ + } if (ctx->options->cmd == CMD_ADD) p7 = cursig; }