diff options
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | crypto/asn1/Makefile | 4 | ||||
-rw-r--r-- | crypto/asn1/asn1.h | 2 | ||||
-rw-r--r-- | crypto/asn1/bio_asn1.c | 495 | ||||
-rw-r--r-- | crypto/bio/bio.h | 21 | ||||
-rw-r--r-- | crypto/pkcs7/Makefile | 4 | ||||
-rw-r--r-- | crypto/pkcs7/bio_pk7.c | 200 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_lib.c | 50 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_smime.c | 3 | ||||
-rw-r--r-- | crypto/pkcs7/pkcs7.h | 1 |
10 files changed, 780 insertions, 4 deletions
@@ -4,6 +4,10 @@ Changes between 0.9.8e and 0.9.9 [xx XXX xxxx] + *) Very *very* experimental PKCS#7 streaming encoder support. Nothing uses + it yet and it is largely untested. + [Steve Henson] + *) Add support for the ecdsa-with-SHA224/256/384/512 signature types. [Nils Larsch] diff --git a/crypto/asn1/Makefile b/crypto/asn1/Makefile index 30a91d0ef4..9890b062e4 100644 --- a/crypto/asn1/Makefile +++ b/crypto/asn1/Makefile @@ -27,7 +27,7 @@ LIBSRC= a_object.c a_bitstr.c a_utctm.c a_gentm.c a_time.c a_int.c a_octet.c \ tasn_new.c tasn_fre.c tasn_enc.c tasn_dec.c tasn_utl.c tasn_typ.c \ tasn_prn.c ameth_lib.c \ f_int.c f_string.c n_pkey.c \ - f_enum.c x_pkey.c a_bool.c x_exten.c \ + f_enum.c x_pkey.c a_bool.c x_exten.c bio_asn1.c \ asn1_gen.c asn1_par.c asn1_lib.c asn1_err.c a_bytes.c a_strnid.c \ evp_asn1.c asn_pack.c p5_pbe.c p5_pbev2.c p8_pkey.c asn_moid.c LIBOBJ= a_object.o a_bitstr.o a_utctm.o a_gentm.o a_time.o a_int.o a_octet.o \ @@ -40,7 +40,7 @@ LIBOBJ= a_object.o a_bitstr.o a_utctm.o a_gentm.o a_time.o a_int.o a_octet.o \ tasn_new.o tasn_fre.o tasn_enc.o tasn_dec.o tasn_utl.o tasn_typ.o \ tasn_prn.o ameth_lib.o \ f_int.o f_string.o n_pkey.o \ - f_enum.o x_pkey.o a_bool.o x_exten.o \ + f_enum.o x_pkey.o a_bool.o x_exten.o bio_asn1.o \ asn1_gen.o asn1_par.o asn1_lib.o asn1_err.o a_bytes.o a_strnid.o \ evp_asn1.o asn_pack.o p5_pbe.o p5_pbev2.o p8_pkey.o asn_moid.o diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index bb8992c063..bed43ab669 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h @@ -1051,6 +1051,8 @@ void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags); unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p); void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags); +BIO_METHOD *BIO_f_asn1(void); + /* 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. diff --git a/crypto/asn1/bio_asn1.c b/crypto/asn1/bio_asn1.c new file mode 100644 index 0000000000..854a52d3d5 --- /dev/null +++ b/crypto/asn1/bio_asn1.c @@ -0,0 +1,495 @@ +/* bio_asn1.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2006 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. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* Experimental ASN1 BIO. When written through the data is converted + * to an ASN1 string type: default is OCTET STRING. Additional functions + * can be provided to add prefix and suffix data. + */ + +#include <string.h> +#include <openssl/bio.h> +#include <openssl/asn1.h> + +/* Must be large enough for biggest tag+length */ +#define DEFAULT_ASN1_BUF_SIZE 20 + +typedef enum + { + ASN1_STATE_START, + ASN1_STATE_PRE_COPY, + ASN1_STATE_HEADER, + ASN1_STATE_HEADER_COPY, + ASN1_STATE_DATA_COPY, + ASN1_STATE_POST_COPY, + ASN1_STATE_DONE + } asn1_bio_state_t; + +typedef struct BIO_ASN1_EX_FUNCS_st + { + asn1_ps_func *ex_func; + asn1_ps_func *ex_free_func; + } BIO_ASN1_EX_FUNCS; + +typedef struct BIO_ASN1_BUF_CTX_t + { + /* Internal state */ + asn1_bio_state_t state; + /* Internal buffer */ + unsigned char *buf; + /* Size of buffer */ + int bufsize; + /* Current position in buffer */ + int bufpos; + /* Current buffer length */ + int buflen; + /* Amount of data to copy */ + int copylen; + /* Class and tag to use */ + int asn1_class, asn1_tag; + asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free; + /* Extra buffer for prefix and suffix data */ + unsigned char *ex_buf; + int ex_len; + int ex_pos; + void *ex_arg; + } BIO_ASN1_BUF_CTX; + + +static int asn1_bio_write(BIO *h, const char *buf,int num); +static int asn1_bio_read(BIO *h, char *buf, int size); +static int asn1_bio_puts(BIO *h, const char *str); +static int asn1_bio_gets(BIO *h, char *str, int size); +static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int asn1_bio_new(BIO *h); +static int asn1_bio_free(BIO *data); +static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); + +static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size); +static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *cleanup, asn1_bio_state_t next); +static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *setup, + asn1_bio_state_t ex_state, + asn1_bio_state_t other_state); + +static BIO_METHOD methods_asn1= + { + BIO_TYPE_ASN1, + "asn1", + asn1_bio_write, + asn1_bio_read, + asn1_bio_puts, + asn1_bio_gets, + asn1_bio_ctrl, + asn1_bio_new, + asn1_bio_free, + asn1_bio_callback_ctrl, + }; + +BIO_METHOD *BIO_f_asn1(void) + { + return(&methods_asn1); + } + + +static int asn1_bio_new(BIO *b) + { + BIO_ASN1_BUF_CTX *ctx; + ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX)); + if (!ctx) + return 0; + if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) + return 0; + b->init = 1; + b->ptr = (char *)ctx; + b->flags = 0; + return 1; + } + +static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size) + { + ctx->buf = OPENSSL_malloc(size); + if (!ctx->buf) + return 0; + ctx->bufsize = size; + ctx->bufpos = 0; + ctx->buflen = 0; + ctx->copylen = 0; + ctx->asn1_class = V_ASN1_UNIVERSAL; + ctx->asn1_tag = V_ASN1_OCTET_STRING; + ctx->ex_buf = 0; + ctx->ex_pos = 0; + ctx->ex_len = 0; + ctx->state = ASN1_STATE_START; + return 1; + } + +static int asn1_bio_free(BIO *b) + { + BIO_ASN1_BUF_CTX *ctx; + ctx = (BIO_ASN1_BUF_CTX *) b->ptr; + if (ctx == NULL) + return 0; + if (ctx->buf) + OPENSSL_free(ctx->buf); + OPENSSL_free(ctx); + b->init = 0; + b->ptr = NULL; + b->flags = 0; + return 1; + } + +static int asn1_bio_write(BIO *b, const char *in , int inl) + { + BIO_ASN1_BUF_CTX *ctx; + int wrmax, wrlen, ret; + unsigned char *p; + if (!in || (inl < 0) || (b->next_bio == NULL)) + return 0; + ctx = (BIO_ASN1_BUF_CTX *) b->ptr; + if (ctx == NULL) + return 0; + + wrlen = 0; + ret = -1; + + for(;;) + { + switch (ctx->state) + { + + /* Setup prefix data, call it */ + case ASN1_STATE_START: + if (!asn1_bio_setup_ex(b, ctx, ctx->prefix, + ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER)) + return 0; + break; + + /* Copy any pre data first */ + case ASN1_STATE_PRE_COPY: + + ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free, + ASN1_STATE_HEADER); + + if (ret <= 0) + goto done; + + break; + + case ASN1_STATE_HEADER: + ctx->buflen = + ASN1_object_size(0, inl, ctx->asn1_tag) - inl; + OPENSSL_assert(ctx->buflen <= ctx->bufsize); + p = ctx->buf; + ASN1_put_object(&p, 0, inl, + ctx->asn1_tag, ctx->asn1_class); + ctx->copylen = inl; + ctx->state = ASN1_STATE_HEADER_COPY; + + break; + + case ASN1_STATE_HEADER_COPY: + ret = BIO_write(b->next_bio, + ctx->buf + ctx->bufpos, ctx->buflen); + if (ret <= 0) + goto done; + + ctx->buflen -= ret; + if (ctx->buflen) + ctx->bufpos += ret; + else + { + ctx->bufpos = 0; + ctx->state = ASN1_STATE_DATA_COPY; + } + + break; + + case ASN1_STATE_DATA_COPY: + + if (inl > ctx->copylen) + wrmax = ctx->copylen; + else + wrmax = inl; + ret = BIO_write(b->next_bio, in, wrmax); + if (ret <= 0) + break; + wrlen += ret; + ctx->copylen -= ret; + in += ret; + inl -= ret; + + if (ctx->copylen == 0) + ctx->state = ASN1_STATE_HEADER; + + if (inl == 0) + goto done; + + break; + + default: + BIO_clear_retry_flags(b); + return 0; + + } + + } + + done: + BIO_clear_retry_flags(b); + BIO_copy_next_retry(b); + + return (wrlen > 0) ? wrlen : ret; + + } + +static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *cleanup, asn1_bio_state_t next) + { + int ret; + if (ctx->ex_len <= 0) + return 1; + for(;;) + { + ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, + ctx->ex_len); + if (ret <= 0) + break; + ctx->ex_len -= ret; + if (ctx->ex_len > 0) + ctx->ex_pos += ret; + else + { + if(cleanup) + cleanup(b, &ctx->ex_buf, &ctx->ex_len, + &ctx->ex_arg); + ctx->state = next; + ctx->ex_pos = 0; + break; + } + } + return ret; + } + +static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *setup, + asn1_bio_state_t ex_state, + asn1_bio_state_t other_state) + { + if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) + { + BIO_clear_retry_flags(b); + return 0; + } + if (ctx->ex_len > 0) + ctx->state = ex_state; + else + ctx->state = other_state; + return 1; + } + +static int asn1_bio_read(BIO *b, char *in , int inl) + { + if (!b->next_bio) + return 0; + return BIO_read(b->next_bio, in , inl); + } + +static int asn1_bio_puts(BIO *b, const char *str) + { + return asn1_bio_write(b, str, strlen(str)); + } + +static int asn1_bio_gets(BIO *b, char *str, int size) + { + if (!b->next_bio) + return 0; + return BIO_gets(b->next_bio, str , size); + } + +static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) + { + if (b->next_bio == NULL) return(0); + return BIO_callback_ctrl(b->next_bio,cmd,fp); + } + +static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2) + { + BIO_ASN1_BUF_CTX *ctx; + BIO_ASN1_EX_FUNCS *ex_func; + long ret = 1; + ctx = (BIO_ASN1_BUF_CTX *) b->ptr; + if (ctx == NULL) + return 0; + switch(cmd) + { + + case BIO_C_SET_PREFIX: + ex_func = arg2; + ctx->prefix = ex_func->ex_func; + ctx->prefix_free = ex_func->ex_free_func; + break; + + case BIO_C_GET_PREFIX: + ex_func = arg2; + ex_func->ex_func = ctx->prefix; + ex_func->ex_free_func = ctx->prefix_free; + break; + + case BIO_C_SET_SUFFIX: + ex_func = arg2; + ctx->suffix = ex_func->ex_func; + ctx->suffix_free = ex_func->ex_free_func; + break; + + case BIO_C_GET_SUFFIX: + ex_func = arg2; + ex_func->ex_func = ctx->suffix; + ex_func->ex_free_func = ctx->suffix_free; + break; + + case BIO_C_SET_EX_ARG: + ctx->ex_arg = arg2; + break; + + case BIO_C_GET_EX_ARG: + *(void **)arg2 = ctx->ex_arg; + break; + + case BIO_CTRL_FLUSH: + if (!b->next_bio) + return 0; + + /* Call post function if possible */ + if (ctx->state == ASN1_STATE_HEADER) + { + if (!asn1_bio_setup_ex(b, ctx, ctx->suffix, + ASN1_STATE_POST_COPY, ASN1_STATE_DONE)) + return 0; + } + + if (ctx->state == ASN1_STATE_POST_COPY) + { + ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free, + ASN1_STATE_DONE); + if (ret <= 0) + return ret; + } + + if (ctx->state == ASN1_STATE_DONE) + return BIO_ctrl(b->next_bio, cmd, arg1, arg2); + else + { + BIO_clear_retry_flags(b); + return 0; + } + break; + + + default: + if (!b->next_bio) + return 0; + return BIO_ctrl(b->next_bio, cmd, arg1, arg2); + + } + + return ret; + } + +static int asn1_bio_set_ex(BIO *b, int cmd, + asn1_ps_func *ex_func, asn1_ps_func *ex_free_func) + { + BIO_ASN1_EX_FUNCS extmp; + extmp.ex_func = ex_func; + extmp.ex_free_func = ex_free_func; + return BIO_ctrl(b, cmd, 0, &extmp); + } + +static int asn1_bio_get_ex(BIO *b, int cmd, + asn1_ps_func **ex_func, asn1_ps_func **ex_free_func) + { + BIO_ASN1_EX_FUNCS extmp; + int ret; + ret = BIO_ctrl(b, cmd, 0, &extmp); + if (ret > 0) + { + *ex_func = extmp.ex_func; + *ex_free_func = extmp.ex_free_func; + } + return ret; + } + +int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free) + { + return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free); + } + +int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free) + { + return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free); + } + +int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free) + { + return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free); + } + +int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free) + { + return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free); + } diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h index 2504cba8de..9a81ee0bd9 100644 --- a/crypto/bio/bio.h +++ b/crypto/bio/bio.h @@ -95,6 +95,7 @@ extern "C" { #define BIO_TYPE_BIO (19|0x0400) /* (half a) BIO pair */ #define BIO_TYPE_LINEBUFFER (20|0x0200) /* filter */ #define BIO_TYPE_DGRAM (21|0x0400|0x0100) +#define BIO_TYPE_ASN1 (22|0x0200) /* filter */ #define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */ #define BIO_TYPE_FILTER 0x0200 @@ -314,6 +315,9 @@ typedef struct bio_f_buffer_ctx_struct int obuf_off; /* write/read offset */ } BIO_F_BUFFER_CTX; +/* Prefix and suffix callback in ASN1 BIO */ +typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen, void *parg); + /* connect BIO stuff */ #define BIO_CONN_S_BEFORE 1 #define BIO_CONN_S_GET_IP 2 @@ -375,6 +379,13 @@ typedef struct bio_f_buffer_ctx_struct #define BIO_C_NWRITE 146 #define BIO_C_RESET_READ_REQUEST 147 +#define BIO_C_SET_PREFIX 148 +#define BIO_C_GET_PREFIX 149 +#define BIO_C_SET_SUFFIX 150 +#define BIO_C_GET_SUFFIX 151 + +#define BIO_C_SET_EX_ARG 152 +#define BIO_C_GET_EX_ARG 153 #define BIO_set_app_data(s,arg) BIO_set_ex_data(s,0,arg) #define BIO_get_app_data(s) BIO_get_ex_data(s,0) @@ -536,6 +547,16 @@ int BIO_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, unsigned long BIO_number_read(BIO *bio); unsigned long BIO_number_written(BIO *bio); +/* For BIO_f_asn1() */ +int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, + asn1_ps_func *prefix_free); +int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, + asn1_ps_func **pprefix_free); +int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, + asn1_ps_func *suffix_free); +int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, + asn1_ps_func **psuffix_free); + # ifndef OPENSSL_NO_FP_API BIO_METHOD *BIO_s_file(void ); BIO *BIO_new_file(const char *filename, const char *mode); diff --git a/crypto/pkcs7/Makefile b/crypto/pkcs7/Makefile index 364bc1dc99..675c319568 100644 --- a/crypto/pkcs7/Makefile +++ b/crypto/pkcs7/Makefile @@ -21,9 +21,9 @@ APPS= LIB=$(TOP)/libcrypto.a LIBSRC= pk7_asn1.c pk7_lib.c pkcs7err.c pk7_doit.c pk7_smime.c pk7_attr.c \ - pk7_mime.c + pk7_mime.c bio_pk7.c LIBOBJ= pk7_asn1.o pk7_lib.o pkcs7err.o pk7_doit.o pk7_smime.o pk7_attr.o \ - pk7_mime.o + pk7_mime.o bio_pk7.o SRC= $(LIBSRC) diff --git a/crypto/pkcs7/bio_pk7.c b/crypto/pkcs7/bio_pk7.c new file mode 100644 index 0000000000..831a4e23b8 --- /dev/null +++ b/crypto/pkcs7/bio_pk7.c @@ -0,0 +1,200 @@ +/* bio_pk7.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2006 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. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include <openssl/asn1.h> +#include <openssl/pkcs7.h> +#include <openssl/bio.h> + +#include <memory.h> +#include <stdio.h> + +/* Highly experiemental PKCS#7 BIO support routines */ + +/* The usage is quite simple, initialize a PKCS7 structure, + * get a BIO from it then any data written through the BIO + * will end up translated to PKCS#7 format on the fly. + * The data is streamed out and does *not* need to be + * all held in memory at once. + * + * When the BIO is flushed the output is finalized and any + * signatures etc written out. + * + * The BIO is a 'proper' BIO and can handle non blocking I/O + * correctly. + * + * The usage is simple. The implementation is *not*... + */ + +/* BIO support data stored in the ASN1 BIO ex_arg */ + +typedef struct pkcs7_aux_st + { + /* PKCS7 structure this BIO refers to */ + PKCS7 *p7; + /* Top of the BIO chain */ + BIO *p7bio; + /* Output BIO */ + BIO *out; + /* Boundary where content is inserted */ + unsigned char **boundary; + /* DER buffer start */ + unsigned char *derbuf; + } PKCS7_SUPPORT; + +static int pkcs7_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg); +static int pkcs7_psfix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg); +static int pkcs7_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg); + +BIO *BIO_new_PKCS7(BIO *out, PKCS7 *p7) + { + PKCS7_SUPPORT *p7aux = NULL; + BIO *p7bio = NULL; + BIO *asn_bio = NULL; + unsigned char **boundary; + p7aux = OPENSSL_malloc(sizeof(PKCS7_SUPPORT)); + asn_bio = BIO_new(BIO_f_asn1()); + + /* ASN1 bio needs to be next to output BIO */ + + out = BIO_push(asn_bio, out); + + BIO_asn1_set_prefix(asn_bio, pkcs7_prefix, pkcs7_psfix_free); + BIO_asn1_set_suffix(asn_bio, pkcs7_suffix, pkcs7_psfix_free); + + /* Now initialize BIO for PKCS#7 output */ + + p7bio = PKCS7_dataInit(p7, out); + PKCS7_stream(&boundary, p7); + + p7aux->p7 = p7; + p7aux->p7bio = p7bio; + p7aux->boundary = boundary; + p7aux->out = out; + + BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, p7aux); + + return p7bio; + + } + + +static int pkcs7_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + PKCS7_SUPPORT *p7aux; + unsigned char *p; + int derlen; + + if (!parg) + return 0; + + p7aux = *(PKCS7_SUPPORT **)parg; + + derlen = i2d_PKCS7_NDEF(p7aux->p7, NULL); + p = OPENSSL_malloc(derlen); + p7aux->derbuf = p; + *pbuf = p; + i2d_PKCS7_NDEF(p7aux->p7, &p); + + *plen = *p7aux->boundary - *pbuf; + + return 1; + } + +static int pkcs7_psfix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + PKCS7_SUPPORT *p7aux; + + if (!parg) + return 0; + + p7aux = *(PKCS7_SUPPORT **)parg; + + if (p7aux->derbuf) + OPENSSL_free(p7aux->derbuf); + + p7aux->derbuf = NULL; + *pbuf = NULL; + *plen = 0; + return 1; + } + +static int pkcs7_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + PKCS7_SUPPORT *p7aux; + unsigned char *p; + int derlen; + + if (!parg) + return 0; + + p7aux = *(PKCS7_SUPPORT **)parg; + + /* Finalize structures */ + PKCS7_dataFinal(p7aux->p7, p7aux->p7bio); + + derlen = i2d_PKCS7_NDEF(p7aux->p7, NULL); + p = OPENSSL_malloc(derlen); + p7aux->derbuf = p; + i2d_PKCS7_NDEF(p7aux->p7, &p); + *pbuf = *p7aux->boundary; + *plen = derlen - (*p7aux->boundary - p7aux->derbuf); + + return 1; + } + + diff --git a/crypto/pkcs7/pk7_lib.c b/crypto/pkcs7/pk7_lib.c index 21738eebe2..8942ae8a53 100644 --- a/crypto/pkcs7/pk7_lib.c +++ b/crypto/pkcs7/pk7_lib.c @@ -594,3 +594,53 @@ int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher) return 1; } +int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7) + { + ASN1_OCTET_STRING *os = NULL; + + switch (OBJ_obj2nid(p7->type)) + { + case NID_pkcs7_data: + os = p7->d.data; + break; + + case NID_pkcs7_signedAndEnveloped: + os = p7->d.signed_and_enveloped->enc_data->enc_data; + if (os == NULL) + { + os=M_ASN1_OCTET_STRING_new(); + p7->d.signed_and_enveloped->enc_data->enc_data=os; + } + break; + + case NID_pkcs7_enveloped: + os = p7->d.enveloped->enc_data->enc_data; + if (os == NULL) + { + os=M_ASN1_OCTET_STRING_new(); + p7->d.enveloped->enc_data->enc_data=os; + } + break; + + case NID_pkcs7_signed: + os=p7->d.sign->contents->d.data; + break; + + default: + os = NULL; + break; + } + + if (os == NULL) + return 0; + + os->flags |= ASN1_STRING_FLAG_NDEF; + *boundary = &os->data; + + return 1; + } + + + + + diff --git a/crypto/pkcs7/pk7_smime.c b/crypto/pkcs7/pk7_smime.c index 718f0db0ef..8952e3989e 100644 --- a/crypto/pkcs7/pk7_smime.c +++ b/crypto/pkcs7/pk7_smime.c @@ -518,6 +518,9 @@ PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, } } + if (flags & PKCS7_STREAM) + return p7; + if (PKCS7_final(p7, in, flags)) return p7; diff --git a/crypto/pkcs7/pkcs7.h b/crypto/pkcs7/pkcs7.h index 20818909dc..f069527bad 100644 --- a/crypto/pkcs7/pkcs7.h +++ b/crypto/pkcs7/pkcs7.h @@ -339,6 +339,7 @@ void PKCS7_RECIP_INFO_get0_alg(PKCS7_RECIP_INFO *ri, X509_ALGOR **penc); int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri); int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509); int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher); +int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7); PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx); ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk); |