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, hx509_certs pool,
heim_octet_string *signed_data) heim_octet_string *signed_data)
{ {
AlgorithmIdentifier digest; hx509_certs certs;
hx509_name name; int ret = 0;
SignerInfo *signer_info;
heim_octet_string buf, content, sigdata = { 0, NULL }; 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; 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; size_t size;
void *ptr;
int ret;
SignedData *sd = &sigctx->sd;
hx509_path path; 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)); memset(&digest, 0, sizeof(digest));
memset(&path, 0, sizeof(path));
content.data = rk_UNCONST(data);
content.length = length;
if (flags & HX509_CMS_SIGATURE_ID_NAME)
cmsidflag = CMS_ID_NAME;
if (_hx509_cert_private_key(cert) == NULL) { if (_hx509_cert_private_key(cert) == NULL) {
hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, 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; return HX509_PRIVATE_KEY_MISSING;
} }
if (digest_alg == NULL) { if (sigctx->digest_alg) {
ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest);
_hx509_cert_private_key(cert), peer, &digest);
} else {
ret = copy_AlgorithmIdentifier(digest_alg, &digest);
if (ret) if (ret)
hx509_clear_error_string(context); hx509_clear_error_string(context);
} else {
ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
_hx509_cert_private_key(cert),
sigctx->peer, &digest);
} }
if (ret) if (ret)
goto out; goto out;
sd.version = CMSVersion_v3; /*
* Allocate on more signerInfo and do the signature processing
*/
if (eContentType == NULL) ptr = realloc(sd->signerInfos.val,
eContentType = oid_id_pkcs7_data(); (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0]));
if (ptr == NULL) {
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);
ret = ENOMEM; ret = ENOMEM;
goto out; 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; signer_info->version = 1;
ret = fill_CMSIdentifier(cert, cmsidflag, &signer_info->sid); ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid);
if (ret) { if (ret) {
hx509_clear_error_string(context); hx509_clear_error_string(context);
goto out; goto out;
@@ -1215,7 +1223,6 @@ hx509_cms_create_signed_1(hx509_context context,
signer_info->signedAttrs = NULL; signer_info->signedAttrs = NULL;
signer_info->unsignedAttrs = NULL; signer_info->unsignedAttrs = NULL;
ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
if (ret) { if (ret) {
hx509_clear_error_string(context); 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 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; CMSAttributes sa;
heim_octet_string sig; heim_octet_string sig;
@@ -1239,7 +1246,7 @@ hx509_cms_create_signed_1(hx509_context context,
ret = _hx509_create_signature(context, ret = _hx509_create_signature(context,
NULL, NULL,
&digest, &digest,
&content, &sigctx->content,
NULL, NULL,
&sig); &sig);
if (ret) if (ret)
@@ -1264,6 +1271,7 @@ hx509_cms_create_signed_1(hx509_context context,
oid_id_pkcs9_messageDigest(), oid_id_pkcs9_messageDigest(),
&buf); &buf);
if (ret) { if (ret) {
free(buf.data);
hx509_clear_error_string(context); hx509_clear_error_string(context);
goto out; goto out;
} }
@@ -1272,7 +1280,7 @@ hx509_cms_create_signed_1(hx509_context context,
ASN1_MALLOC_ENCODE(ContentType, ASN1_MALLOC_ENCODE(ContentType,
buf.data, buf.data,
buf.length, buf.length,
eContentType, sigctx->eContentType,
&size, &size,
ret); ret);
if (ret) if (ret)
@@ -1285,6 +1293,7 @@ hx509_cms_create_signed_1(hx509_context context,
oid_id_pkcs9_contentType(), oid_id_pkcs9_contentType(),
&buf); &buf);
if (ret) { if (ret) {
free(buf.data);
hx509_clear_error_string(context); hx509_clear_error_string(context);
goto out; goto out;
} }
@@ -1305,16 +1314,15 @@ hx509_cms_create_signed_1(hx509_context context,
if (size != sigdata.length) if (size != sigdata.length)
_hx509_abort("internal ASN.1 encoder error"); _hx509_abort("internal ASN.1 encoder error");
} else { } else {
sigdata.data = content.data; sigdata.data = sigctx->content.data;
sigdata.length = content.length; sigdata.length = sigctx->content.length;
} }
{ {
AlgorithmIdentifier sigalg; AlgorithmIdentifier sigalg;
ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG, ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
_hx509_cert_private_key(cert), peer, _hx509_cert_private_key(cert), sigctx->peer,
&sigalg); &sigalg);
if (ret) if (ret)
goto out; goto out;
@@ -1330,54 +1338,30 @@ hx509_cms_create_signed_1(hx509_context context,
goto out; goto out;
} }
ALLOC_SEQ(&sd.digestAlgorithms, 1); sigctx->sd.signerInfos.len++;
if (sd.digestAlgorithms.val == NULL) { signer_info = 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;
}
/* /*
* Provide best effort path * Provide best effort path
*/ */
if (pool) { if (sigctx->certs) {
_hx509_calculate_path(context, unsigned int i;
HX509_CALCULATE_PATH_NO_ANCHOR,
time(NULL),
anchors,
0,
cert,
pool,
&path);
} else
_hx509_path_append(context, &path, cert);
if (sigctx->pool) {
if (path.len) { _hx509_calculate_path(context,
int i; HX509_CALCULATE_PATH_NO_ANCHOR,
time(NULL),
ALLOC(sd.certificates, 1); sigctx->anchors,
if (sd.certificates == NULL) { 0,
hx509_clear_error_string(context); cert,
ret = ENOMEM; sigctx->pool,
goto out; &path);
} } else
ALLOC_SEQ(sd.certificates, path.len); _hx509_path_append(context, &path, cert);
if (sd.certificates->val == NULL) {
hx509_clear_error_string(context);
ret = ENOMEM;
goto out;
}
for (i = 0; i < path.len; i++) { for (i = 0; i < path.len; i++) {
ret = hx509_cert_binary(context, path.val[i], /* XXX remove dups */
&sd.certificates->val[i]); ret = hx509_certs_add(context, sigctx->certs, path.val[i]);
if (ret) { if (ret) {
hx509_clear_error_string(context); hx509_clear_error_string(context);
goto out; 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, ASN1_MALLOC_ENCODE(SignedData,
signed_data->data, signed_data->length, signed_data->data, signed_data->length,
&sd, &size, ret); &sigctx.sd, &size, ret);
if (ret) { if (ret) {
hx509_clear_error_string(context); hx509_clear_error_string(context);
goto out; goto out;
@@ -1396,11 +1523,8 @@ hx509_cms_create_signed_1(hx509_context context,
_hx509_abort("internal ASN.1 encoder error"); _hx509_abort("internal ASN.1 encoder error");
out: out:
if (sigdata.data != content.data) hx509_certs_free(&sigctx.certs);
der_free_octet_string(&sigdata); free_SignedData(&sigctx.sd);
free_AlgorithmIdentifier(&digest);
_hx509_path_free(&path);
free_SignedData(&sd);
return ret; return ret;
} }