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
This commit is contained in:
Love Hörnquist Åstrand
2009-02-04 22:04:28 +00:00
parent f0214c8843
commit 90a9ed5fd2

View File

@@ -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;
}