diff options
30 files changed, 852 insertions, 478 deletions
diff --git a/apps/cms.c b/apps/cms.c index 8402a272e2..b2037b4df2 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -1,5 +1,5 @@ /* - * Copyright 2008-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2008-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -65,7 +65,7 @@ struct cms_key_param_st { typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_ENCRYPT, - OPT_DECRYPT, OPT_SIGN, OPT_SIGN_RECEIPT, OPT_RESIGN, + OPT_DECRYPT, OPT_SIGN, OPT_CADES, OPT_SIGN_RECEIPT, OPT_RESIGN, OPT_VERIFY, OPT_VERIFY_RETCODE, OPT_VERIFY_RECEIPT, OPT_CMSOUT, OPT_DATA_OUT, OPT_DATA_CREATE, OPT_DIGEST_VERIFY, OPT_DIGEST_CREATE, OPT_COMPRESS, OPT_UNCOMPRESS, @@ -102,6 +102,7 @@ const OPTIONS cms_options[] = { {"sign", OPT_SIGN, '-', "Sign message"}, {"sign_receipt", OPT_SIGN_RECEIPT, '-', "Generate a signed receipt for the message"}, {"resign", OPT_RESIGN, '-', "Resign a signed message"}, + {"cades", OPT_CADES, '-', "Include signer certificate digest"}, {"verify", OPT_VERIFY, '-', "Verify signed message"}, {"verify_retcode", OPT_VERIFY_RETCODE, '-'}, {"verify_receipt", OPT_VERIFY_RECEIPT, '<'}, @@ -326,6 +327,9 @@ int cms_main(int argc, char **argv) case OPT_BINARY: flags |= CMS_BINARY; break; + case OPT_CADES: + flags |= CMS_CADES; + break; case OPT_KEYID: flags |= CMS_USE_KEYID; break; diff --git a/crypto/build.info b/crypto/build.info index a0bb90acb4..e014e0336e 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -5,7 +5,7 @@ SUBDIRS=objects buffer bio stack lhash rand evp asn1 pem x509 x509v3 conf \ md2 md4 md5 sha mdc2 gmac hmac ripemd whrlpool poly1305 blake2 \ siphash sm3 des aes rc2 rc4 rc5 idea aria bf cast camellia \ seed sm4 chacha modes bn ec rsa dsa dh sm2 dso engine \ - err comp ocsp cms ts srp cmac ct async kmac + err comp ocsp cms ts srp cmac ct async kmac ess LIBS=../libcrypto SOURCE[../libcrypto]=\ diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c index 9596fab182..f7d4b7fd96 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -27,6 +27,10 @@ static const ERR_STRING_DATA CMS_str_functs[] = { {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ADD1_SIGNER, 0), "CMS_add1_signer"}, {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ADD1_SIGNINGTIME, 0), "cms_add1_signingTime"}, + {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ADD1_SIGNING_CERT, 0), + "CMS_add1_signing_cert"}, + {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ADD1_SIGNING_CERT_V2, 0), + "CMS_add1_signing_cert_v2"}, {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_COMPRESS, 0), "CMS_compress"}, {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_COMPRESSEDDATA_CREATE, 0), "cms_CompressedData_create"}, diff --git a/crypto/cms/cms_ess.c b/crypto/cms/cms_ess.c index 86e88ffbbe..95e3628d9c 100644 --- a/crypto/cms/cms_ess.c +++ b/crypto/cms/cms_ess.c @@ -1,5 +1,5 @@ /* - * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2008-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -14,11 +14,13 @@ #include <openssl/x509v3.h> #include <openssl/err.h> #include <openssl/cms.h> +#include <openssl/ess.h> #include "cms_lcl.h" +#include "internal/ess_int.h" IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest) -/* ESS services: for now just Signed Receipt related */ +/* ESS services */ int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr) { @@ -335,3 +337,70 @@ ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si) CMS_ReceiptRequest_free(rr); return os; } + +/* + * Add signer certificate's V2 digest to a SignerInfo + * structure + */ + +int CMS_add1_signing_cert_v2(CMS_SignerInfo *si, + ESS_SIGNING_CERT_V2 *sc) +{ + ASN1_STRING *seq = NULL; + unsigned char *p, *pp; + int len; + + /* Add SigningCertificateV2 signed attribute to the signer info. */ + len = i2d_ESS_SIGNING_CERT_V2(sc, NULL); + if ((pp = OPENSSL_malloc(len)) == NULL) + goto err; + p = pp; + i2d_ESS_SIGNING_CERT_V2(sc, &p); + if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set(seq, pp, len)) + goto err; + OPENSSL_free(pp); + pp = NULL; + if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_signingCertificateV2, + V_ASN1_SEQUENCE, seq, -1)) + goto err; + ASN1_STRING_free(seq); + return 1; + err: + CMSerr(CMS_F_CMS_ADD1_SIGNING_CERT_V2, ERR_R_MALLOC_FAILURE); + ASN1_STRING_free(seq); + OPENSSL_free(pp); + return 0; +} + +/* + * Add signer certificate's digest to a SignerInfo + * structure + */ + +int CMS_add1_signing_cert(CMS_SignerInfo *si, ESS_SIGNING_CERT *sc) +{ + ASN1_STRING *seq = NULL; + unsigned char *p, *pp; + int len; + + /* Add SigningCertificate signed attribute to the signer info. */ + len = i2d_ESS_SIGNING_CERT(sc, NULL); + if ((pp = OPENSSL_malloc(len)) == NULL) + goto err; + p = pp; + i2d_ESS_SIGNING_CERT(sc, &p); + if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set(seq, pp, len)) + goto err; + OPENSSL_free(pp); + pp = NULL; + if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_signingCertificate, + V_ASN1_SEQUENCE, seq, -1)) + goto err; + ASN1_STRING_free(seq); + return 1; + err: + CMSerr(CMS_F_CMS_ADD1_SIGNING_CERT, ERR_R_MALLOC_FAILURE); + ASN1_STRING_free(seq); + OPENSSL_free(pp); + return 0; +} diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c index f4f872efe8..71b3041116 100644 --- a/crypto/cms/cms_sd.c +++ b/crypto/cms/cms_sd.c @@ -332,6 +332,27 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, !CMS_SignerInfo_sign(si)) goto err; } + if (flags & CMS_CADES) { + ESS_SIGNING_CERT *sc = NULL; + ESS_SIGNING_CERT_V2 *sc2 = NULL; + int add_sc; + + if (md == EVP_sha1() || md == NULL) { + if ((sc = ESS_SIGNING_CERT_new_init(signer, + NULL, 1)) == NULL) + goto err; + add_sc = CMS_add1_signing_cert(si, sc); + ESS_SIGNING_CERT_free(sc); + } else { + if ((sc2 = ESS_SIGNING_CERT_V2_new_init(md, signer, + NULL, 1)) == NULL) + goto err; + add_sc = CMS_add1_signing_cert_v2(si, sc2); + ESS_SIGNING_CERT_V2_free(sc2); + } + if (!add_sc) + goto err; + } } if (!(flags & CMS_NOCERTS)) { diff --git a/crypto/err/err.c b/crypto/err/err.c index 44e7115f9c..4505479772 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -64,6 +64,7 @@ static ERR_STRING_DATA ERR_str_libraries[] = { {ERR_PACK(ERR_LIB_KDF, 0, 0), "KDF routines"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, 0), "STORE routines"}, {ERR_PACK(ERR_LIB_SM2, 0, 0), "SM2 routines"}, + {ERR_PACK(ERR_LIB_ESS, 0, 0), "ESS routines"}, {0, NULL}, }; diff --git a/crypto/err/err_all.c b/crypto/err/err_all.c index 83ceff5c2e..3911ecc5c9 100644 --- a/crypto/err/err_all.c +++ b/crypto/err/err_all.c @@ -38,6 +38,7 @@ #include <openssl/asyncerr.h> #include <openssl/kdferr.h> #include <openssl/storeerr.h> +#include <openssl/esserr.h> int err_load_crypto_strings_int(void) { @@ -91,6 +92,7 @@ int err_load_crypto_strings_int(void) # ifndef OPENSSL_NO_CT ERR_load_CT_strings() == 0 || # endif + ERR_load_ESS_strings() == 0 || ERR_load_ASYNC_strings() == 0 || #endif ERR_load_KDF_strings() == 0 || diff --git a/crypto/err/openssl.ec b/crypto/err/openssl.ec index 3e092eae0a..94d46d067b 100644 --- a/crypto/err/openssl.ec +++ b/crypto/err/openssl.ec @@ -34,6 +34,7 @@ L ASYNC include/openssl/async.h crypto/async/async_err.c L KDF include/openssl/kdf.h crypto/kdf/kdf_err.c L SM2 crypto/include/internal/sm2.h crypto/sm2/sm2_err.c L OSSL_STORE include/openssl/store.h crypto/store/store_err.c +L ESS include/openssl/ess.h crypto/ess/ess_err.c # additional header files to be scanned for function names L NONE include/openssl/x509_vfy.h NONE diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index fba1dc31f1..0e133d6e7d 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1,4 +1,4 @@ -# Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 1999-2019 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -242,6 +242,8 @@ CMS_F_CMS_ADD1_RECEIPTREQUEST:158:CMS_add1_ReceiptRequest CMS_F_CMS_ADD1_RECIPIENT_CERT:101:CMS_add1_recipient_cert CMS_F_CMS_ADD1_SIGNER:102:CMS_add1_signer CMS_F_CMS_ADD1_SIGNINGTIME:103:cms_add1_signingTime +CMS_F_CMS_ADD1_SIGNING_CERT:181:CMS_add1_signing_cert +CMS_F_CMS_ADD1_SIGNING_CERT_V2:182:CMS_add1_signing_cert_v2 CMS_F_CMS_COMPRESS:104:CMS_compress CMS_F_CMS_COMPRESSEDDATA_CREATE:105:cms_CompressedData_create CMS_F_CMS_COMPRESSEDDATA_INIT_BIO:106:cms_CompressedData_init_bio @@ -709,6 +711,12 @@ ENGINE_F_INT_CTRL_HELPER:172:int_ctrl_helper ENGINE_F_INT_ENGINE_CONFIGURE:188:int_engine_configure ENGINE_F_INT_ENGINE_MODULE_INIT:187:int_engine_module_init ENGINE_F_OSSL_HMAC_INIT:200:ossl_hmac_init +ESS_F_ESS_CERT_ID_NEW_INIT:100:ESS_CERT_ID_new_init +ESS_F_ESS_CERT_ID_V2_NEW_INIT:101:ESS_CERT_ID_V2_new_init +ESS_F_ESS_SIGNING_CERT_ADD:104:ESS_SIGNING_CERT_add +ESS_F_ESS_SIGNING_CERT_NEW_INIT:102:ESS_SIGNING_CERT_new_init +ESS_F_ESS_SIGNING_CERT_V2_ADD:105:ESS_SIGNING_CERT_V2_add +ESS_F_ESS_SIGNING_CERT_V2_NEW_INIT:103:ESS_SIGNING_CERT_V2_new_init EVP_F_AESNI_INIT_KEY:165:aesni_init_key EVP_F_AES_GCM_CTRL:196:aes_gcm_ctrl EVP_F_AES_GCM_TLS_CIPHER:207:aes_gcm_tls_cipher @@ -1558,12 +1566,6 @@ SSL_F_WPACKET_START_SUB_PACKET_LEN__:634:WPACKET_start_sub_packet_len__ SSL_F_WRITE_STATE_MACHINE:586:write_state_machine TS_F_DEF_SERIAL_CB:110:def_serial_cb TS_F_DEF_TIME_CB:111:def_time_cb -TS_F_ESS_ADD_SIGNING_CERT:112:ess_add_signing_cert -TS_F_ESS_ADD_SIGNING_CERT_V2:147:ess_add_signing_cert_v2 -TS_F_ESS_CERT_ID_NEW_INIT:113:ess_CERT_ID_new_init -TS_F_ESS_CERT_ID_V2_NEW_INIT:156:ess_cert_id_v2_new_init -TS_F_ESS_SIGNING_CERT_NEW_INIT:114:ess_SIGNING_CERT_new_init -TS_F_ESS_SIGNING_CERT_V2_NEW_INIT:157:ess_signing_cert_v2_new_init TS_F_INT_TS_RESP_VERIFY_TOKEN:149:int_ts_RESP_verify_token TS_F_PKCS7_TO_TS_TST_INFO:148:PKCS7_to_TS_TST_INFO TS_F_TS_ACCURACY_SET_MICROS:115:TS_ACCURACY_set_micros @@ -2223,6 +2225,9 @@ ENGINE_R_UNIMPLEMENTED_CIPHER:146:unimplemented cipher ENGINE_R_UNIMPLEMENTED_DIGEST:147:unimplemented digest ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD:101:unimplemented public key method ENGINE_R_VERSION_INCOMPATIBILITY:145:version incompatibility +ESS_R_ESS_SIGNING_CERTIFICATE_ERROR:102:ess signing certificate error +ESS_R_ESS_SIGNING_CERT_ADD_ERROR:100:ess signing cert add error +ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR:101:ess signing cert v2 add error EVP_R_AES_KEY_SETUP_FAILED:143:aes key setup failed EVP_R_ARIA_KEY_SETUP_FAILED:176:aria key setup failed EVP_R_BAD_DECRYPT:100:bad decrypt diff --git a/crypto/ess/build.info b/crypto/ess/build.info new file mode 100644 index 0000000000..24fcecc8f5 --- /dev/null +++ b/crypto/ess/build.info @@ -0,0 +1,3 @@ +LIBS=../../libcrypto +SOURCE[../../libcrypto]= \ + ess_lib.c ess_asn1.c ess_err.c diff --git a/crypto/ess/ess_asn1.c b/crypto/ess/ess_asn1.c new file mode 100644 index 0000000000..d10746906a --- /dev/null +++ b/crypto/ess/ess_asn1.c @@ -0,0 +1,57 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/err.h> +#include <openssl/asn1t.h> +#include <openssl/ess.h> +#include <openssl/x509v3.h> +#include "internal/ess_int.h" + +/* ASN1 stuff for ESS Structure */ + +ASN1_SEQUENCE(ESS_ISSUER_SERIAL) = { + ASN1_SEQUENCE_OF(ESS_ISSUER_SERIAL, issuer, GENERAL_NAME), + ASN1_SIMPLE(ESS_ISSUER_SERIAL, serial, ASN1_INTEGER) +} static_ASN1_SEQUENCE_END(ESS_ISSUER_SERIAL) + +IMPLEMENT_ASN1_FUNCTIONS_const(ESS_ISSUER_SERIAL) +IMPLEMENT_ASN1_DUP_FUNCTION(ESS_ISSUER_SERIAL) + +ASN1_SEQUENCE(ESS_CERT_ID) = { + ASN1_SIMPLE(ESS_CERT_ID, hash, ASN1_OCTET_STRING), + ASN1_OPT(ESS_CERT_ID, issuer_serial, ESS_ISSUER_SERIAL) +} static_ASN1_SEQUENCE_END(ESS_CERT_ID) + +IMPLEMENT_ASN1_FUNCTIONS_const(ESS_CERT_ID) +IMPLEMENT_ASN1_DUP_FUNCTION(ESS_CERT_ID) + +ASN1_SEQUENCE(ESS_SIGNING_CERT) = { + ASN1_SEQUENCE_OF(ESS_SIGNING_CERT, cert_ids, ESS_CERT_ID), + ASN1_SEQUENCE_OF_OPT(ESS_SIGNING_CERT, policy_info, POLICYINFO) +} static_ASN1_SEQUENCE_END(ESS_SIGNING_CERT) + +IMPLEMENT_ASN1_FUNCTIONS_const(ESS_SIGNING_CERT) +IMPLEMENT_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT) + +ASN1_SEQUENCE(ESS_CERT_ID_V2) = { + ASN1_OPT(ESS_CERT_ID_V2, hash_alg, X509_ALGOR), + ASN1_SIMPLE(ESS_CERT_ID_V2, hash, ASN1_OCTET_STRING), + ASN1_OPT(ESS_CERT_ID_V2, issuer_serial, ESS_ISSUER_SERIAL) +} static_ASN1_SEQUENCE_END(ESS_CERT_ID_V2) + +IMPLEMENT_ASN1_FUNCTIONS_const(ESS_CERT_ID_V2) +IMPLEMENT_ASN1_DUP_FUNCTION(ESS_CERT_ID_V2) + +ASN1_SEQUENCE(ESS_SIGNING_CERT_V2) = { + ASN1_SEQUENCE_OF(ESS_SIGNING_CERT_V2, cert_ids, ESS_CERT_ID_V2), + ASN1_SEQUENCE_OF_OPT(ESS_SIGNING_CERT_V2, policy_info, POLICYINFO) +} static_ASN1_SEQUENCE_END(ESS_SIGNING_CERT_V2) + +IMPLEMENT_ASN1_FUNCTIONS_const(ESS_SIGNING_CERT_V2) +IMPLEMENT_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT_V2) diff --git a/crypto/ess/ess_err.c b/crypto/ess/ess_err.c new file mode 100644 index 0000000000..215b7f1ebc --- /dev/null +++ b/crypto/ess/ess_err.c @@ -0,0 +1,53 @@ +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/err.h> +#include <openssl/esserr.h> + +#ifndef OPENSSL_NO_ERR + +static const ERR_STRING_DATA ESS_str_functs[] = { + {ERR_PACK(ERR_LIB_ESS, ESS_F_ESS_CERT_ID_NEW_INIT, 0), + "ESS_CERT_ID_new_init"}, + {ERR_PACK(ERR_LIB_ESS, ESS_F_ESS_CERT_ID_V2_NEW_INIT, 0), + "ESS_CERT_ID_V2_new_init"}, + {ERR_PACK(ERR_LIB_ESS, ESS_F_ESS_SIGNING_CERT_ADD, 0), + "ESS_SIGNING_CERT_add"}, + {ERR_PACK(ERR_LIB_ESS, ESS_F_ESS_SIGNING_CERT_NEW_INIT, 0), + "ESS_SIGNING_CERT_new_init"}, + {ERR_PACK(ERR_LIB_ESS, ESS_F_ESS_SIGNING_CERT_V2_ADD, 0), + "ESS_SIGNING_CERT_V2_add"}, + {ERR_PACK(ERR_LIB_ESS, ESS_F_ESS_SIGNING_CERT_V2_NEW_INIT, 0), + "ESS_SIGNING_CERT_V2_new_init"}, + {0, NULL} +}; + +static const ERR_STRING_DATA ESS_str_reasons[] = { + {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_SIGNING_CERTIFICATE_ERROR), + "ess signing certificate error"}, + {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_SIGNING_CERT_ADD_ERROR), + "ess signing cert add error"}, + {ERR_PACK(ERR_LIB_ESS, 0, ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR), + "ess signing cert v2 add error"}, + {0, NULL} +}; + +#endif + +int ERR_load_ESS_strings(void) +{ +#ifndef OPENSSL_NO_ERR + if (ERR_func_error_string(ESS_str_functs[0].error) == NULL) { + ERR_load_strings_const(ESS_str_functs); + ERR_load_strings_const(ESS_str_reasons); + } +#endif + return 1; +} diff --git a/crypto/ess/ess_lib.c b/crypto/ess/ess_lib.c new file mode 100644 index 0000000000..fa9cff18be --- /dev/null +++ b/crypto/ess/ess_lib.c @@ -0,0 +1,269 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/x509v3.h> +#include <openssl/err.h> +#include <openssl/ess.h> +#include "internal/ess_int.h" + +static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed); +static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg, + X509 *cert, int issuer_needed); + +ESS_SIGNING_CERT *ESS_SIGNING_CERT_new_init(X509 *signcert, + STACK_OF(X509) *certs, + int issuer_needed) +{ + ESS_CERT_ID *cid = NULL; + ESS_SIGNING_CERT *sc; + int i; + + if ((sc = ESS_SIGNING_CERT_new()) == NULL) + goto err; + if (sc->cert_ids == NULL + && (sc->cert_ids = sk_ESS_CERT_ID_new_null()) == NULL) + goto err; + + if ((cid = ESS_CERT_ID_new_init(signcert, issuer_needed)) == NULL + || !sk_ESS_CERT_ID_push(sc->cert_ids, cid)) + goto err; + for (i = 0; i < sk_X509_num(certs); ++i) { + X509 *cert = sk_X509_value(certs, i); + if ((cid = ESS_CERT_ID_new_init(cert, 1)) == NULL + || !sk_ESS_CERT_ID_push(sc->cert_ids, cid)) + goto err; + } + + return sc; + err: + ESS_SIGNING_CERT_free(sc); + ESS_CERT_ID_free(cid); + ESSerr(ESS_F_ESS_SIGNING_CERT_NEW_INIT, ERR_R_MALLOC_FAILURE); + return NULL; +} + +static ESS_CERT_ID *ESS_CERT_ID_new_init(X509 *cert, int issuer_needed) +{ + ESS_CERT_ID *cid = NULL; + GENERAL_NAME *name = NULL; + unsigned char cert_sha1[SHA_DIGEST_LENGTH]; + + /* Call for side-effect of computing hash and caching extensions */ + X509_check_purpose(cert, -1, 0); + if ((cid = ESS_CERT_ID_new()) == NULL) + goto err; + X509_digest(cert, EVP_sha1(), cert_sha1, NULL); + if (!ASN1_OCTET_STRING_set(cid->hash, cert_sha1, SHA_DIGEST_LENGTH)) + goto err; + + /* Setting the issuer/serial if requested. */ + if (!issuer_needed) + return cid; + + if (cid->issuer_serial == NULL + && (cid->issuer_serial = ESS_ISSUER_SERIAL_new()) == NULL) + goto err; + if ((name = GENERAL_NAME_new()) == NULL) + goto err; + name->type = GEN_DIRNAME; + if ((name->d.dirn = X509_NAME_dup(X509_get_issuer_name(cert))) == NULL) + goto err; + if (!sk_GENERAL_NAME_push(cid->issuer_serial->issuer, name)) + goto err; + name = NULL; /* Ownership is lost. */ + ASN1_INTEGER_free(cid->issuer_serial->serial); + if (!(cid->issuer_serial->serial = + ASN1_INTEGER_dup(X509_get_serialNumber(cert)))) + goto err; + + return cid; + err: + GENERAL_NAME_free(name); + ESS_CERT_ID_free(cid); + ESSerr(ESS_F_ESS_CERT_ID_NEW_INIT, ERR_R_MALLOC_FAILURE); + return NULL; +} + +ESS_SIGNING_CERT_V2 *ESS_SIGNING_CERT_V2_new_init(const EVP_MD *hash_alg, + X509 *signcert, + STACK_OF(X509) *certs, + int issuer_needed) +{ + ESS_CERT_ID_V2 *cid = NULL; + ESS_SIGNING_CERT_V2 *sc; + int i; + + if ((sc = ESS_SIGNING_CERT_V2_new()) == NULL) + goto err; + if ((cid = ESS_CERT_ID_V2_new_init(hash_alg, signcert, issuer_needed)) == NULL) + goto err; + if (!sk_ESS_CERT_ID_V2_push(sc->cert_ids, cid)) + goto err; + cid = NULL; + + for (i = 0; i < sk_X509_num(certs); ++i) { + X509 *cert = sk_X509_value(certs, i); + + if ((cid = ESS_CERT_ID_V2_new_init(hash_alg, cert, 1)) == NULL) + goto err; + if (!sk_ESS_CERT_ID_V2_push(sc->cert_ids, cid)) + goto err; + cid = NULL; + } + + return sc; + err: + ESS_SIGNING_CERT_V2_free(sc); + ESS_CERT_ID_V2_free(cid); + ESSerr(ESS_F_ESS_SIGNING_CERT_V2_NEW_INIT, ERR_R_MALLOC_FAILURE); + return NULL; +} + +static ESS_CERT_ID_V2 *ESS_CERT_ID_V2_new_init(const EVP_MD *hash_alg, + X509 *cert, int issuer_needed) +{ + ESS_CERT_ID_V2 *cid; + GENERAL_NAME *name = NULL; + unsigned char hash[EVP_MAX_MD_SIZE]; + unsigned int hash_len = sizeof(hash); + X509_ALGOR *alg = NULL; + + memset(hash, 0, sizeof(hash)); + + if ((cid = ESS_CERT_ID_V2_new()) == NULL) + goto err; + + if (hash_alg != EVP_sha256()) { + alg = X509_ALGOR_new(); + if (alg == NULL) + goto err; + X509_ALGOR_set_md(alg, hash_alg); + if (alg->algorithm == NULL) + goto err; + cid->hash_alg = alg; + alg = NULL; + } else { + cid->hash_alg = NULL; + } + + if (!X509_digest(cert, hash_alg, hash, &hash_len)) + goto err; + + if (!ASN1_OCTET_STRING_set(cid->hash, hash, hash_len)) + goto err; + + if (!issuer_needed) + return cid; + + if ((cid->issuer_serial = ESS_ISSUER_SERIAL_new()) == NULL) + goto err; + if ((name = GENERAL_NAME_new()) == NULL) + goto err; + name->type = GEN_DIRNAME; + if ((name->d.dirn = X509_NAME_dup(X509_get_issuer_name(cert))) == NULL) + goto err; + if (!sk_GENERAL_NAME_push(cid->issuer_serial->issuer, name)) + goto err; + name = NULL; /* Ownership is lost. */ + ASN1_INTEGER_free(cid->issuer_serial->serial); + cid->issuer_serial->serial = ASN1_INTEGER_dup(X509_get_serialNumber(cert)); + if (cid->issuer_serial->serial == NULL) + goto err; + + return cid; + err: + X509_ALGOR_free(alg); + GENERAL_NAME_free(name); + ESS_CERT_ID_V2_free(cid); + ESSerr(ESS_F_ESS_CERT_ID_V2_NEW_INIT, ERR_R_MALLOC_FAILURE); + return NULL; +} + +ESS_SIGNING_CERT *ESS_SIGNING_CERT_get(PKCS7_SIGNER_INFO *si) +{ + ASN1_TYPE *attr; + const unsigned char *p; + attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate); + if (!attr) + return NULL; + p = attr->value.sequence->data; + return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length); +} + +ESS_SIGNING_CERT_V2 *ESS_SIGNING_CERT_V2_get(PKCS7_SIGNER_INFO *si) +{ + ASN1_TYPE *attr; + const unsigned char *p; + + attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificateV2); + if (attr == NULL) + return NULL; + p = attr->value.sequence->data; + return d2i_ESS_SIGNING_CERT_V2(NULL, &p, attr->value.sequence->length); +} + +int ESS_SIGNING_CERT_add(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT *sc) +{ + ASN1_STRING *seq = NULL; + unsigned char *p, *pp = NULL; + int len; + + len = i2d_ESS_SIGNING_CERT(sc, NULL); + if ((pp = OPENSSL_malloc(len)) == NULL) { + ESSerr(ESS_F_ESS_SIGNING_CERT_ADD, ERR_R_MALLOC_FAILURE); + goto err; + } + p = pp; + i2d_ESS_SIGNING_CERT(sc, &p); + if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set(seq, pp, len)) { + ESSerr(ESS_F_ESS_SIGNING_CERT_ADD, ERR_R_MALLOC_FAILURE); + goto err; + } + OPENSSL_free(pp); + pp = NULL; + return PKCS7_add_signed_attribute(si, + NID_id_smime_aa_signingCertificate, + V_ASN1_SEQUENCE, seq); + err: + ASN1_STRING_free(seq); + OPENSSL_free(pp); + + return 0; +} + +int ESS_SIGNING_CERT_V2_add(PKCS7_SIGNER_INFO *si, + ESS_SIGNING_CERT_V2 *sc) +{ + ASN1_STRING *seq = NULL; + unsigned char *p, *pp = NULL; + int len = i2d_ESS_SIGNING_CERT_V2(sc, NULL); + + if ((pp = OPENSSL_malloc(len)) == NULL) { + ESSerr(ESS_F_ESS_SIGNING_CERT_V2_ADD, ERR_R_MALLOC_FAILURE); + goto err; + } + + p = pp; + i2d_ESS_SIGNING_CERT_V2(sc, &p); + if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set(seq, pp, len)) { + ESSerr(ESS_F_ESS_SIGNING_CERT_V2_ADD, ERR_R_MALLOC_FAILURE); + goto err; + } + + OPENSSL_free(pp); + pp = NULL; + return PKCS7_add_signed_attribute(si, + NID_id_smime_aa_signingCertificateV2, + V_ASN1_SEQUENCE, seq); + err: + ASN1_STRING_free(seq); + OPENSSL_free(pp); + return 0; +} diff --git a/crypto/include/internal/ess_int.h b/crypto/include/internal/ess_int.h new file mode 100644 index 0000000000..26476ae984 --- /dev/null +++ b/crypto/include/internal/ess_int.h @@ -0,0 +1,78 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* internal ESS related stuff */ + +ESS_SIGNING_CERT *ESS_SIGNING_CERT_get(PKCS7_SIGNER_INFO *si); +int ESS_SIGNING_CERT_add(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT *sc); + +ESS_SIGNING_CERT_V2 *ESS_SIGNING_CERT_V2_get(PKCS7_SIGNER_INFO *si); +int ESS_SIGNING_CERT_V2_add(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT_V2 *sc); + +/*- + * IssuerSerial ::= SEQUENCE { + * issuer GeneralNames, + * serialNumber CertificateSerialNumber + * } + */ + +struct ESS_issuer_serial { + STACK_OF(GENERAL_NAME) *issuer; + ASN1_INTEGER *serial; +}; + +/*- + * ESSCertID ::= SEQUENCE { + * certHash Hash, + * issuerSerial IssuerSerial OPTIONAL + * } + */ + +struct ESS_cert_id { + ASN1_OCTET_STRING *hash; /* Always SHA-1 digest. */ + ESS_ISSUER_SERIAL *issuer_serial; +}; + +/*- + * SigningCertificate ::= SEQUENCE { + * certs SEQUENCE OF ESSCertID, + * policies SEQUENCE OF PolicyInformation OPTIONAL + * } + */ + +struct ESS_signing_cert { + STACK_OF(ESS_CERT_ID) *cert_ids; + STACK_OF(POLICYINFO) *policy_info; +}; + +/*- + * ESSCertIDv2 ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier DEFAULT id-sha256, + * certHash Hash, + * issuerSerial IssuerSerial OPTIONAL + * } + */ + +struct ESS_cert_id_v2_st { + X509_ALGOR *hash_alg; /* Default: SHA-256 */ + ASN1_OCTET_STRING *hash; + ESS_ISSUER_SERIAL *issuer_serial; +}; + +/* |