From f4cc56f494b3f42642ea3b322e57737da80f889a Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 26 Mar 2008 13:10:21 +0000 Subject: Signed Receipt Request utility functions and option on CMS utility to print out receipt requests. --- apps/cms.c | 78 ++++++++++++++++++++ crypto/cms/Makefile | 4 +- crypto/cms/cms.h | 19 +++++ crypto/cms/cms_asn1.c | 5 +- crypto/cms/cms_err.c | 1 + crypto/cms/cms_ess.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++ crypto/cms/cms_lcl.h | 4 +- crypto/stack/safestack.h | 22 ++++++ crypto/x509v3/v3_genn.c | 92 ++++++++++++++++++++++++ 9 files changed, 403 insertions(+), 6 deletions(-) create mode 100644 crypto/cms/cms_ess.c diff --git a/apps/cms.c b/apps/cms.c index 9607ec5920..eb1dc3e9d9 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -70,6 +70,7 @@ #define PROG cms_main static int save_certs(char *signerfile, STACK_OF(X509) *signers); static int smime_cb(int ok, X509_STORE_CTX *ctx); +static void receipt_request_print(BIO *out, CMS_ContentInfo *cms); #define SMIME_OP 0x10 #define SMIME_IP 0x20 @@ -111,6 +112,7 @@ int MAIN(int argc, char **argv) BIO *in = NULL, *out = NULL, *indata = NULL; int badarg = 0; int flags = CMS_DETACHED, noout = 0, print = 0; + int rr_print = 0; char *to = NULL, *from = NULL, *subject = NULL; char *CAfile = NULL, *CApath = NULL; char *passargin = NULL, *passin = NULL; @@ -244,6 +246,8 @@ int MAIN(int argc, char **argv) flags |= CMS_CRLFEOL; else if (!strcmp (*args, "-noout")) noout = 1; + else if (!strcmp (*args, "-receipt_request_print")) + rr_print = 1; else if (!strcmp (*args, "-print")) { noout = 1; @@ -939,6 +943,9 @@ int MAIN(int argc, char **argv) } sk_X509_free(signers); } + if (rr_print) + receipt_request_print(bio_err, cms); + } else { @@ -1041,4 +1048,75 @@ static int smime_cb(int ok, X509_STORE_CTX *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); + } + } + #endif diff --git a/crypto/cms/Makefile b/crypto/cms/Makefile index a251164c8d..affda881a0 100644 --- a/crypto/cms/Makefile +++ b/crypto/cms/Makefile @@ -18,9 +18,9 @@ APPS= LIB=$(TOP)/libcrypto.a LIBSRC= cms_lib.c cms_asn1.c cms_att.c cms_io.c cms_smime.c cms_err.c \ - cms_sd.c cms_dd.c cms_cd.c cms_env.c cms_enc.c + cms_sd.c cms_dd.c cms_cd.c cms_env.c cms_enc.c cms_ess.c LIBOBJ= cms_lib.o cms_asn1.o cms_att.o cms_io.o cms_smime.o cms_err.o \ - cms_sd.o cms_dd.o cms_cd.o cms_env.o cms_enc.o + cms_sd.o cms_dd.o cms_cd.o cms_env.o cms_enc.o cms_ess.o SRC= $(LIBSRC) diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h index 797f86bb9c..15205bba47 100644 --- a/crypto/cms/cms.h +++ b/crypto/cms/cms.h @@ -75,7 +75,9 @@ typedef struct CMS_ReceiptRequest_st CMS_ReceiptRequest; typedef struct CMS_Receipt_st CMS_Receipt; DECLARE_STACK_OF(CMS_SignerInfo) +DECLARE_STACK_OF(GENERAL_NAMES) DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo) +DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest) DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo) #define CMS_SIGNERINFO_ISSUER_SERIAL 0 @@ -283,6 +285,22 @@ int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si, void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid, int lastpos, int type); +#ifdef HEADER_X509V3_H + +int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr); +int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, + unsigned char *id, int idlen, + int allorfirst, + STACK_OF(GENERAL_NAMES) *receiptList, + STACK_OF(GENERAL_NAMES) *receiptsTo); +void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, + ASN1_STRING **pcid, + int *pallorfirst, + STACK_OF(GENERAL_NAMES) **plist, + STACK_OF(GENERAL_NAMES) **prto); + +#endif + /* BEGIN ERROR CODES */ /* The following lines are auto generated by the script mkerr.pl. Any changes * made after this point may be overwritten when the script is next run. @@ -294,6 +312,7 @@ void ERR_load_CMS_strings(void); /* Function codes. */ #define CMS_F_CHECK_CONTENT 99 #define CMS_F_CMS_ADD0_RECIPIENT_KEY 100 +#define CMS_F_CMS_ADD1_RECEIPTREQUEST 158 #define CMS_F_CMS_ADD1_RECIPIENT_CERT 101 #define CMS_F_CMS_ADD1_SIGNER 102 #define CMS_F_CMS_ADD1_SIGNINGTIME 103 diff --git a/crypto/cms/cms_asn1.c b/crypto/cms/cms_asn1.c index bef043a8f0..2979993eb2 100644 --- a/crypto/cms/cms_asn1.c +++ b/crypto/cms/cms_asn1.c @@ -362,11 +362,12 @@ ASN1_ITEM_TEMPLATE_END(CMS_Attributes_Verify) ASN1_CHOICE(CMS_ReceiptsFrom) = { ASN1_IMP(CMS_ReceiptsFrom, d.allOrFirstTier, LONG, 0), - ASN1_IMP_SEQUENCE_OF(CMS_ReceiptsFrom, d.receiptList, GENERAL_NAME, 1) + ASN1_IMP_SEQUENCE_OF(CMS_ReceiptsFrom, d.receiptList, GENERAL_NAMES, 1) } ASN1_CHOICE_END(CMS_ReceiptsFrom) ASN1_SEQUENCE(CMS_ReceiptRequest) = { ASN1_SIMPLE(CMS_ReceiptRequest, signedContentIdentifier, ASN1_OCTET_STRING), - ASN1_SIMPLE(CMS_ReceiptRequest, receiptsFrom, CMS_ReceiptsFrom) + ASN1_SIMPLE(CMS_ReceiptRequest, receiptsFrom, CMS_ReceiptsFrom), + ASN1_SEQUENCE_OF(CMS_ReceiptRequest, receiptsTo, GENERAL_NAMES) } ASN1_SEQUENCE_END(CMS_ReceiptRequest) diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c index 51a3ade0cc..7b1294cac0 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -72,6 +72,7 @@ static ERR_STRING_DATA CMS_str_functs[]= { {ERR_FUNC(CMS_F_CHECK_CONTENT), "CHECK_CONTENT"}, {ERR_FUNC(CMS_F_CMS_ADD0_RECIPIENT_KEY), "CMS_add0_recipient_key"}, +{ERR_FUNC(CMS_F_CMS_ADD1_RECEIPTREQUEST), "CMS_ADD1_RECEIPTREQUEST"}, {ERR_FUNC(CMS_F_CMS_ADD1_RECIPIENT_CERT), "CMS_add1_recipient_cert"}, {ERR_FUNC(CMS_F_CMS_ADD1_SIGNER), "CMS_add1_signer"}, {ERR_FUNC(CMS_F_CMS_ADD1_SIGNINGTIME), "CMS_ADD1_SIGNINGTIME"}, diff --git a/crypto/cms/cms_ess.c b/crypto/cms/cms_ess.c new file mode 100644 index 0000000000..00cd9dcb43 --- /dev/null +++ b/crypto/cms/cms_ess.c @@ -0,0 +1,184 @@ +/* crypto/cms/cms_ess.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 OpenSSL PROJECT OR + * ITS 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 "cryptlib.h" +#include +#include +#include +#include +#include +#include +#include "cms_lcl.h" +#include "asn1_locl.h" + +DECLARE_ASN1_ITEM(CMS_ReceiptRequest) + +IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest) + +/* ESS services: for now just Signed Receipt related */ + +int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr) + { + ASN1_STRING *str; + CMS_ReceiptRequest *rr = NULL; + if (prr) + *prr = NULL; + str = CMS_signed_get0_data_by_OBJ(si, + OBJ_nid2obj(NID_id_smime_aa_receiptRequest), + -3, V_ASN1_SEQUENCE); + if (!str) + return 0; + + rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest)); + if (!rr) + return -1; + if (prr) + *prr = rr; + else + CMS_ReceiptRequest_free(rr); + return 1; + } + +int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, + unsigned char *id, int idlen, + int allorfirst, + STACK_OF(GENERAL_NAMES) *receiptList, + STACK_OF(GENERAL_NAMES) *receiptsTo) + { + CMS_ReceiptRequest *rr = NULL; + STACK_OF(GENERAL_NAMES) *tmpto = NULL; + unsigned char *rrder = NULL; + int rrderlen; + int r = 0; + + rr = CMS_ReceiptRequest_new(); + if (!rr) + goto merr; + if (id) + { + if (!ASN1_STRING_set(rr->signedContentIdentifier, id, idlen)) + goto merr; + } + else + { + if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32)) + goto merr; + if (RAND_pseudo_bytes(rr->signedContentIdentifier->data, 32) + <= 0) + goto err; + } + + tmpto = rr->receiptsTo; + rr->receiptsTo = receiptsTo; + + if (receiptList) + { + rr->receiptsFrom->type = 1; + rr->receiptsFrom->d.receiptList = receiptList; + } + else + { + rr->receiptsFrom->type = 0; + rr->receiptsFrom->d.allOrFirstTier = allorfirst; + } + + rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder); + + r = CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest, + V_ASN1_SEQUENCE, rrder, rrderlen); + + merr: + CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE); + + err: + if (rr) + { + rr->receiptsTo = tmpto; + rr->receiptsFrom->type = 0; + CMS_ReceiptRequest_free(rr); + } + if (rrder) + OPENSSL_free(rrder); + + return r; + + } + +void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, + ASN1_STRING **pcid, + int *pallorfirst, + STACK_OF(GENERAL_NAMES) **plist, + STACK_OF(GENERAL_NAMES) **prto) + { + if (pcid) + *pcid = rr->signedContentIdentifier; + if (rr->receiptsFrom->type == 0) + { + if (pallorfirst) + *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier; + if (plist) + *plist = NULL; + } + else + { + if (pallorfirst) + *pallorfirst = -1; + if (plist) + *plist = rr->receiptsFrom->d.receiptList; + } + if (prto) + *prto = rr->receiptsTo; + } + + + diff --git a/crypto/cms/cms_lcl.h b/crypto/cms/cms_lcl.h index 0956721938..5111617fdd 100644 --- a/crypto/cms/cms_lcl.h +++ b/crypto/cms/cms_lcl.h @@ -383,7 +383,7 @@ struct CMS_ReceiptRequest_st { ASN1_OCTET_STRING *signedContentIdentifier; CMS_ReceiptsFrom *receiptsFrom; - GENERAL_NAMES *receiptsTo; + STACK_OF(GENERAL_NAMES) *receiptsTo; }; @@ -393,7 +393,7 @@ struct CMS_ReceiptsFrom_st union { long allOrFirstTier; - GENERAL_NAMES *receiptList; + STACK_OF(GENERAL_NAMES) *receiptList; } d; }; #endif diff --git a/crypto/stack/safestack.h b/crypto/stack/safestack.h index 955275b361..c00b478e72 100644 --- a/crypto/stack/safestack.h +++ b/crypto/stack/safestack.h @@ -810,6 +810,28 @@ STACK_OF(type) \ #define sk_GENERAL_NAME_sort(st) SKM_sk_sort(GENERAL_NAME, (st)) #define sk_GENERAL_NAME_is_sorted(st) SKM_sk_is_sorted(GENERAL_NAME, (st)) +#define sk_GENERAL_NAMES_new(st) SKM_sk_new(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_new_null() SKM_sk_new_null(GENERAL_NAMES) +#define sk_GENERAL_NAMES_free(st) SKM_sk_free(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_num(st) SKM_sk_num(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_value(st, i) SKM_sk_value(GENERAL_NAMES, (st), (i)) +#define sk_GENERAL_NAMES_set(st, i, val) SKM_sk_set(GENERAL_NAMES, (st), (i), (val)) +#define sk_GENERAL_NAMES_zero(st) SKM_sk_zero(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_push(st, val) SKM_sk_push(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_unshift(st, val) SKM_sk_unshift(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_find(st, val) SKM_sk_find(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_find_ex(st, val) SKM_sk_find_ex(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_delete(st, i) SKM_sk_delete(GENERAL_NAMES, (st), (i)) +#define sk_GENERAL_NAMES_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_NAMES, (st), (ptr)) +#define sk_GENERAL_NAMES_insert(st, val, i) SKM_sk_insert(GENERAL_NAMES, (st), (val), (i)) +#define sk_GENERAL_NAMES_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_NAMES, (st), (cmp)) +#define sk_GENERAL_NAMES_dup(st) SKM_sk_dup(GENERAL_NAMES, st) +#define sk_GENERAL_NAMES_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_NAMES, (st), (free_func)) +#define sk_GENERAL_NAMES_shift(st) SKM_sk_shift(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_pop(st) SKM_sk_pop(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_sort(st) SKM_sk_sort(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_is_sorted(st) SKM_sk_is_sorted(GENERAL_NAMES, (st)) + #define sk_GENERAL_SUBTREE_new(st) SKM_sk_new(GENERAL_SUBTREE, (st)) #define sk_GENERAL_SUBTREE_new_null() SKM_sk_new_null(GENERAL_SUBTREE) #define sk_GENERAL_SUBTREE_free(st) SKM_sk_free(GENERAL_SUBTREE, (st)) diff --git a/crypto/x509v3/v3_genn.c b/crypto/x509v3/v3_genn.c index 363f2d32d5..2a80586276 100644 --- a/crypto/x509v3/v3_genn.c +++ b/crypto/x509v3/v3_genn.c @@ -158,3 +158,95 @@ int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b) result = ASN1_TYPE_cmp(a->value, b->value); return result; } + +void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value) + { + switch(type) + { + case GEN_X400: + case GEN_EDIPARTY: + a->d.other = value; + break; + + case GEN_OTHERNAME: + a->d.otherName = value; + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + a->d.ia5 = value; + break; + + case GEN_DIRNAME: + a->d.dirn = value; + break; + + case GEN_IPADD: + a->d.ip = value; + break; + + case GEN_RID: + a->d.rid = value; + break; + } + a->type = type; + } + +void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype) + { + if (ptype) + *ptype = a->type; + switch(a->type) + { + case GEN_X400: + case GEN_EDIPARTY: + return a->d.other; + + case GEN_OTHERNAME: + return a->d.otherName; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + return a->d.ia5; + + case GEN_DIRNAME: + return a->d.dirn; + + case GEN_IPADD: + return a->d.ip; + + case GEN_RID: + return a->d.rid; + + default: + return NULL; + } + } + +int GENERAL_NAME_set0_othername(GENERAL_NAME *gen, + ASN1_OBJECT *oid, ASN1_TYPE *value) + { + OTHERNAME *oth; + oth = OTHERNAME_new(); + if (!oth) + return 0; + oth->type_id = oid; + oth->value = value; + GENERAL_NAME_set0_value(gen, GEN_OTHERNAME, oth); + return 1; + } + +int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen, + ASN1_OBJECT **poid, ASN1_TYPE **pvalue) + { + if (gen->type != GEN_OTHERNAME) + return 0; + if (poid) + *poid = gen->d.otherName->type_id; + if (pvalue) + *pvalue = gen->d.otherName->value; + return 1; + } + -- cgit v1.2.3