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:
334
lib/hx509/cms.c
334
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user