summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/lib/hx509/cms.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/lib/hx509/cms.c')
-rw-r--r--crypto/heimdal/lib/hx509/cms.c1426
1 files changed, 0 insertions, 1426 deletions
diff --git a/crypto/heimdal/lib/hx509/cms.c b/crypto/heimdal/lib/hx509/cms.c
deleted file mode 100644
index 80bcaac..0000000
--- a/crypto/heimdal/lib/hx509/cms.c
+++ /dev/null
@@ -1,1426 +0,0 @@
-/*
- * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the Institute nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "hx_locl.h"
-RCSID("$Id: cms.c 22327 2007-12-15 04:49:37Z lha $");
-
-/**
- * @page page_cms CMS/PKCS7 message functions.
- *
- * CMS is defined in RFC 3369 and is an continuation of the RSA Labs
- * standard PKCS7. The basic messages in CMS is
- *
- * - SignedData
- * Data signed with private key (RSA, DSA, ECDSA) or secret
- * (symmetric) key
- * - EnvelopedData
- * Data encrypted with private key (RSA)
- * - EncryptedData
- * Data encrypted with secret (symmetric) key.
- * - ContentInfo
- * Wrapper structure including type and data.
- *
- *
- * See the library functions here: @ref hx509_cms
- */
-
-#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
-#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
-
-/**
- * Wrap data and oid in a ContentInfo and encode it.
- *
- * @param oid type of the content.
- * @param buf data to be wrapped. If a NULL pointer is passed in, the
- * optional content field in the ContentInfo is not going be filled
- * in.
- * @param res the encoded buffer, the result should be freed with
- * der_free_octet_string().
- *
- * @return Returns an hx509 error code.
- *
- * @ingroup hx509_cms
- */
-
-int
-hx509_cms_wrap_ContentInfo(const heim_oid *oid,
- const heim_octet_string *buf,
- heim_octet_string *res)
-{
- ContentInfo ci;
- size_t size;
- int ret;
-
- memset(res, 0, sizeof(*res));
- memset(&ci, 0, sizeof(ci));
-
- ret = der_copy_oid(oid, &ci.contentType);
- if (ret)
- return ret;
- if (buf) {
- ALLOC(ci.content, 1);
- if (ci.content == NULL) {
- free_ContentInfo(&ci);
- return ENOMEM;
- }
- ci.content->data = malloc(buf->length);
- if (ci.content->data == NULL) {
- free_ContentInfo(&ci);
- return ENOMEM;
- }
- memcpy(ci.content->data, buf->data, buf->length);
- ci.content->length = buf->length;
- }
-
- ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
- free_ContentInfo(&ci);
- if (ret)
- return ret;
- if (res->length != size)
- _hx509_abort("internal ASN.1 encoder error");
-
- return 0;
-}
-
-/**
- * Decode an ContentInfo and unwrap data and oid it.
- *
- * @param in the encoded buffer.
- * @param oid type of the content.
- * @param out data to be wrapped.
- * @param have_data since the data is optional, this flags show dthe
- * diffrence between no data and the zero length data.
- *
- * @return Returns an hx509 error code.
- *
- * @ingroup hx509_cms
- */
-
-int
-hx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
- heim_oid *oid,
- heim_octet_string *out,
- int *have_data)
-{
- ContentInfo ci;
- size_t size;
- int ret;
-
- memset(oid, 0, sizeof(*oid));
- memset(out, 0, sizeof(*out));
-
- ret = decode_ContentInfo(in->data, in->length, &ci, &size);
- if (ret)
- return ret;
-
- ret = der_copy_oid(&ci.contentType, oid);
- if (ret) {
- free_ContentInfo(&ci);
- return ret;
- }
- if (ci.content) {
- ret = der_copy_octet_string(ci.content, out);
- if (ret) {
- der_free_oid(oid);
- free_ContentInfo(&ci);
- return ret;
- }
- } else
- memset(out, 0, sizeof(*out));
-
- if (have_data)
- *have_data = (ci.content != NULL) ? 1 : 0;
-
- free_ContentInfo(&ci);
-
- return 0;
-}
-
-#define CMS_ID_SKI 0
-#define CMS_ID_NAME 1
-
-static int
-fill_CMSIdentifier(const hx509_cert cert,
- int type,
- CMSIdentifier *id)
-{
- int ret;
-
- switch (type) {
- case CMS_ID_SKI:
- id->element = choice_CMSIdentifier_subjectKeyIdentifier;
- ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert),
- &id->u.subjectKeyIdentifier);
- if (ret == 0)
- break;
- /* FALL THOUGH */
- case CMS_ID_NAME: {
- hx509_name name;
-
- id->element = choice_CMSIdentifier_issuerAndSerialNumber;
- ret = hx509_cert_get_issuer(cert, &name);
- if (ret)
- return ret;
- ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer);
- hx509_name_free(&name);
- if (ret)
- return ret;
-
- ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber);
- break;
- }
- default:
- _hx509_abort("CMS fill identifier with unknown type");
- }
- return ret;
-}
-
-static int
-unparse_CMSIdentifier(hx509_context context,
- CMSIdentifier *id,
- char **str)
-{
- int ret;
-
- *str = NULL;
- switch (id->element) {
- case choice_CMSIdentifier_issuerAndSerialNumber: {
- IssuerAndSerialNumber *iasn;
- char *serial, *name;
-
- iasn = &id->u.issuerAndSerialNumber;
-
- ret = _hx509_Name_to_string(&iasn->issuer, &name);
- if(ret)
- return ret;
- ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial);
- if (ret) {
- free(name);
- return ret;
- }
- asprintf(str, "certificate issued by %s with serial number %s",
- name, serial);
- free(name);
- free(serial);
- break;
- }
- case choice_CMSIdentifier_subjectKeyIdentifier: {
- KeyIdentifier *ki = &id->u.subjectKeyIdentifier;
- char *keyid;
- ssize_t len;
-
- len = hex_encode(ki->data, ki->length, &keyid);
- if (len < 0)
- return ENOMEM;
-
- asprintf(str, "certificate with id %s", keyid);
- free(keyid);
- break;
- }
- default:
- asprintf(str, "certificate have unknown CMSidentifier type");
- break;
- }
- if (*str == NULL)
- return ENOMEM;
- return 0;
-}
-
-static int
-find_CMSIdentifier(hx509_context context,
- CMSIdentifier *client,
- hx509_certs certs,
- hx509_cert *signer_cert,
- int match)
-{
- hx509_query q;
- hx509_cert cert;
- Certificate c;
- int ret;
-
- memset(&c, 0, sizeof(c));
- _hx509_query_clear(&q);
-
- *signer_cert = NULL;
-
- switch (client->element) {
- case choice_CMSIdentifier_issuerAndSerialNumber:
- q.serial = &client->u.issuerAndSerialNumber.serialNumber;
- q.issuer_name = &client->u.issuerAndSerialNumber.issuer;
- q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
- break;
- case choice_CMSIdentifier_subjectKeyIdentifier:
- q.subject_id = &client->u.subjectKeyIdentifier;
- q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
- break;
- default:
- hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE,
- "unknown CMS identifier element");
- return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
- }
-
- q.match |= match;
-
- q.match |= HX509_QUERY_MATCH_TIME;
- q.timenow = time(NULL);
-
- ret = hx509_certs_find(context, certs, &q, &cert);
- if (ret == HX509_CERT_NOT_FOUND) {
- char *str;
-
- ret = unparse_CMSIdentifier(context, client, &str);
- if (ret == 0) {
- hx509_set_error_string(context, 0,
- HX509_CMS_NO_RECIPIENT_CERTIFICATE,
- "Failed to find %s", str);
- } else
- hx509_clear_error_string(context);
- return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
- } else if (ret) {
- hx509_set_error_string(context, HX509_ERROR_APPEND,
- HX509_CMS_NO_RECIPIENT_CERTIFICATE,
- "Failed to find CMS id in cert store");
- return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
- }
-
- *signer_cert = cert;
-
- return 0;
-}
-
-/**
- * Decode and unencrypt EnvelopedData.
- *
- * Extract data and parameteres from from the EnvelopedData. Also
- * supports using detached EnvelopedData.
- *
- * @param context A hx509 context.
- * @param certs Certificate that can decrypt the EnvelopedData
- * encryption key.
- * @param flags HX509_CMS_UE flags to control the behavior.
- * @param data pointer the structure the contains the DER/BER encoded
- * EnvelopedData stucture.
- * @param length length of the data that data point to.
- * @param encryptedContent in case of detached signature, this
- * contains the actual encrypted data, othersize its should be NULL.
- * @param contentType output type oid, should be freed with der_free_oid().
- * @param content the data, free with der_free_octet_string().
- *
- * @ingroup hx509_cms
- */
-
-int
-hx509_cms_unenvelope(hx509_context context,
- hx509_certs certs,
- int flags,
- const void *data,
- size_t length,
- const heim_octet_string *encryptedContent,
- heim_oid *contentType,
- heim_octet_string *content)
-{
- heim_octet_string key;
- EnvelopedData ed;
- hx509_cert cert;
- AlgorithmIdentifier *ai;
- const heim_octet_string *enccontent;
- heim_octet_string *params, params_data;
- heim_octet_string ivec;
- size_t size;
- int ret, i, matched = 0, findflags = 0;
-
-
- memset(&key, 0, sizeof(key));
- memset(&ed, 0, sizeof(ed));
- memset(&ivec, 0, sizeof(ivec));
- memset(content, 0, sizeof(*content));
- memset(contentType, 0, sizeof(*contentType));
-
- if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
- findflags |= HX509_QUERY_KU_ENCIPHERMENT;
-
- ret = decode_EnvelopedData(data, length, &ed, &size);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to decode EnvelopedData");
- return ret;
- }
-
- if (ed.recipientInfos.len == 0) {
- ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
- hx509_set_error_string(context, 0, ret,
- "No recipient info in enveloped data");
- goto out;
- }
-
- enccontent = ed.encryptedContentInfo.encryptedContent;
- if (enccontent == NULL) {
- if (encryptedContent == NULL) {
- ret = HX509_CMS_NO_DATA_AVAILABLE;
- hx509_set_error_string(context, 0, ret,
- "Content missing from encrypted data");
- goto out;
- }
- enccontent = encryptedContent;
- } else if (encryptedContent != NULL) {
- ret = HX509_CMS_NO_DATA_AVAILABLE;
- hx509_set_error_string(context, 0, ret,
- "Both internal and external encrypted data");
- goto out;
- }
-
- cert = NULL;
- for (i = 0; i < ed.recipientInfos.len; i++) {
- KeyTransRecipientInfo *ri;
- char *str;
- int ret2;
-
- ri = &ed.recipientInfos.val[i];
-
- ret = find_CMSIdentifier(context, &ri->rid, certs, &cert,
- HX509_QUERY_PRIVATE_KEY|findflags);
- if (ret)
- continue;
-
- matched = 1; /* found a matching certificate, let decrypt */
-
- ret = _hx509_cert_private_decrypt(context,
- &ri->encryptedKey,
- &ri->keyEncryptionAlgorithm.algorithm,
- cert, &key);
-
- hx509_cert_free(cert);
- if (ret == 0)
- break; /* succuessfully decrypted cert */
- cert = NULL;
- ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
- if (ret2 == 0) {
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "Failed to decrypt with %s", str);
- free(str);
- }
- }
-
- if (!matched) {
- ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
- hx509_set_error_string(context, 0, ret,
- "No private key matched any certificate");
- goto out;
- }
-
- if (cert == NULL) {
- ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "No private key decrypted the transfer key");
- goto out;
- }
-
- ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to copy EnvelopedData content oid");
- goto out;
- }
-
- ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
- if (ai->parameters) {
- params_data.data = ai->parameters->data;
- params_data.length = ai->parameters->length;
- params = &params_data;
- } else
- params = NULL;
-
- {
- hx509_crypto crypto;
-
- ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
- if (ret)
- goto out;
-
- if (params) {
- ret = hx509_crypto_set_params(context, crypto, params, &ivec);
- if (ret) {
- hx509_crypto_destroy(crypto);
- goto out;
- }
- }
-
- ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
- if (ret) {
- hx509_crypto_destroy(crypto);
- hx509_set_error_string(context, 0, ret,
- "Failed to set key for decryption "
- "of EnvelopedData");
- goto out;
- }
-
- ret = hx509_crypto_decrypt(crypto,
- enccontent->data,
- enccontent->length,
- ivec.length ? &ivec : NULL,
- content);
- hx509_crypto_destroy(crypto);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to decrypt EnvelopedData");
- goto out;
- }
- }
-
-out:
-
- free_EnvelopedData(&ed);
- der_free_octet_string(&key);
- if (ivec.length)
- der_free_octet_string(&ivec);
- if (ret) {
- der_free_oid(contentType);
- der_free_octet_string(content);
- }
-
- return ret;
-}
-
-/**
- * Encrypt end encode EnvelopedData.
- *
- * Encrypt and encode EnvelopedData. The data is encrypted with a
- * random key and the the random key is encrypted with the
- * certificates private key. This limits what private key type can be
- * used to RSA.
- *
- * @param context A hx509 context.
- * @param flags flags to control the behavior, no flags today
- * @param cert Certificate to encrypt the EnvelopedData encryption key
- * with.
- * @param data pointer the data to encrypt.
- * @param length length of the data that data point to.
- * @param encryption_type Encryption cipher to use for the bulk data,
- * use NULL to get default.
- * @param contentType type of the data that is encrypted
- * @param content the output of the function,
- * free with der_free_octet_string().
- *
- * @ingroup hx509_cms
- */
-
-int
-hx509_cms_envelope_1(hx509_context context,
- int flags,
- hx509_cert cert,
- const void *data,
- size_t length,
- const heim_oid *encryption_type,
- const heim_oid *contentType,
- heim_octet_string *content)
-{
- KeyTransRecipientInfo *ri;
- heim_octet_string ivec;
- heim_octet_string key;
- hx509_crypto crypto = NULL;
- EnvelopedData ed;
- size_t size;
- int ret;
-
- memset(&ivec, 0, sizeof(ivec));
- memset(&key, 0, sizeof(key));
- memset(&ed, 0, sizeof(ed));
- memset(content, 0, sizeof(*content));
-
- if (encryption_type == NULL)
- encryption_type = oid_id_aes_256_cbc();
-
- ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
- if (ret)
- goto out;
-
- ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
- if (ret)
- goto out;
-
- ret = hx509_crypto_set_random_key(crypto, &key);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Create random key for EnvelopedData content");
- goto out;
- }
-
- ret = hx509_crypto_random_iv(crypto, &ivec);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to create a random iv");
- goto out;
- }
-
- ret = hx509_crypto_encrypt(crypto,
- data,
- length,
- &ivec,
- &ed.encryptedContentInfo.encryptedContent);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to encrypt EnvelopedData content");
- goto out;
- }
-
- {
- AlgorithmIdentifier *enc_alg;
- enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
- ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to set crypto oid "
- "for EnvelopedData");
- goto out;
- }
- ALLOC(enc_alg->parameters, 1);
- if (enc_alg->parameters == NULL) {
- ret = ENOMEM;
- hx509_set_error_string(context, 0, ret,
- "Failed to allocate crypto paramaters "
- "for EnvelopedData");
- goto out;
- }
-
- ret = hx509_crypto_get_params(context,
- crypto,
- &ivec,
- enc_alg->parameters);
- if (ret) {
- goto out;
- }
- }
-
- ALLOC_SEQ(&ed.recipientInfos, 1);
- if (ed.recipientInfos.val == NULL) {
- ret = ENOMEM;
- hx509_set_error_string(context, 0, ret,
- "Failed to allocate recipients info "
- "for EnvelopedData");
- goto out;
- }
-
- ri = &ed.recipientInfos.val[0];
-
- ri->version = 0;
- ret = fill_CMSIdentifier(cert, CMS_ID_SKI, &ri->rid);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to set CMS identifier info "
- "for EnvelopedData");
- goto out;
- }
-
- ret = _hx509_cert_public_encrypt(context,
- &key, cert,
- &ri->keyEncryptionAlgorithm.algorithm,
- &ri->encryptedKey);
- if (ret) {
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "Failed to encrypt transport key for "
- "EnvelopedData");
- goto out;
- }
-
- /*
- *
- */
-
- ed.version = 0;
- ed.originatorInfo = NULL;
-
- ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to copy content oid for "
- "EnvelopedData");
- goto out;
- }
-
- ed.unprotectedAttrs = NULL;
-
- ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
- &ed, &size, ret);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to encode EnvelopedData");
- goto out;
- }
- if (size != content->length)
- _hx509_abort("internal ASN.1 encoder error");
-
-out:
- if (crypto)
- hx509_crypto_destroy(crypto);
- if (ret)
- der_free_octet_string(content);
- der_free_octet_string(&key);
- der_free_octet_string(&ivec);
- free_EnvelopedData(&ed);
-
- return ret;
-}
-
-static int
-any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs)
-{
- int ret, i;
-
- if (sd->certificates == NULL)
- return 0;
-
- for (i = 0; i < sd->certificates->len; i++) {
- hx509_cert c;
-
- ret = hx509_cert_init_data(context,
- sd->certificates->val[i].data,
- sd->certificates->val[i].length,
- &c);
- if (ret)
- return ret;
- ret = hx509_certs_add(context, certs, c);
- hx509_cert_free(c);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static const Attribute *
-find_attribute(const CMSAttributes *attr, const heim_oid *oid)
-{
- int i;
- for (i = 0; i < attr->len; i++)
- if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0)
- return &attr->val[i];
- return NULL;
-}
-
-/**
- * Decode SignedData and verify that the signature is correct.
- *
- * @param context A hx509 context.
- * @param ctx a hx509 version context
- * @param data
- * @param length length of the data that data point to.
- * @param signedContent
- * @param pool certificate pool to build certificates paths.
- * @param contentType free with der_free_oid()
- * @param content the output of the function, free with
- * der_free_octet_string().
- * @param signer_certs list of the cerficates used to sign this
- * request, free with hx509_certs_free().
- *
- * @ingroup hx509_cms
- */
-
-int
-hx509_cms_verify_signed(hx509_context context,
- hx509_verify_ctx ctx,
- const void *data,
- size_t length,
- const heim_octet_string *signedContent,
- hx509_certs pool,
- heim_oid *contentType,
- heim_octet_string *content,
- hx509_certs *signer_certs)
-{
- SignerInfo *signer_info;
- hx509_cert cert = NULL;
- hx509_certs certs = NULL;
- SignedData sd;
- size_t size;
- int ret, i, found_valid_sig;
-
- *signer_certs = NULL;
- content->data = NULL;
- content->length = 0;
- contentType->length = 0;
- contentType->components = NULL;
-
- memset(&sd, 0, sizeof(sd));
-
- ret = decode_SignedData(data, length, &sd, &size);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to decode SignedData");
- goto out;
- }
-
- if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
- ret = HX509_CMS_NO_DATA_AVAILABLE;
- hx509_set_error_string(context, 0, ret,
- "No content data in SignedData");
- goto out;
- }
- if (sd.encapContentInfo.eContent && signedContent) {
- ret = HX509_CMS_NO_DATA_AVAILABLE;
- hx509_set_error_string(context, 0, ret,
- "Both external and internal SignedData");
- goto out;
- }
- if (sd.encapContentInfo.eContent)
- signedContent = sd.encapContentInfo.eContent;
-
- ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
- 0, NULL, &certs);
- if (ret)
- goto out;
-
- ret = hx509_certs_init(context, "MEMORY:cms-signer-certs",
- 0, NULL, signer_certs);
- if (ret)
- goto out;
-
- /* XXX Check CMS version */
-
- ret = any_to_certs(context, &sd, certs);
- if (ret)
- goto out;
-
- if (pool) {
- ret = hx509_certs_merge(context, certs, pool);
- if (ret)
- goto out;
- }
-
- for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
- heim_octet_string *signed_data;
- const heim_oid *match_oid;
- heim_oid decode_oid;
-
- signer_info = &sd.signerInfos.val[i];
- match_oid = NULL;
-
- if (signer_info->signature.length == 0) {
- ret = HX509_CMS_MISSING_SIGNER_DATA;
- hx509_set_error_string(context, 0, ret,
- "SignerInfo %d in SignedData "
- "missing sigature", i);
- continue;
- }
-
- ret = find_CMSIdentifier(context, &signer_info->sid, certs, &cert,
- HX509_QUERY_KU_DIGITALSIGNATURE);
- if (ret)
- continue;
-
- if (signer_info->signedAttrs) {
- const Attribute *attr;
-
- CMSAttributes sa;
- heim_octet_string os;
-
- sa.val = signer_info->signedAttrs->val;
- sa.len = signer_info->signedAttrs->len;
-
- /* verify that sigature exists */
- attr = find_attribute(&sa, oid_id_pkcs9_messageDigest());
- if (attr == NULL) {
- ret = HX509_CRYPTO_SIGNATURE_MISSING;
- hx509_set_error_string(context, 0, ret,
- "SignerInfo have signed attributes "
- "but messageDigest (signature) "
- "is missing");
- goto next_sigature;
- }
- if (attr->value.len != 1) {
- ret = HX509_CRYPTO_SIGNATURE_MISSING;
- hx509_set_error_string(context, 0, ret,
- "SignerInfo have more then one "
- "messageDigest (signature)");
- goto next_sigature;
- }
-
- ret = decode_MessageDigest(attr->value.val[0].data,
- attr->value.val[0].length,
- &os,
- &size);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to decode "
- "messageDigest (signature)");
- goto next_sigature;
- }
-
- ret = _hx509_verify_signature(context,
- NULL,
- &signer_info->digestAlgorithm,
- signedContent,
- &os);
- der_free_octet_string(&os);
- if (ret) {
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "Failed to verify messageDigest");
- goto next_sigature;
- }
-
- /*
- * Fetch content oid inside signedAttrs or set it to
- * id-pkcs7-data.
- */
- attr = find_attribute(&sa, oid_id_pkcs9_contentType());
- if (attr == NULL) {
- match_oid = oid_id_pkcs7_data();
- } else {
- if (attr->value.len != 1) {
- ret = HX509_CMS_DATA_OID_MISMATCH;
- hx509_set_error_string(context, 0, ret,
- "More then one oid in signedAttrs");
- goto next_sigature;
-
- }
- ret = decode_ContentType(attr->value.val[0].data,
- attr->value.val[0].length,
- &decode_oid,
- &size);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to decode "
- "oid in signedAttrs");
- goto next_sigature;
- }
- match_oid = &decode_oid;
- }
-
- ALLOC(signed_data, 1);
- if (signed_data == NULL) {
- if (match_oid == &decode_oid)
- der_free_oid(&decode_oid);
- ret = ENOMEM;
- hx509_clear_error_string(context);
- goto next_sigature;
- }
-
- ASN1_MALLOC_ENCODE(CMSAttributes,
- signed_data->data,
- signed_data->length,
- &sa,
- &size, ret);
- if (ret) {
- if (match_oid == &decode_oid)
- der_free_oid(&decode_oid);
- free(signed_data);
- hx509_clear_error_string(context);
- goto next_sigature;
- }
- if (size != signed_data->length)
- _hx509_abort("internal ASN.1 encoder error");
-
- } else {
- signed_data = rk_UNCONST(signedContent);
- match_oid = oid_id_pkcs7_data();
- }
-
- if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType)) {
- ret = HX509_CMS_DATA_OID_MISMATCH;
- hx509_set_error_string(context, 0, ret,
- "Oid in message mismatch from the expected");
- }
- if (match_oid == &decode_oid)
- der_free_oid(&decode_oid);
-
- if (ret == 0) {
- ret = hx509_verify_signature(context,
- cert,
- &signer_info->signatureAlgorithm,
- signed_data,
- &signer_info->signature);
- if (ret)
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "Failed to verify sigature in "
- "CMS SignedData");
- }
- if (signed_data != signedContent) {
- der_free_octet_string(signed_data);
- free(signed_data);
- }
- if (ret)
- goto next_sigature;
-
- ret = hx509_verify_path(context, ctx, cert, certs);
- if (ret)
- goto next_sigature;
-
- ret = hx509_certs_add(context, *signer_certs, cert);
- if (ret)
- goto next_sigature;
-
- found_valid_sig++;
-
- next_sigature:
- if (cert)
- hx509_cert_free(cert);
- cert = NULL;
- }
- if (found_valid_sig == 0) {
- if (ret == 0) {
- ret = HX509_CMS_SIGNER_NOT_FOUND;
- hx509_set_error_string(context, 0, ret,
- "No signers where found");
- }
- goto out;
- }
-
- ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
-
- content->data = malloc(signedContent->length);
- if (content->data == NULL) {
- hx509_clear_error_string(context);
- ret = ENOMEM;
- goto out;
- }
- content->length = signedContent->length;
- memcpy(content->data, signedContent->data, content->length);
-
-out:
- free_SignedData(&sd);
- if (certs)
- hx509_certs_free(&certs);
- if (ret) {
- if (*signer_certs)
- hx509_certs_free(signer_certs);
- der_free_oid(contentType);
- der_free_octet_string(content);
- }
-
- return ret;
-}
-
-static int
-add_one_attribute(Attribute **attr,
- unsigned int *len,
- const heim_oid *oid,
- heim_octet_string *data)
-{
- void *d;
- int ret;
-
- d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
- if (d == NULL)
- return ENOMEM;
- (*attr) = d;
-
- ret = der_copy_oid(oid, &(*attr)[*len].type);
- if (ret)
- return ret;
-
- ALLOC_SEQ(&(*attr)[*len].value, 1);
- if ((*attr)[*len].value.val == NULL) {
- der_free_oid(&(*attr)[*len].type);
- return ENOMEM;
- }
-
- (*attr)[*len].value.val[0].data = data->data;
- (*attr)[*len].value.val[0].length = data->length;
-
- *len += 1;
-
- return 0;
-}
-
-/**
- * Decode SignedData and verify that the signature is correct.
- *
- * @param context A hx509 context.
- * @param flags
- * @param eContentType the type of the data.
- * @param data data to sign
- * @param length length of the data that data point to.
- * @param digest_alg digest algorithm to use, use NULL to get the
- * default or the peer determined algorithm.
- * @param cert certificate to use for sign the data.
- * @param peer info about the peer the message to send the message to,
- * like what digest algorithm to use.
- * @param anchors trust anchors that the client will use, used to
- * polulate the certificates included in the message
- * @param pool certificates to use in try to build the path to the
- * trust anchors.
- * @param signed_data the output of the function, free with
- * der_free_octet_string().
- *
- * @ingroup hx509_cms
- */
-
-int
-hx509_cms_create_signed_1(hx509_context context,
- int flags,
- const heim_oid *eContentType,
- const void *data, size_t length,
- const AlgorithmIdentifier *digest_alg,
- hx509_cert cert,
- hx509_peer_info peer,
- hx509_certs anchors,
- hx509_certs pool,
- heim_octet_string *signed_data)
-{
- AlgorithmIdentifier digest;
- hx509_name name;
- SignerInfo *signer_info;
- heim_octet_string buf, content, sigdata = { 0, NULL };
- SignedData sd;
- int ret;
- size_t size;
- 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;
-
- if (_hx509_cert_private_key(cert) == NULL) {
- hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
- "Private key missing for signing");
- 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 (ret)
- hx509_clear_error_string(context);
- }
- if (ret)
- goto out;
-
- sd.version = CMSVersion_v3;
-
- 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);
- ret = ENOMEM;
- goto out;
- }
-
- signer_info = &sd.signerInfos.val[0];
-
- signer_info->version = 1;
-
- ret = fill_CMSIdentifier(cert, cmsidflag, &signer_info->sid);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
-
- signer_info->signedAttrs = NULL;
- signer_info->unsignedAttrs = NULL;
-
-
- ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
-
- /*
- * If it isn't pkcs7-data send signedAttributes
- */
-
- if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) {
- CMSAttributes sa;
- heim_octet_string sig;
-
- ALLOC(signer_info->signedAttrs, 1);
- if (signer_info->signedAttrs == NULL) {
- ret = ENOMEM;
- goto out;
- }
-
- ret = _hx509_create_signature(context,
- NULL,
- &digest,
- &content,
- NULL,
- &sig);
- if (ret)
- goto out;
-
- ASN1_MALLOC_ENCODE(MessageDigest,
- buf.data,
- buf.length,
- &sig,
- &size,
- ret);
- der_free_octet_string(&sig);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
- if (size != buf.length)
- _hx509_abort("internal ASN.1 encoder error");
-
- ret = add_one_attribute(&signer_info->signedAttrs->val,
- &signer_info->signedAttrs->len,
- oid_id_pkcs9_messageDigest(),
- &buf);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
-
-
- ASN1_MALLOC_ENCODE(ContentType,
- buf.data,
- buf.length,
- eContentType,
- &size,
- ret);
- if (ret)
- goto out;
- if (size != buf.length)
- _hx509_abort("internal ASN.1 encoder error");
-
- ret = add_one_attribute(&signer_info->signedAttrs->val,
- &signer_info->signedAttrs->len,
- oid_id_pkcs9_contentType(),
- &buf);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
-
- sa.val = signer_info->signedAttrs->val;
- sa.len = signer_info->signedAttrs->len;
-
- ASN1_MALLOC_ENCODE(CMSAttributes,
- sigdata.data,
- sigdata.length,
- &sa,
- &size,
- ret);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
- if (size != sigdata.length)
- _hx509_abort("internal ASN.1 encoder error");
- } else {
- sigdata.data = content.data;
- sigdata.length = content.length;
- }
-
-
- {
- AlgorithmIdentifier sigalg;
-
- ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
- _hx509_cert_private_key(cert), peer,
- &sigalg);
- if (ret)
- goto out;
-
- ret = _hx509_create_signature(context,
- _hx509_cert_private_key(cert),
- &sigalg,
- &sigdata,
- &signer_info->signatureAlgorithm,
- &signer_info->signature);
- free_AlgorithmIdentifier(&sigalg);
- if (ret)
- 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;
- }
-
- /*
- * 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 (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;
- }
-
- for (i = 0; i < path.len; i++) {
- ret = hx509_cert_binary(context, path.val[i],
- &sd.certificates->val[i]);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
- }
- }
-
- ASN1_MALLOC_ENCODE(SignedData,
- signed_data->data, signed_data->length,
- &sd, &size, ret);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
- if (signed_data->length != size)
- _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);
-
- return ret;
-}
-
-int
-hx509_cms_decrypt_encrypted(hx509_context context,
- hx509_lock lock,
- const void *data,
- size_t length,
- heim_oid *contentType,
- heim_octet_string *content)
-{
- heim_octet_string cont;
- CMSEncryptedData ed;
- AlgorithmIdentifier *ai;
- int ret;
-
- memset(content, 0, sizeof(*content));
- memset(&cont, 0, sizeof(cont));
-
- ret = decode_CMSEncryptedData(data, length, &ed, NULL);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to decode CMSEncryptedData");
- return ret;
- }
-
- if (ed.encryptedContentInfo.encryptedContent == NULL) {
- ret = HX509_CMS_NO_DATA_AVAILABLE;
- hx509_set_error_string(context, 0, ret,
- "No content in EncryptedData");
- goto out;
- }
-
- ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
-
- ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
- if (ai->parameters == NULL) {
- ret = HX509_ALG_NOT_SUPP;
- hx509_clear_error_string(context);
- goto out;
- }
-
- ret = _hx509_pbe_decrypt(context,
- lock,
- ai,
- ed.encryptedContentInfo.encryptedContent,
- &cont);
- if (ret)
- goto out;
-
- *content = cont;
-
-out:
- if (ret) {
- if (cont.data)
- free(cont.data);
- }
- free_CMSEncryptedData(&ed);
- return ret;
-}
OpenPOWER on IntegriCloud