diff options
Diffstat (limited to 'crypto/heimdal/lib/hx509/cms.c')
-rw-r--r-- | crypto/heimdal/lib/hx509/cms.c | 1426 |
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 = ¶ms_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; -} |