From 90a9ed5fd2fd959e390a0f1c1d38650b05e7cab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Wed, 4 Feb 2009 22:04:28 +0000 Subject: [PATCH] Add hx509_cms_create_signed() that allows signing with 0 or more certs. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@24580 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/hx509/cms.c | 334 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 229 insertions(+), 105 deletions(-) diff --git a/lib/hx509/cms.c b/lib/hx509/cms.c index 6b2877886..0bc74bbcd 100644 --- a/lib/hx509/cms.c +++ b/lib/hx509/cms.c @@ -1131,26 +1131,52 @@ hx509_cms_create_signed_1(hx509_context context, hx509_certs pool, heim_octet_string *signed_data) { - AlgorithmIdentifier digest; - hx509_name name; - SignerInfo *signer_info; - heim_octet_string buf, content, sigdata = { 0, NULL }; + hx509_certs certs; + int ret = 0; + + signed_data->data = NULL; + signed_data->length = 0; + + ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs); + if (ret) + return ret; + ret = hx509_certs_add(context, certs, cert); + + ret = hx509_cms_create_signed(context, flags, eContentType, data, length, + digest_alg, certs, peer, anchors, pool, + signed_data); + + hx509_certs_free(&certs); + return ret; +} + +struct sigctx { SignedData sd; - int ret; + const AlgorithmIdentifier *digest_alg; + const heim_oid *eContentType; + heim_octet_string content; + hx509_peer_info peer; + int cmsidflag; + hx509_certs certs; + hx509_certs anchors; + hx509_certs pool; +}; + +static int +sig_process(hx509_context context, void *ctx, hx509_cert cert) +{ + struct sigctx *sigctx = ctx; + heim_octet_string buf, sigdata = { 0, NULL }; + SignerInfo *signer_info = NULL; + AlgorithmIdentifier digest; size_t size; + void *ptr; + int ret; + SignedData *sd = &sigctx->sd; hx509_path path; - int cmsidflag = CMS_ID_SKI; - memset(&sd, 0, sizeof(sd)); - memset(&name, 0, sizeof(name)); - memset(&path, 0, sizeof(path)); memset(&digest, 0, sizeof(digest)); - - content.data = rk_UNCONST(data); - content.length = length; - - if (flags & HX509_CMS_SIGATURE_ID_NAME) - cmsidflag = CMS_ID_NAME; + memset(&path, 0, sizeof(path)); if (_hx509_cert_private_key(cert) == NULL) { hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, @@ -1158,55 +1184,37 @@ hx509_cms_create_signed_1(hx509_context context, return HX509_PRIVATE_KEY_MISSING; } - if (digest_alg == NULL) { - ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, - _hx509_cert_private_key(cert), peer, &digest); - } else { - ret = copy_AlgorithmIdentifier(digest_alg, &digest); + if (sigctx->digest_alg) { + ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest); if (ret) hx509_clear_error_string(context); + } else { + ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, + _hx509_cert_private_key(cert), + sigctx->peer, &digest); } if (ret) goto out; - sd.version = CMSVersion_v3; + /* + * Allocate on more signerInfo and do the signature processing + */ - if (eContentType == NULL) - eContentType = oid_id_pkcs7_data(); - - der_copy_oid(eContentType, &sd.encapContentInfo.eContentType); - - /* */ - if ((flags & HX509_CMS_SIGATURE_DETACHED) == 0) { - ALLOC(sd.encapContentInfo.eContent, 1); - if (sd.encapContentInfo.eContent == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } - - sd.encapContentInfo.eContent->data = malloc(length); - if (sd.encapContentInfo.eContent->data == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } - memcpy(sd.encapContentInfo.eContent->data, data, length); - sd.encapContentInfo.eContent->length = length; - } - - ALLOC_SEQ(&sd.signerInfos, 1); - if (sd.signerInfos.val == NULL) { - hx509_clear_error_string(context); + ptr = realloc(sd->signerInfos.val, + (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0])); + if (ptr == NULL) { ret = ENOMEM; goto out; } + sd->signerInfos.val = ptr; - signer_info = &sd.signerInfos.val[0]; + signer_info = &sd->signerInfos.val[sd->signerInfos.len]; + + memset(signer_info, 0, sizeof(*signer_info)); signer_info->version = 1; - ret = fill_CMSIdentifier(cert, cmsidflag, &signer_info->sid); + ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid); if (ret) { hx509_clear_error_string(context); goto out; @@ -1215,7 +1223,6 @@ hx509_cms_create_signed_1(hx509_context context, signer_info->signedAttrs = NULL; signer_info->unsignedAttrs = NULL; - ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); if (ret) { hx509_clear_error_string(context); @@ -1226,7 +1233,7 @@ hx509_cms_create_signed_1(hx509_context context, * If it isn't pkcs7-data send signedAttributes */ - if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) { + if (der_heim_oid_cmp(sigctx->eContentType, oid_id_pkcs7_data()) != 0) { CMSAttributes sa; heim_octet_string sig; @@ -1239,7 +1246,7 @@ hx509_cms_create_signed_1(hx509_context context, ret = _hx509_create_signature(context, NULL, &digest, - &content, + &sigctx->content, NULL, &sig); if (ret) @@ -1264,6 +1271,7 @@ hx509_cms_create_signed_1(hx509_context context, oid_id_pkcs9_messageDigest(), &buf); if (ret) { + free(buf.data); hx509_clear_error_string(context); goto out; } @@ -1272,7 +1280,7 @@ hx509_cms_create_signed_1(hx509_context context, ASN1_MALLOC_ENCODE(ContentType, buf.data, buf.length, - eContentType, + sigctx->eContentType, &size, ret); if (ret) @@ -1285,6 +1293,7 @@ hx509_cms_create_signed_1(hx509_context context, oid_id_pkcs9_contentType(), &buf); if (ret) { + free(buf.data); hx509_clear_error_string(context); goto out; } @@ -1305,16 +1314,15 @@ hx509_cms_create_signed_1(hx509_context context, if (size != sigdata.length) _hx509_abort("internal ASN.1 encoder error"); } else { - sigdata.data = content.data; - sigdata.length = content.length; + sigdata.data = sigctx->content.data; + sigdata.length = sigctx->content.length; } - { AlgorithmIdentifier sigalg; ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG, - _hx509_cert_private_key(cert), peer, + _hx509_cert_private_key(cert), sigctx->peer, &sigalg); if (ret) goto out; @@ -1330,54 +1338,30 @@ hx509_cms_create_signed_1(hx509_context context, goto out; } - ALLOC_SEQ(&sd.digestAlgorithms, 1); - if (sd.digestAlgorithms.val == NULL) { - ret = ENOMEM; - hx509_clear_error_string(context); - goto out; - } - - ret = copy_AlgorithmIdentifier(&digest, &sd.digestAlgorithms.val[0]); - if (ret) { - hx509_clear_error_string(context); - goto out; - } + sigctx->sd.signerInfos.len++; + signer_info = NULL; /* * Provide best effort path */ - if (pool) { - _hx509_calculate_path(context, - HX509_CALCULATE_PATH_NO_ANCHOR, - time(NULL), - anchors, - 0, - cert, - pool, - &path); - } else - _hx509_path_append(context, &path, cert); + if (sigctx->certs) { + unsigned int i; - - if (path.len) { - int i; - - ALLOC(sd.certificates, 1); - if (sd.certificates == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } - ALLOC_SEQ(sd.certificates, path.len); - if (sd.certificates->val == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } + if (sigctx->pool) { + _hx509_calculate_path(context, + HX509_CALCULATE_PATH_NO_ANCHOR, + time(NULL), + sigctx->anchors, + 0, + cert, + sigctx->pool, + &path); + } else + _hx509_path_append(context, &path, cert); for (i = 0; i < path.len; i++) { - ret = hx509_cert_binary(context, path.val[i], - &sd.certificates->val[i]); + /* XXX remove dups */ + ret = hx509_certs_add(context, sigctx->certs, path.val[i]); if (ret) { hx509_clear_error_string(context); goto out; @@ -1385,9 +1369,152 @@ hx509_cms_create_signed_1(hx509_context context, } } + out: + if (signer_info) + free_SignerInfo(signer_info); + if (sigdata.data != sigctx->content.data) + der_free_octet_string(&sigdata); + _hx509_path_free(&path); + free_AlgorithmIdentifier(&digest); + + return ret; +} + +static int +cert_process(hx509_context context, void *ctx, hx509_cert cert) +{ + struct sigctx *sigctx = ctx; + const unsigned int i = sigctx->sd.certificates->len; + void *ptr; + int ret; + + ptr = realloc(sigctx->sd.certificates->val, + (i + 1) * sizeof(sigctx->sd.certificates->val[0])); + if (ptr == NULL) + return ENOMEM; + sigctx->sd.certificates->val = ptr; + + ret = hx509_cert_binary(context, cert, + &sigctx->sd.certificates->val[i]); + if (ret == 0) + sigctx->sd.certificates->len++; + + return ret; +} + +int +hx509_cms_create_signed(hx509_context context, + int flags, + const heim_oid *eContentType, + const void *data, size_t length, + const AlgorithmIdentifier *digest_alg, + hx509_certs certs, + hx509_peer_info peer, + hx509_certs anchors, + hx509_certs pool, + heim_octet_string *signed_data) +{ + unsigned int i; + hx509_name name; + int ret; + size_t size; + struct sigctx sigctx; + + memset(&sigctx, 0, sizeof(sigctx)); + memset(&name, 0, sizeof(name)); + + if (eContentType == NULL) + eContentType = oid_id_pkcs7_data(); + + sigctx.digest_alg = digest_alg; + sigctx.content.data = rk_UNCONST(data); + sigctx.content.length = length; + sigctx.eContentType = eContentType; + sigctx.peer = peer; + if (flags & HX509_CMS_SIGATURE_ID_NAME) + sigctx.cmsidflag = CMS_ID_NAME; + else + sigctx.cmsidflag = CMS_ID_SKI; + + ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs); + if (ret) + return ret; + + sigctx.anchors = anchors; + sigctx.pool = pool; + + sigctx.sd.version = CMSVersion_v3; + + der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); + + /** + * Use HX509_CMS_SIGATURE_DETACHED to create detached signatures. + */ + if ((flags & HX509_CMS_SIGATURE_DETACHED) == 0) { + ALLOC(sigctx.sd.encapContentInfo.eContent, 1); + if (sigctx.sd.encapContentInfo.eContent == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + sigctx.sd.encapContentInfo.eContent->data = malloc(length); + if (sigctx.sd.encapContentInfo.eContent->data == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length); + sigctx.sd.encapContentInfo.eContent->length = length; + } + + /** + * Use HX509_CMS_SIGATURE_NO_SIGNER to create no sigInfo (no + * sigatures). + */ + if ((flags & HX509_CMS_SIGATURE_NO_SIGNER) == 0) { + ret = hx509_certs_iter(context, certs, sig_process, &sigctx); + if (ret) + goto out; + } + + if (sigctx.sd.signerInfos.len) { + ALLOC_SEQ(&sigctx.sd.digestAlgorithms, sigctx.sd.signerInfos.len); + if (sigctx.sd.digestAlgorithms.val == NULL) { + ret = ENOMEM; + hx509_clear_error_string(context); + goto out; + } + + /* XXX remove dups */ + for (i = 0; i < sigctx.sd.signerInfos.len; i++) { + AlgorithmIdentifier *di = + &sigctx.sd.signerInfos.val[i].digestAlgorithm; + ret = copy_AlgorithmIdentifier(di, + &sigctx.sd.digestAlgorithms.val[i]); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + } + + if (sigctx.certs) { + ALLOC(sigctx.sd.certificates, 1); + if (sigctx.sd.certificates == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + ret = hx509_certs_iter(context, sigctx.certs, cert_process, &sigctx); + if (ret) + goto out; + } + ASN1_MALLOC_ENCODE(SignedData, signed_data->data, signed_data->length, - &sd, &size, ret); + &sigctx.sd, &size, ret); if (ret) { hx509_clear_error_string(context); goto out; @@ -1396,11 +1523,8 @@ hx509_cms_create_signed_1(hx509_context context, _hx509_abort("internal ASN.1 encoder error"); out: - if (sigdata.data != content.data) - der_free_octet_string(&sigdata); - free_AlgorithmIdentifier(&digest); - _hx509_path_free(&path); - free_SignedData(&sd); + hx509_certs_free(&sigctx.certs); + free_SignedData(&sigctx.sd); return ret; }