Skip to content
cms.c 47 KiB
Newer Older
            if (!si)
                goto end;
            if (kparam) {
                EVP_PKEY_CTX *pctx;
                pctx = CMS_SignerInfo_get0_pkey_ctx(si);
                if (!cms_set_pkey_param(pctx, kparam->param))
                    goto end;
            }
            if (rr && !CMS_add1_ReceiptRequest(si, rr))
                goto end;
            X509_free(signer);
            signer = NULL;
            EVP_PKEY_free(key);
            key = NULL;
        }
        /* If not streaming or resigning finalize structure */
        if ((operation == SMIME_SIGN) && !(flags & CMS_STREAM)) {
            if (!CMS_final(cms, in, NULL, flags))
                goto end;
        }
    }

    if (!cms) {
        BIO_printf(bio_err, "Error creating CMS structure\n");
        goto end;
    }

    ret = 4;
    if (operation == SMIME_DECRYPT) {
        if (flags & CMS_DEBUG_DECRYPT)
            CMS_decrypt(cms, NULL, NULL, NULL, NULL, flags);

        if (secret_key) {
            if (!CMS_decrypt_set1_key(cms,
                                      secret_key, secret_keylen,
                                      secret_keyid, secret_keyidlen)) {
                BIO_puts(bio_err, "Error decrypting CMS using secret key\n");
                goto end;
            }
        }

        if (key) {
            if (!CMS_decrypt_set1_pkey(cms, key, recip)) {
                BIO_puts(bio_err, "Error decrypting CMS using private key\n");
                goto end;
            }
        }

        if (pwri_pass) {
            if (!CMS_decrypt_set1_password(cms, pwri_pass, -1)) {
                BIO_puts(bio_err, "Error decrypting CMS using password\n");
                goto end;
            }
        }

        if (!CMS_decrypt(cms, NULL, NULL, indata, out, flags)) {
            BIO_printf(bio_err, "Error decrypting CMS structure\n");
            goto end;
        }
    } else if (operation == SMIME_DATAOUT) {
        if (!CMS_data(cms, out, flags))
            goto end;
    } else if (operation == SMIME_UNCOMPRESS) {
        if (!CMS_uncompress(cms, indata, out, flags))
            goto end;
    } else if (operation == SMIME_DIGEST_VERIFY) {
        if (CMS_digest_verify(cms, indata, out, flags) > 0)
            BIO_printf(bio_err, "Verification successful\n");
        else {
            BIO_printf(bio_err, "Verification failure\n");
            goto end;
        }
    } else if (operation == SMIME_ENCRYPTED_DECRYPT) {
        if (!CMS_EncryptedData_decrypt(cms, secret_key, secret_keylen,
                                       indata, out, flags))
            goto end;
    } else if (operation == SMIME_VERIFY) {
        if (CMS_verify(cms, other, store, indata, out, flags) > 0)
            BIO_printf(bio_err, "Verification successful\n");
        else {
            BIO_printf(bio_err, "Verification failure\n");
            if (verify_retcode)
                ret = verify_err + 32;
            goto end;
        }
        if (signerfile) {
            STACK_OF(X509) *signers;
            signers = CMS_get0_signers(cms);
            if (!save_certs(signerfile, signers)) {
                BIO_printf(bio_err,
                           "Error writing signers to %s\n", signerfile);
                ret = 5;
                goto end;
            }
            sk_X509_free(signers);
        }
        if (rr_print)
            receipt_request_print(bio_err, cms);

    } else if (operation == SMIME_VERIFY_RECEIPT) {
        if (CMS_verify_receipt(rcms, cms, other, store, flags) > 0)
            BIO_printf(bio_err, "Verification successful\n");
        else {
            BIO_printf(bio_err, "Verification failure\n");
            goto end;
        }
    } else {
        if (noout) {
            if (print)
                CMS_ContentInfo_print_ctx(out, cms, 0, NULL);
        } else if (outformat == FORMAT_SMIME) {
            if (to)
                BIO_printf(out, "To: %s\n", to);
            if (from)
                BIO_printf(out, "From: %s\n", from);
            if (subject)
                BIO_printf(out, "Subject: %s\n", subject);
            if (operation == SMIME_RESIGN)
                ret = SMIME_write_CMS(out, cms, indata, flags);
            else
                ret = SMIME_write_CMS(out, cms, in, flags);
        } else if (outformat == FORMAT_PEM)
            ret = PEM_write_bio_CMS_stream(out, cms, in, flags);
        else if (outformat == FORMAT_ASN1)
            ret = i2d_CMS_bio_stream(out, cms, in, flags);
        else {
            BIO_printf(bio_err, "Bad output format for CMS file\n");
            goto end;
        }
        if (ret <= 0) {
            ret = 6;
            goto end;
        }
    }
    ret = 0;
 end:
    if (ret)
        ERR_print_errors(bio_err);
    if (need_rand)
        app_RAND_write_file(NULL, bio_err);
    sk_X509_pop_free(encerts, X509_free);
    sk_X509_pop_free(other, X509_free);
    if (vpm)
        X509_VERIFY_PARAM_free(vpm);
    if (sksigners)
        sk_OPENSSL_STRING_free(sksigners);
    if (skkeys)
        sk_OPENSSL_STRING_free(skkeys);
    if (secret_key)
        OPENSSL_free(secret_key);
    if (secret_keyid)
        OPENSSL_free(secret_keyid);
    if (pwri_tmp)
        OPENSSL_free(pwri_tmp);
    if (econtent_type)
        ASN1_OBJECT_free(econtent_type);
    if (rr)
        CMS_ReceiptRequest_free(rr);
    if (rr_to)
        sk_OPENSSL_STRING_free(rr_to);
    if (rr_from)
        sk_OPENSSL_STRING_free(rr_from);
    for (key_param = key_first; key_param;) {
        cms_key_param *tparam;
        sk_OPENSSL_STRING_free(key_param->param);
        tparam = key_param->next;
        OPENSSL_free(key_param);
        key_param = tparam;
    }
    X509_STORE_free(store);
    X509_free(cert);
    X509_free(recip);
    X509_free(signer);
    EVP_PKEY_free(key);
    CMS_ContentInfo_free(cms);
    CMS_ContentInfo_free(rcms);
    BIO_free(rctin);
    BIO_free(in);
    BIO_free(indata);
    BIO_free_all(out);
    if (passin)
        OPENSSL_free(passin);
    return (ret);
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
}

static int save_certs(char *signerfile, STACK_OF(X509) *signers)
{
    int i;
    BIO *tmp;
    if (!signerfile)
        return 1;
    tmp = BIO_new_file(signerfile, "w");
    if (!tmp)
        return 0;
    for (i = 0; i < sk_X509_num(signers); i++)
        PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
    BIO_free(tmp);
    return 1;
}
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed

/* Minimal callback just to output policy info (if any) */

static int cms_cb(int ok, X509_STORE_CTX *ctx)
    error = X509_STORE_CTX_get_error(ctx);
    verify_err = error;
    if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
        && ((error != X509_V_OK) || (ok != 2)))
        return ok;
    policies_print(NULL, ctx);
static void gnames_stack_print(BIO *out, STACK_OF(GENERAL_NAMES) *gns)
{
    STACK_OF(GENERAL_NAME) *gens;
    GENERAL_NAME *gen;
    int i, j;
    for (i = 0; i < sk_GENERAL_NAMES_num(gns); i++) {
        gens = sk_GENERAL_NAMES_value(gns, i);
        for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
            gen = sk_GENERAL_NAME_value(gens, j);
            BIO_puts(out, "    ");
            GENERAL_NAME_print(out, gen);
            BIO_puts(out, "\n");
        }
    }
    return;
}

static void receipt_request_print(BIO *out, CMS_ContentInfo *cms)
{
    STACK_OF(CMS_SignerInfo) *sis;
    CMS_SignerInfo *si;
    CMS_ReceiptRequest *rr;
    int allorfirst;
    STACK_OF(GENERAL_NAMES) *rto, *rlist;
    ASN1_STRING *scid;
    int i, rv;
    sis = CMS_get0_SignerInfos(cms);
    for (i = 0; i < sk_CMS_SignerInfo_num(sis); i++) {
        si = sk_CMS_SignerInfo_value(sis, i);
        rv = CMS_get1_ReceiptRequest(si, &rr);
        BIO_printf(bio_err, "Signer %d:\n", i + 1);
        if (rv == 0)
            BIO_puts(bio_err, "  No Receipt Request\n");
        else if (rv < 0) {
            BIO_puts(bio_err, "  Receipt Request Parse Error\n");
            ERR_print_errors(bio_err);
        } else {
            char *id;
            int idlen;
            CMS_ReceiptRequest_get0_values(rr, &scid, &allorfirst,
                                           &rlist, &rto);
            BIO_puts(out, "  Signed Content ID:\n");
            idlen = ASN1_STRING_length(scid);
            id = (char *)ASN1_STRING_data(scid);
            BIO_dump_indent(out, id, idlen, 4);
            BIO_puts(out, "  Receipts From");
            if (rlist) {
                BIO_puts(out, " List:\n");
                gnames_stack_print(out, rlist);
            } else if (allorfirst == 1)
                BIO_puts(out, ": First Tier\n");
            else if (allorfirst == 0)
                BIO_puts(out, ": All\n");
            else
                BIO_printf(out, " Unknown (%d)\n", allorfirst);
            BIO_puts(out, "  Receipts To:\n");
            gnames_stack_print(out, rto);
        }
        if (rr)
            CMS_ReceiptRequest_free(rr);
    }
}
static STACK_OF(GENERAL_NAMES) *make_names_stack(STACK_OF(OPENSSL_STRING) *ns)
{
    int i;
    STACK_OF(GENERAL_NAMES) *ret;
    GENERAL_NAMES *gens = NULL;
    GENERAL_NAME *gen = NULL;
    ret = sk_GENERAL_NAMES_new_null();
    if (!ret)
        goto err;
    for (i = 0; i < sk_OPENSSL_STRING_num(ns); i++) {
        char *str = sk_OPENSSL_STRING_value(ns, i);
        gen = a2i_GENERAL_NAME(NULL, NULL, NULL, GEN_EMAIL, str, 0);
        if (!gen)
            goto err;
        gens = GENERAL_NAMES_new();
        if (!gens)
            goto err;
        if (!sk_GENERAL_NAME_push(gens, gen))
            goto err;
        gen = NULL;
        if (!sk_GENERAL_NAMES_push(ret, gens))
            goto err;
        gens = NULL;
    }

    return ret;

 err:
    if (ret)
        sk_GENERAL_NAMES_pop_free(ret, GENERAL_NAMES_free);
    if (gens)
        GENERAL_NAMES_free(gens);
    if (gen)
        GENERAL_NAME_free(gen);
    return NULL;
}

static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING)
                                                *rr_to, int rr_allorfirst, STACK_OF(OPENSSL_STRING)
                                                *rr_from)
{
    STACK_OF(GENERAL_NAMES) *rct_to, *rct_from;
    CMS_ReceiptRequest *rr;
    rct_to = make_names_stack(rr_to);
    if (!rct_to)
        goto err;
    if (rr_from) {
        rct_from = make_names_stack(rr_from);
        if (!rct_from)
            goto err;
    } else
        rct_from = NULL;
    rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from,
                                    rct_to);
    return rr;
 err:
    return NULL;
}
static int cms_set_pkey_param(EVP_PKEY_CTX *pctx,
                              STACK_OF(OPENSSL_STRING) *param)
{
    char *keyopt;
    int i;
    if (sk_OPENSSL_STRING_num(param) <= 0)
        return 1;
    for (i = 0; i < sk_OPENSSL_STRING_num(param); i++) {
        keyopt = sk_OPENSSL_STRING_value(param, i);
        if (pkey_ctrl_string(pctx, keyopt) <= 0) {
            BIO_printf(bio_err, "parameter error \"%s\"\n", keyopt);
            ERR_print_errors(bio_err);
            return 0;
        }
    }
    return 1;
}
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
#endif