1c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* asn_mime.c */
2c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * project.
4c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org */
5c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* ====================================================================
6c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * Copyright (c) 1999-2008 The OpenSSL Project.  All rights reserved.
7c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *
8c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * Redistribution and use in source and binary forms, with or without
9c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * modification, are permitted provided that the following conditions
10c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * are met:
11c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *
12c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * 1. Redistributions of source code must retain the above copyright
13c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    notice, this list of conditions and the following disclaimer.
14c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *
15c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * 2. Redistributions in binary form must reproduce the above copyright
16c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    notice, this list of conditions and the following disclaimer in
17c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    the documentation and/or other materials provided with the
18c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    distribution.
19c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *
20c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * 3. All advertising materials mentioning features or use of this
21c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    software must display the following acknowledgment:
22c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    "This product includes software developed by the OpenSSL Project
23c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *
25c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    endorse or promote products derived from this software without
27c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    prior written permission. For written permission, please contact
28c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    licensing@OpenSSL.org.
29c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *
30c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * 5. Products derived from this software may not be called "OpenSSL"
31c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    nor may "OpenSSL" appear in their names without prior written
32c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    permission of the OpenSSL Project.
33c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *
34c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * 6. Redistributions of any form whatsoever must retain the following
35c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    acknowledgment:
36c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    "This product includes software developed by the OpenSSL Project
37c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *
39c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * OF THE POSSIBILITY OF SUCH DAMAGE.
51c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * ====================================================================
52c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org *
53c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org */
54c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
55c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#include <stdio.h>
56c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#include <ctype.h>
57c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#include "cryptlib.h"
58c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#include <openssl/rand.h>
59c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#include <openssl/x509.h>
60c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#include <openssl/asn1.h>
61c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#include <openssl/asn1t.h>
62480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#include "asn1_locl.h"
63c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
64c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Generalised MIME like utilities for streaming ASN1. Although many
65c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * have a PKCS7/CMS like flavour others are more general purpose.
66c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org */
67c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
68c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* MIME format structures
69c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * Note that all are translated to lower case apart from
70c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * parameter values. Quotes are stripped off
71c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org */
72c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
73c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgtypedef struct {
74c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgchar *param_name;			/* Param name e.g. "micalg" */
75c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgchar *param_value;			/* Param value e.g. "sha1" */
76c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org} MIME_PARAM;
77c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
78c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgDECLARE_STACK_OF(MIME_PARAM)
79c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgIMPLEMENT_STACK_OF(MIME_PARAM)
80c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
81c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgtypedef struct {
82c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgchar *name;				/* Name of line e.g. "content-type" */
83c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgchar *value;				/* Value of line e.g. "text/plain" */
84c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgSTACK_OF(MIME_PARAM) *params;		/* Zero or more parameters */
85c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org} MIME_HEADER;
86c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
87c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgDECLARE_STACK_OF(MIME_HEADER)
88c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgIMPLEMENT_STACK_OF(MIME_HEADER)
89c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
90480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgstatic int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
91480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org					const ASN1_ITEM *it);
92c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic char * strip_ends(char *name);
93c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic char * strip_start(char *name);
94c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic char * strip_end(char *name);
95c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic MIME_HEADER *mime_hdr_new(char *name, char *value);
96c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value);
97c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio);
98c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int mime_hdr_cmp(const MIME_HEADER * const *a,
99c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			const MIME_HEADER * const *b);
100c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int mime_param_cmp(const MIME_PARAM * const *a,
101c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			const MIME_PARAM * const *b);
102c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic void mime_param_free(MIME_PARAM *param);
103c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int mime_bound_check(char *line, int linelen, char *bound, int blen);
104c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret);
105c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int strip_eol(char *linebuf, int *plen);
106c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name);
107c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name);
108c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic void mime_hdr_free(MIME_HEADER *hdr);
109c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
110c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#define MAX_SMLEN 1024
111c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#define mime_debug(x) /* x */
112c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
113480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/* Output an ASN1 structure in BER format streaming if necessary */
114480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
115480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgint i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
116480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				const ASN1_ITEM *it)
117480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
118480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	/* If streaming create stream BIO and copy all content through it */
119480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	if (flags & SMIME_STREAM)
120480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		{
121480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		BIO *bio, *tbio;
122480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		bio = BIO_new_NDEF(out, val, it);
123480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		if (!bio)
124480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			{
125480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			ASN1err(ASN1_F_I2D_ASN1_BIO_STREAM,ERR_R_MALLOC_FAILURE);
126480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			return 0;
127480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			}
128480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		SMIME_crlf_copy(in, bio, flags);
129480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(void)BIO_flush(bio);
130480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		/* Free up successive BIOs until we hit the old output BIO */
131480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		do
132480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			{
133480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			tbio = BIO_pop(bio);
134480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			BIO_free(bio);
135480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			bio = tbio;
136480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			} while (bio != out);
137480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		}
138480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	/* else just write out ASN1 structure which will have all content
139480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	 * stored internally
140480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	 */
141480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	else
142480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ASN1_item_i2d_bio(it, out, val);
143480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	return 1;
144480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
145480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
146c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Base 64 read and write of ASN1 structure */
147c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
148c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int B64_write_ASN1(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
149c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				const ASN1_ITEM *it)
150c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	{
151c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO *b64;
152c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int r;
153c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	b64 = BIO_new(BIO_f_base64());
154c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!b64)
155c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
156c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_B64_WRITE_ASN1,ERR_R_MALLOC_FAILURE);
157c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
158c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
159c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* prepend the b64 BIO so all data is base64 encoded.
160c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	 */
161c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	out = BIO_push(b64, out);
162480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	r = i2d_ASN1_bio_stream(out, val, in, flags, it);
163c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	(void)BIO_flush(out);
164c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_pop(out);
165c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_free(b64);
166c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return r;
167c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
168c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
169480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/* Streaming ASN1 PEM write */
170480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
171480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgint PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
172480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				const char *hdr,
173480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				const ASN1_ITEM *it)
174480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
175480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	int r;
176480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	BIO_printf(out, "-----BEGIN %s-----\n", hdr);
177480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	r = B64_write_ASN1(out, val, in, flags, it);
178480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	BIO_printf(out, "-----END %s-----\n", hdr);
179480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	return r;
180480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
181480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
182c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic ASN1_VALUE *b64_read_asn1(BIO *bio, const ASN1_ITEM *it)
183c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
184c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO *b64;
185c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	ASN1_VALUE *val;
186c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!(b64 = BIO_new(BIO_f_base64()))) {
187c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_B64_READ_ASN1,ERR_R_MALLOC_FAILURE);
188c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
189c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
190c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	bio = BIO_push(b64, bio);
191c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	val = ASN1_item_d2i_bio(it, bio, NULL);
192c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!val)
193c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_B64_READ_ASN1,ASN1_R_DECODE_ERROR);
194c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	(void)BIO_flush(bio);
195c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	bio = BIO_pop(bio);
196c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_free(b64);
197c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return val;
198c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
199c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
200c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Generate the MIME "micalg" parameter from RFC3851, RFC4490 */
201c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
202c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int asn1_write_micalg(BIO *out, STACK_OF(X509_ALGOR) *mdalgs)
203c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	{
204480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	const EVP_MD *md;
205480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	int i, have_unknown = 0, write_comma, ret = 0, md_nid;
206c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	have_unknown = 0;
207c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	write_comma = 0;
208c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	for (i = 0; i < sk_X509_ALGOR_num(mdalgs); i++)
209c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
210c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if (write_comma)
211c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			BIO_write(out, ",", 1);
212c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		write_comma = 1;
213c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		md_nid = OBJ_obj2nid(sk_X509_ALGOR_value(mdalgs, i)->algorithm);
214480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		md = EVP_get_digestbynid(md_nid);
215480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		if (md && md->md_ctrl)
216480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			{
217480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			int rv;
218480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			char *micstr;
219480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			rv = md->md_ctrl(NULL, EVP_MD_CTRL_MICALG, 0, &micstr);
220480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			if (rv > 0)
221480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				{
222480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				BIO_puts(out, micstr);
223480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				OPENSSL_free(micstr);
224480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				continue;
225480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				}
226480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			if (rv != -2)
227480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				goto err;
228480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			}
229c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		switch(md_nid)
230c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			{
231c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case NID_sha1:
232c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			BIO_puts(out, "sha1");
233c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
234c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
235c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case NID_md5:
236c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			BIO_puts(out, "md5");
237c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
238c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
239c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case NID_sha256:
240c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			BIO_puts(out, "sha-256");
241c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
242c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
243c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case NID_sha384:
244c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			BIO_puts(out, "sha-384");
245c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
246c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
247c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case NID_sha512:
248c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			BIO_puts(out, "sha-512");
249c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
250c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
251480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			case NID_id_GostR3411_94:
252480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			BIO_puts(out, "gostr3411-94");
253480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				goto err;
254480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org			break;
255480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
256c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			default:
257c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if (have_unknown)
258c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				write_comma = 0;
259c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			else
260c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				{
261c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				BIO_puts(out, "unknown");
262c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				have_unknown = 1;
263c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				}
264c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
265c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
266c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
267c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
268c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
269480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	ret = 1;
270480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	err:
271480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
272480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	return ret;
273c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
274c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
275c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
276c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* SMIME sender */
277c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
278480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgint SMIME_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
279c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				int ctype_nid, int econt_nid,
280c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				STACK_OF(X509_ALGOR) *mdalgs,
281c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				const ASN1_ITEM *it)
282c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
283c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char bound[33], c;
284c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int i;
285c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	const char *mime_prefix, *mime_eol, *cname = "smime.p7m";
286c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	const char *msg_type=NULL;
287c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (flags & SMIME_OLDMIME)
288c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		mime_prefix = "application/x-pkcs7-";
289c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	else
290c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		mime_prefix = "application/pkcs7-";
291c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
292c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (flags & SMIME_CRLFEOL)
293c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		mime_eol = "\r\n";
294c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	else
295c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		mime_eol = "\n";
296c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if((flags & SMIME_DETACHED) && data) {
297c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* We want multipart/signed */
298c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		/* Generate a random boundary */
299c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		RAND_pseudo_bytes((unsigned char *)bound, 32);
300c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		for(i = 0; i < 32; i++) {
301c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			c = bound[i] & 0xf;
302c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(c < 10) c += '0';
303c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			else c += 'A' - 10;
304c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			bound[i] = c;
305c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
306c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		bound[32] = 0;
307c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
308c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, "Content-Type: multipart/signed;");
309c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, " protocol=\"%ssignature\";", mime_prefix);
310c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_puts(bio, " micalg=\"");
311c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		asn1_write_micalg(bio, mdalgs);
312c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, "\"; boundary=\"----%s\"%s%s",
313c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org						bound, mime_eol, mime_eol);
314c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, "This is an S/MIME signed message%s%s",
315c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org						mime_eol, mime_eol);
316c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		/* Now write out the first part */
317c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, "------%s%s", bound, mime_eol);
318480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		if (!asn1_output_data(bio, data, val, flags, it))
319c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return 0;
320c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, "%s------%s%s", mime_eol, bound, mime_eol);
321c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
322c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		/* Headers for signature */
323c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
324c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, "Content-Type: %ssignature;", mime_prefix);
325c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, " name=\"smime.p7s\"%s", mime_eol);
326c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, "Content-Transfer-Encoding: base64%s",
327c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org								mime_eol);
328c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, "Content-Disposition: attachment;");
329c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, " filename=\"smime.p7s\"%s%s",
330c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org							mime_eol, mime_eol);
331c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		B64_write_ASN1(bio, val, NULL, 0, it);
332c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio,"%s------%s--%s%s", mime_eol, bound,
333c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org							mime_eol, mime_eol);
334c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 1;
335c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
336c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
337c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Determine smime-type header */
338c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
339c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (ctype_nid == NID_pkcs7_enveloped)
340c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		msg_type = "enveloped-data";
341c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	else if (ctype_nid == NID_pkcs7_signed)
342c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
343c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if (econt_nid == NID_id_smime_ct_receipt)
344c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			msg_type = "signed-receipt";
345c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		else if (sk_X509_ALGOR_num(mdalgs) >= 0)
346c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			msg_type = "signed-data";
347c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		else
348c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			msg_type = "certs-only";
349c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
350c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	else if (ctype_nid == NID_id_smime_ct_compressedData)
351c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
352c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		msg_type = "compressed-data";
353c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		cname = "smime.p7z";
354c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
355c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* MIME headers */
356c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
357c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_printf(bio, "Content-Disposition: attachment;");
358c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_printf(bio, " filename=\"%s\"%s", cname, mime_eol);
359c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_printf(bio, "Content-Type: %smime;", mime_prefix);
360c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (msg_type)
361c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_printf(bio, " smime-type=%s;", msg_type);
362c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_printf(bio, " name=\"%s\"%s", cname, mime_eol);
363c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_printf(bio, "Content-Transfer-Encoding: base64%s%s",
364c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org						mime_eol, mime_eol);
365c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (!B64_write_ASN1(bio, val, data, flags, it))
366c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
367c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_printf(bio, "%s", mime_eol);
368c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return 1;
369c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
370c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
371c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Handle output of ASN1 data */
372c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
373c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
374c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
375c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org					const ASN1_ITEM *it)
376c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	{
377c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO *tmpbio;
378c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	const ASN1_AUX *aux = it->funcs;
379c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	ASN1_STREAM_ARG sarg;
3802c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	int rv = 1;
381c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
3822c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	/* If data is not deteched or resigning then the output BIO is
3832c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	 * already set up to finalise when it is written through.
3842c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	 */
3852c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (!(flags & SMIME_DETACHED) || (flags & PKCS7_REUSE_DIGEST))
386c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
387c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		SMIME_crlf_copy(data, out, flags);
388c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 1;
389c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
390c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
391c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (!aux || !aux->asn1_cb)
392c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
393c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_ASN1_OUTPUT_DATA,
394c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org					ASN1_R_STREAMING_NOT_SUPPORTED);
395c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
396c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
397c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
398c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	sarg.out = out;
399c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	sarg.ndef_bio = NULL;
400c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	sarg.boundary = NULL;
401c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
402c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Let ASN1 code prepend any needed BIOs */
403c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
404c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (aux->asn1_cb(ASN1_OP_DETACHED_PRE, &val, it, &sarg) <= 0)
405c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
406c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
407c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Copy data across, passing through filter BIOs for processing */
408c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	SMIME_crlf_copy(data, sarg.ndef_bio, flags);
409c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
410c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Finalize structure */
411c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (aux->asn1_cb(ASN1_OP_DETACHED_POST, &val, it, &sarg) <= 0)
4122c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		rv = 0;
413c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
414c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Now remove any digests prepended to the BIO */
415c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
416c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	while (sarg.ndef_bio != out)
417c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
418c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		tmpbio = BIO_pop(sarg.ndef_bio);
419c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		BIO_free(sarg.ndef_bio);
420c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		sarg.ndef_bio = tmpbio;
421c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
422c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
4232c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return rv;
424c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
425c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
426c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
427c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* SMIME reader: handle multipart/signed and opaque signing.
428c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * in multipart case the content is placed in a memory BIO
429c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * pointed to by "bcont". In opaque this is set to NULL
430c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org */
431c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
432c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it)
433c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
434c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO *asnin;
435c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	STACK_OF(MIME_HEADER) *headers = NULL;
436c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	STACK_OF(BIO) *parts = NULL;
437c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	MIME_HEADER *hdr;
438c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	MIME_PARAM *prm;
439c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	ASN1_VALUE *val;
440c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int ret;
441c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
442c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(bcont) *bcont = NULL;
443c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
444c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (!(headers = mime_parse_hdr(bio))) {
445c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_MIME_PARSE_ERROR);
446c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return NULL;
447c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
448c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
449c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) {
450c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
451c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_CONTENT_TYPE);
452c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return NULL;
453c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
454c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
455c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Handle multipart/signed */
456c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
457c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!strcmp(hdr->value, "multipart/signed")) {
458c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		/* Split into two parts */
459c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		prm = mime_param_find(hdr, "boundary");
460c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!prm || !prm->param_value) {
461c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
462c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_MULTIPART_BOUNDARY);
463c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return NULL;
464c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
465c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ret = multi_split(bio, prm->param_value, &parts);
466c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
467c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!ret || (sk_BIO_num(parts) != 2) ) {
468c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_MULTIPART_BODY_FAILURE);
469c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			sk_BIO_pop_free(parts, BIO_vfree);
470c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return NULL;
471c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
472c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
473c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		/* Parse the signature piece */
474c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		asnin = sk_BIO_value(parts, 1);
475c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
476c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if (!(headers = mime_parse_hdr(asnin))) {
477c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_MIME_SIG_PARSE_ERROR);
478c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			sk_BIO_pop_free(parts, BIO_vfree);
479c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return NULL;
480c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
481c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
482c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		/* Get content type */
483c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
484c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!(hdr = mime_hdr_find(headers, "content-type")) ||
485c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org								 !hdr->value) {
486c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
487c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_SIG_CONTENT_TYPE);
488c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return NULL;
489c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
490c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
491c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(strcmp(hdr->value, "application/x-pkcs7-signature") &&
492c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			strcmp(hdr->value, "application/pkcs7-signature")) {
493c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_SIG_INVALID_MIME_TYPE);
494c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			ERR_add_error_data(2, "type: ", hdr->value);
4952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
496c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			sk_BIO_pop_free(parts, BIO_vfree);
497c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return NULL;
498c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
499c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
500c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		/* Read in ASN1 */
501c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!(val = b64_read_asn1(asnin, it))) {
502c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_ASN1_SIG_PARSE_ERROR);
503c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			sk_BIO_pop_free(parts, BIO_vfree);
504c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return NULL;
505c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
506c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
507c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(bcont) {
508c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			*bcont = sk_BIO_value(parts, 0);
509c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			BIO_free(asnin);
510c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			sk_BIO_free(parts);
511c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		} else sk_BIO_pop_free(parts, BIO_vfree);
512c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return val;
513c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
514c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
515c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* OK, if not multipart/signed try opaque signature */
516c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
517c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (strcmp (hdr->value, "application/x-pkcs7-mime") &&
518c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	    strcmp (hdr->value, "application/pkcs7-mime")) {
519c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_INVALID_MIME_TYPE);
520c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ERR_add_error_data(2, "type: ", hdr->value);
521c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
522c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return NULL;
523c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
524c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
525c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
526c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
527c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!(val = b64_read_asn1(bio, it))) {
528c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_ASN1_PARSE_ERROR);
529c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return NULL;
530c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
531c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return val;
532c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
533c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
534c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
535c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Copy text from one BIO to another making the output CRLF at EOL */
536c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgint SMIME_crlf_copy(BIO *in, BIO *out, int flags)
537c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
538c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO *bf;
539c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char eol;
540c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int len;
541c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char linebuf[MAX_SMLEN];
542c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Buffer output so we don't write one line at a time. This is
543c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	 * useful when streaming as we don't end up with one OCTET STRING
544c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	 * per line.
545c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	 */
546c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	bf = BIO_new(BIO_f_buffer());
547c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (!bf)
548c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
549c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	out = BIO_push(bf, out);
550c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(flags & SMIME_BINARY)
551c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
552c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		while((len = BIO_read(in, linebuf, MAX_SMLEN)) > 0)
553c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org						BIO_write(out, linebuf, len);
554c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
555c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	else
556c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
557c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(flags & SMIME_TEXT)
558c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			BIO_printf(out, "Content-Type: text/plain\r\n\r\n");
559c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		while ((len = BIO_gets(in, linebuf, MAX_SMLEN)) > 0)
560c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			{
561c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			eol = strip_eol(linebuf, &len);
562c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if (len)
563c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				BIO_write(out, linebuf, len);
564c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(eol) BIO_write(out, "\r\n", 2);
565c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
566c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
567c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	(void)BIO_flush(out);
568c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_pop(out);
569c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO_free(bf);
570c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return 1;
571c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
572c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
573c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Strip off headers if they are text/plain */
574c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgint SMIME_text(BIO *in, BIO *out)
575c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
576c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char iobuf[4096];
577c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int len;
578c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	STACK_OF(MIME_HEADER) *headers;
579c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	MIME_HEADER *hdr;
580c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
581c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (!(headers = mime_parse_hdr(in))) {
582c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_SMIME_TEXT,ASN1_R_MIME_PARSE_ERROR);
583c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
584c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
585c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) {
586c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_SMIME_TEXT,ASN1_R_MIME_NO_CONTENT_TYPE);
587c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
588c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
589c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
590c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (strcmp (hdr->value, "text/plain")) {
591c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ASN1err(ASN1_F_SMIME_TEXT,ASN1_R_INVALID_MIME_TYPE);
592c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		ERR_add_error_data(2, "type: ", hdr->value);
593c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
594c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
595c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
596c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
597c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
598c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org						BIO_write(out, iobuf, len);
599c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if (len < 0)
600c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		return 0;
601c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return 1;
602c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
603c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
604c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Split a multipart/XXX message body into component parts: result is
605c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * canonical parts in a STACK of bios
606c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org */
607c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
608c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret)
609c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
610c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char linebuf[MAX_SMLEN];
611c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int len, blen;
612c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int eol = 0, next_eol = 0;
613c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	BIO *bpart = NULL;
614c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	STACK_OF(BIO) *parts;
615c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char state, part, first;
616c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
617c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	blen = strlen(bound);
618c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	part = 0;
619c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	state = 0;
620c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	first = 1;
621c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	parts = sk_BIO_new_null();
622c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	*ret = parts;
623c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
624c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		state = mime_bound_check(linebuf, len, bound, blen);
625c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(state == 1) {
626c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			first = 1;
627c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			part++;
628c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		} else if(state == 2) {
629c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			sk_BIO_push(parts, bpart);
630c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return 1;
631c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		} else if(part) {
632c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			/* Strip CR+LF from linebuf */
633c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			next_eol = strip_eol(linebuf, &len);
634c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(first) {
635c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				first = 0;
636c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				if(bpart) sk_BIO_push(parts, bpart);
637c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				bpart = BIO_new(BIO_s_mem());
638c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				BIO_set_mem_eof_return(bpart, 0);
639c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			} else if (eol)
640c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				BIO_write(bpart, "\r\n", 2);
641c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			eol = next_eol;
642c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if (len)
643c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				BIO_write(bpart, linebuf, len);
644c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
645c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
646c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return 0;
647c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
648c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
649c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* This is the big one: parse MIME header lines up to message body */
650c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
651c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#define MIME_INVALID	0
652c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#define MIME_START	1
653c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#define MIME_TYPE	2
654c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#define MIME_NAME	3
655c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#define MIME_VALUE	4
656c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#define MIME_QUOTE	5
657c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org#define MIME_COMMENT	6
658c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
659c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
660c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio)
661c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
662c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char *p, *q, c;
663c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char *ntmp;
664c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char linebuf[MAX_SMLEN];
665c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	MIME_HEADER *mhdr = NULL;
666c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	STACK_OF(MIME_HEADER) *headers;
667c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int len, state, save_state = 0;
668c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
669c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	headers = sk_MIME_HEADER_new(mime_hdr_cmp);
670c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
671c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* If whitespace at line start then continuation line */
672c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(mhdr && isspace((unsigned char)linebuf[0])) state = MIME_NAME;
673c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	else state = MIME_START;
674c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	ntmp = NULL;
675c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Go through all characters */
676c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	for(p = linebuf, q = linebuf; (c = *p) && (c!='\r') && (c!='\n'); p++) {
677c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
678c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* State machine to handle MIME headers
679c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	 * if this looks horrible that's because it *is*
680c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org         */
681c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
682c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		switch(state) {
683c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case MIME_START:
684c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(c == ':') {
685c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				state = MIME_TYPE;
686c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				*p = 0;
687c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				ntmp = strip_ends(q);
688c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				q = p + 1;
689c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
690c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
691c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
692c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case MIME_TYPE:
693c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(c == ';') {
694c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				mime_debug("Found End Value\n");
695c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				*p = 0;
696c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				mhdr = mime_hdr_new(ntmp, strip_ends(q));
697c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				sk_MIME_HEADER_push(headers, mhdr);
698c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				ntmp = NULL;
699c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				q = p + 1;
700c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				state = MIME_NAME;
701c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			} else if(c == '(') {
702c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				save_state = state;
703c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				state = MIME_COMMENT;
704c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
705c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
706c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
707c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case MIME_COMMENT:
708c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(c == ')') {
709c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				state = save_state;
710c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
711c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
712c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
713c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case MIME_NAME:
714c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(c == '=') {
715c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				state = MIME_VALUE;
716c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				*p = 0;
717c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				ntmp = strip_ends(q);
718c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				q = p + 1;
719c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
720c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break ;
721c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
722c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case MIME_VALUE:
723c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(c == ';') {
724c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				state = MIME_NAME;
725c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				*p = 0;
726c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
727c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				ntmp = NULL;
728c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				q = p + 1;
729c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			} else if (c == '"') {
730c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				mime_debug("Found Quote\n");
731c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				state = MIME_QUOTE;
732c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			} else if(c == '(') {
733c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				save_state = state;
734c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				state = MIME_COMMENT;
735c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
736c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
737c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
738c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			case MIME_QUOTE:
739c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(c == '"') {
740c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				mime_debug("Found Match Quote\n");
741c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				state = MIME_VALUE;
742c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
743c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
744c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
745c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
746c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
747c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(state == MIME_TYPE) {
748c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		mhdr = mime_hdr_new(ntmp, strip_ends(q));
749c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		sk_MIME_HEADER_push(headers, mhdr);
750c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	} else if(state == MIME_VALUE)
751c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			 mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
752c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(p == linebuf) break;	/* Blank line means end of headers */
753c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
754c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
755c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgreturn headers;
756c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
757c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
758c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
759c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic char *strip_ends(char *name)
760c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
761c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return strip_end(strip_start(name));
762c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
763c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
764c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Strip a parameter of whitespace from start of param */
765c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic char *strip_start(char *name)
766c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
767c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char *p, c;
768c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Look for first non white space or quote */
769c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	for(p = name; (c = *p) ;p++) {
770c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(c == '"') {
771c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			/* Next char is start of string if non null */
772c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(p[1]) return p + 1;
773c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			/* Else null string */
774c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return NULL;
775c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
776c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!isspace((unsigned char)c)) return p;
777c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
778c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return NULL;
779c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
780c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
781c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* As above but strip from end of string : maybe should handle brackets? */
782c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic char *strip_end(char *name)
783c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
784c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char *p, c;
785c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!name) return NULL;
786c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Look for first non white space or quote */
787c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	for(p = name + strlen(name) - 1; p >= name ;p--) {
788c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		c = *p;
789c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(c == '"') {
790c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(p - 1 == name) return NULL;
791c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			*p = 0;
792c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			return name;
793c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
794c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(isspace((unsigned char)c)) *p = 0;
795c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		else return name;
796c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
797c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return NULL;
798c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
799c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
800c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic MIME_HEADER *mime_hdr_new(char *name, char *value)
801c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
802c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	MIME_HEADER *mhdr;
803c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char *tmpname, *tmpval, *p;
804c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int c;
805c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(name) {
806c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!(tmpname = BUF_strdup(name))) return NULL;
807c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		for(p = tmpname ; *p; p++) {
8082c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			c = (unsigned char)*p;
809c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(isupper(c)) {
810c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				c = tolower(c);
811c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				*p = c;
812c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
813c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
814c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	} else tmpname = NULL;
815c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(value) {
816c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!(tmpval = BUF_strdup(value))) return NULL;
817c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		for(p = tmpval ; *p; p++) {
8182c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			c = (unsigned char)*p;
819c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(isupper(c)) {
820c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				c = tolower(c);
821c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				*p = c;
822c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
823c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
824c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	} else tmpval = NULL;
825c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	mhdr = (MIME_HEADER *) OPENSSL_malloc(sizeof(MIME_HEADER));
826c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!mhdr) return NULL;
827c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	mhdr->name = tmpname;
828c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	mhdr->value = tmpval;
829c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!(mhdr->params = sk_MIME_PARAM_new(mime_param_cmp))) return NULL;
830c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return mhdr;
831c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
832c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
833c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value)
834c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
835c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char *tmpname, *tmpval, *p;
836c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int c;
837c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	MIME_PARAM *mparam;
838c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(name) {
839c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		tmpname = BUF_strdup(name);
840c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!tmpname) return 0;
841c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		for(p = tmpname ; *p; p++) {
8422c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			c = (unsigned char)*p;
843c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			if(isupper(c)) {
844c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				c = tolower(c);
845c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org				*p = c;
846c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			}
847c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
848c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	} else tmpname = NULL;
849c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(value) {
850c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		tmpval = BUF_strdup(value);
851c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!tmpval) return 0;
852c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	} else tmpval = NULL;
853c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Parameter values are case sensitive so leave as is */
854c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	mparam = (MIME_PARAM *) OPENSSL_malloc(sizeof(MIME_PARAM));
855c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!mparam) return 0;
856c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	mparam->param_name = tmpname;
857c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	mparam->param_value = tmpval;
858c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	sk_MIME_PARAM_push(mhdr->params, mparam);
859c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return 1;
860c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
861c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
862c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int mime_hdr_cmp(const MIME_HEADER * const *a,
863c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			const MIME_HEADER * const *b)
864c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
8652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (!(*a)->name || !(*b)->name)
8662c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		return !!(*a)->name - !!(*b)->name;
8672c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
868c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return(strcmp((*a)->name, (*b)->name));
869c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
870c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
871c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int mime_param_cmp(const MIME_PARAM * const *a,
872c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			const MIME_PARAM * const *b)
873c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
8742c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (!(*a)->param_name || !(*b)->param_name)
8752c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		return !!(*a)->param_name - !!(*b)->param_name;
876c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return(strcmp((*a)->param_name, (*b)->param_name));
877c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
878c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
879c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Find a header with a given name (if possible) */
880c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
881c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name)
882c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
883c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	MIME_HEADER htmp;
884c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int idx;
885c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	htmp.name = name;
886c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	idx = sk_MIME_HEADER_find(hdrs, &htmp);
887c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(idx < 0) return NULL;
888c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return sk_MIME_HEADER_value(hdrs, idx);
889c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
890c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
891c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name)
892c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
893c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	MIME_PARAM param;
894c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int idx;
895c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	param.param_name = name;
896c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	idx = sk_MIME_PARAM_find(hdr->params, &param);
897c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(idx < 0) return NULL;
898c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return sk_MIME_PARAM_value(hdr->params, idx);
899c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
900c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
901c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic void mime_hdr_free(MIME_HEADER *hdr)
902c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
903c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(hdr->name) OPENSSL_free(hdr->name);
904c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(hdr->value) OPENSSL_free(hdr->value);
905c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(hdr->params) sk_MIME_PARAM_pop_free(hdr->params, mime_param_free);
906c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	OPENSSL_free(hdr);
907c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
908c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
909c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic void mime_param_free(MIME_PARAM *param)
910c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
911c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(param->param_name) OPENSSL_free(param->param_name);
912c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(param->param_value) OPENSSL_free(param->param_value);
913c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	OPENSSL_free(param);
914c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
915c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
916c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org/* Check for a multipart boundary. Returns:
917c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * 0 : no boundary
918c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * 1 : part boundary
919c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org * 2 : final boundary
920c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org */
921c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int mime_bound_check(char *line, int linelen, char *bound, int blen)
922c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org{
923c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(linelen == -1) linelen = strlen(line);
924c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(blen == -1) blen = strlen(bound);
925c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Quickly eliminate if line length too short */
926c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(blen + 2 > linelen) return 0;
927c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	/* Check for part boundary */
928c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	if(!strncmp(line, "--", 2) && !strncmp(line + 2, bound, blen)) {
929c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if(!strncmp(line + blen + 2, "--", 2)) return 2;
930c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		else return 1;
931c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
932c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return 0;
933c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org}
934c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org
935c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.orgstatic int strip_eol(char *linebuf, int *plen)
936c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	{
937c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int len = *plen;
938c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	char *p, c;
939c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	int is_eol = 0;
940c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	p = linebuf + len - 1;
941c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	for (p = linebuf + len - 1; len > 0; len--, p--)
942c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		{
943c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		c = *p;
944c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		if (c == '\n')
945c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			is_eol = 1;
946c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		else if (c != '\r')
947c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org			break;
948c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org		}
949c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	*plen = len;
950c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	return is_eol;
951c9490d33b98b7affb729b5f1db13cb0a348471aagl@chromium.org	}
952