pk7_mime.c
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:20k
源码类别:

其他游戏

开发平台:

Visual C++

  1. /* pk7_mime.c */
  2. /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
  3.  * project.
  4.  */
  5. /* ====================================================================
  6.  * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  *
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer. 
  14.  *
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in
  17.  *    the documentation and/or other materials provided with the
  18.  *    distribution.
  19.  *
  20.  * 3. All advertising materials mentioning features or use of this
  21.  *    software must display the following acknowledgment:
  22.  *    "This product includes software developed by the OpenSSL Project
  23.  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
  24.  *
  25.  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
  26.  *    endorse or promote products derived from this software without
  27.  *    prior written permission. For written permission, please contact
  28.  *    licensing@OpenSSL.org.
  29.  *
  30.  * 5. Products derived from this software may not be called "OpenSSL"
  31.  *    nor may "OpenSSL" appear in their names without prior written
  32.  *    permission of the OpenSSL Project.
  33.  *
  34.  * 6. Redistributions of any form whatsoever must retain the following
  35.  *    acknowledgment:
  36.  *    "This product includes software developed by the OpenSSL Project
  37.  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
  38.  *
  39.  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  40.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  41.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  42.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
  43.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  44.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  45.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  46.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  47.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  48.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  49.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  50.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  51.  * ====================================================================
  52.  *
  53.  * This product includes cryptographic software written by Eric Young
  54.  * (eay@cryptsoft.com).  This product includes software written by Tim
  55.  * Hudson (tjh@cryptsoft.com).
  56.  *
  57.  */
  58. #include <stdio.h>
  59. #include <ctype.h>
  60. #include "cryptlib.h"
  61. #include <openssl/rand.h>
  62. #include <openssl/x509.h>
  63. /* MIME and related routines */
  64. /* MIME format structures
  65.  * Note that all are translated to lower case apart from
  66.  * parameter values. Quotes are stripped off
  67.  */
  68. typedef struct {
  69. char *param_name; /* Param name e.g. "micalg" */
  70. char *param_value; /* Param value e.g. "sha1" */
  71. } MIME_PARAM;
  72. DECLARE_STACK_OF(MIME_PARAM)
  73. IMPLEMENT_STACK_OF(MIME_PARAM)
  74. typedef struct {
  75. char *name; /* Name of line e.g. "content-type" */
  76. char *value; /* Value of line e.g. "text/plain" */
  77. STACK_OF(MIME_PARAM) *params; /* Zero or more parameters */
  78. } MIME_HEADER;
  79. DECLARE_STACK_OF(MIME_HEADER)
  80. IMPLEMENT_STACK_OF(MIME_HEADER)
  81. static int pkcs7_output_data(BIO *bio, BIO *data, PKCS7 *p7, int flags);
  82. static int B64_write_PKCS7(BIO *bio, PKCS7 *p7);
  83. static PKCS7 *B64_read_PKCS7(BIO *bio);
  84. static char * strip_ends(char *name);
  85. static char * strip_start(char *name);
  86. static char * strip_end(char *name);
  87. static MIME_HEADER *mime_hdr_new(char *name, char *value);
  88. static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value);
  89. static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio);
  90. static int mime_hdr_cmp(const MIME_HEADER * const *a,
  91. const MIME_HEADER * const *b);
  92. static int mime_param_cmp(const MIME_PARAM * const *a,
  93. const MIME_PARAM * const *b);
  94. static void mime_param_free(MIME_PARAM *param);
  95. static int mime_bound_check(char *line, int linelen, char *bound, int blen);
  96. static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret);
  97. static int strip_eol(char *linebuf, int *plen);
  98. static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name);
  99. static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name);
  100. static void mime_hdr_free(MIME_HEADER *hdr);
  101. #define MAX_SMLEN 1024
  102. #define mime_debug(x) /* x */
  103. /* Base 64 read and write of PKCS#7 structure */
  104. static int B64_write_PKCS7(BIO *bio, PKCS7 *p7)
  105. {
  106. BIO *b64;
  107. if(!(b64 = BIO_new(BIO_f_base64()))) {
  108. PKCS7err(PKCS7_F_B64_WRITE_PKCS7,ERR_R_MALLOC_FAILURE);
  109. return 0;
  110. }
  111. bio = BIO_push(b64, bio);
  112. i2d_PKCS7_bio(bio, p7);
  113. BIO_flush(bio);
  114. bio = BIO_pop(bio);
  115. BIO_free(b64);
  116. return 1;
  117. }
  118. static PKCS7 *B64_read_PKCS7(BIO *bio)
  119. {
  120. BIO *b64;
  121. PKCS7 *p7;
  122. if(!(b64 = BIO_new(BIO_f_base64()))) {
  123. PKCS7err(PKCS7_F_B64_READ_PKCS7,ERR_R_MALLOC_FAILURE);
  124. return 0;
  125. }
  126. bio = BIO_push(b64, bio);
  127. if(!(p7 = d2i_PKCS7_bio(bio, NULL))) 
  128. PKCS7err(PKCS7_F_B64_READ_PKCS7,PKCS7_R_DECODE_ERROR);
  129. BIO_flush(bio);
  130. bio = BIO_pop(bio);
  131. BIO_free(b64);
  132. return p7;
  133. }
  134. /* SMIME sender */
  135. int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags)
  136. {
  137. char bound[33], c;
  138. int i;
  139. char *mime_prefix, *mime_eol, *msg_type=NULL;
  140. if (flags & PKCS7_NOOLDMIMETYPE)
  141. mime_prefix = "application/pkcs7-";
  142. else
  143. mime_prefix = "application/x-pkcs7-";
  144. if (flags & PKCS7_CRLFEOL)
  145. mime_eol = "rn";
  146. else
  147. mime_eol = "n";
  148. if((flags & PKCS7_DETACHED) && data) {
  149. /* We want multipart/signed */
  150. /* Generate a random boundary */
  151. RAND_pseudo_bytes((unsigned char *)bound, 32);
  152. for(i = 0; i < 32; i++) {
  153. c = bound[i] & 0xf;
  154. if(c < 10) c += '0';
  155. else c += 'A' - 10;
  156. bound[i] = c;
  157. }
  158. bound[32] = 0;
  159. BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
  160. BIO_printf(bio, "Content-Type: multipart/signed;");
  161. BIO_printf(bio, " protocol="%ssignature";", mime_prefix);
  162. BIO_printf(bio, " micalg=sha1; boundary="----%s"%s%s",
  163. bound, mime_eol, mime_eol);
  164. BIO_printf(bio, "This is an S/MIME signed message%s%s",
  165. mime_eol, mime_eol);
  166. /* Now write out the first part */
  167. BIO_printf(bio, "------%s%s", bound, mime_eol);
  168. pkcs7_output_data(bio, data, p7, flags);
  169. BIO_printf(bio, "%s------%s%s", mime_eol, bound, mime_eol);
  170. /* Headers for signature */
  171. BIO_printf(bio, "Content-Type: %ssignature;", mime_prefix); 
  172. BIO_printf(bio, " name="smime.p7s"%s", mime_eol);
  173. BIO_printf(bio, "Content-Transfer-Encoding: base64%s",
  174. mime_eol);
  175. BIO_printf(bio, "Content-Disposition: attachment;");
  176. BIO_printf(bio, " filename="smime.p7s"%s%s",
  177. mime_eol, mime_eol);
  178. B64_write_PKCS7(bio, p7);
  179. BIO_printf(bio,"%s------%s--%s%s", mime_eol, bound,
  180. mime_eol, mime_eol);
  181. return 1;
  182. }
  183. /* Determine smime-type header */
  184. if (PKCS7_type_is_enveloped(p7))
  185. msg_type = "enveloped-data";
  186. else if (PKCS7_type_is_signed(p7))
  187. {
  188. /* If we have any signers it is signed-data othewise 
  189.  * certs-only.
  190.  */
  191. STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
  192. sinfos = PKCS7_get_signer_info(p7);
  193. if (sk_PKCS7_SIGNER_INFO_num(sinfos) > 0)
  194. msg_type = "signed-data";
  195. else
  196. msg_type = "certs-only";
  197. }
  198. /* MIME headers */
  199. BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
  200. BIO_printf(bio, "Content-Disposition: attachment;");
  201. BIO_printf(bio, " filename="smime.p7m"%s", mime_eol);
  202. BIO_printf(bio, "Content-Type: %smime;", mime_prefix);
  203. if (msg_type)
  204. BIO_printf(bio, " smime-type=%s;", msg_type);
  205. BIO_printf(bio, " name="smime.p7m"%s", mime_eol);
  206. BIO_printf(bio, "Content-Transfer-Encoding: base64%s%s",
  207. mime_eol, mime_eol);
  208. B64_write_PKCS7(bio, p7);
  209. BIO_printf(bio, "%s", mime_eol);
  210. return 1;
  211. }
  212. /* Handle output of PKCS#7 data */
  213. static int pkcs7_output_data(BIO *out, BIO *data, PKCS7 *p7, int flags)
  214. {
  215. BIO *tmpbio, *p7bio;
  216. if (!(flags & PKCS7_STREAM))
  217. {
  218. SMIME_crlf_copy(data, out, flags);
  219. return 1;
  220. }
  221. /* Partial sign operation */
  222. /* Initialize sign operation */
  223. p7bio = PKCS7_dataInit(p7, out);
  224. /* Copy data across, computing digests etc */
  225. SMIME_crlf_copy(data, p7bio, flags);
  226. /* Must be detached */
  227. PKCS7_set_detached(p7, 1);
  228. /* Finalize signatures */
  229. PKCS7_dataFinal(p7, p7bio);
  230. /* Now remove any digests prepended to the BIO */
  231. while (p7bio != out)
  232. {
  233. tmpbio = BIO_pop(p7bio);
  234. BIO_free(p7bio);
  235. p7bio = tmpbio;
  236. }
  237. return 1;
  238. }
  239. /* SMIME reader: handle multipart/signed and opaque signing.
  240.  * in multipart case the content is placed in a memory BIO
  241.  * pointed to by "bcont". In opaque this is set to NULL
  242.  */
  243. PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont)
  244. {
  245. BIO *p7in;
  246. STACK_OF(MIME_HEADER) *headers = NULL;
  247. STACK_OF(BIO) *parts = NULL;
  248. MIME_HEADER *hdr;
  249. MIME_PARAM *prm;
  250. PKCS7 *p7;
  251. int ret;
  252. if(bcont) *bcont = NULL;
  253. if (!(headers = mime_parse_hdr(bio))) {
  254. PKCS7err(PKCS7_F_SMIME_READ_PKCS7,PKCS7_R_MIME_PARSE_ERROR);
  255. return NULL;
  256. }
  257. if(!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) {
  258. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  259. PKCS7err(PKCS7_F_SMIME_READ_PKCS7, PKCS7_R_NO_CONTENT_TYPE);
  260. return NULL;
  261. }
  262. /* Handle multipart/signed */
  263. if(!strcmp(hdr->value, "multipart/signed")) {
  264. /* Split into two parts */
  265. prm = mime_param_find(hdr, "boundary");
  266. if(!prm || !prm->param_value) {
  267. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  268. PKCS7err(PKCS7_F_SMIME_READ_PKCS7, PKCS7_R_NO_MULTIPART_BOUNDARY);
  269. return NULL;
  270. }
  271. ret = multi_split(bio, prm->param_value, &parts);
  272. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  273. if(!ret || (sk_BIO_num(parts) != 2) ) {
  274. PKCS7err(PKCS7_F_SMIME_READ_PKCS7, PKCS7_R_NO_MULTIPART_BODY_FAILURE);
  275. sk_BIO_pop_free(parts, BIO_vfree);
  276. return NULL;
  277. }
  278. /* Parse the signature piece */
  279. p7in = sk_BIO_value(parts, 1);
  280. if (!(headers = mime_parse_hdr(p7in))) {
  281. PKCS7err(PKCS7_F_SMIME_READ_PKCS7,PKCS7_R_MIME_SIG_PARSE_ERROR);
  282. sk_BIO_pop_free(parts, BIO_vfree);
  283. return NULL;
  284. }
  285. /* Get content type */
  286. if(!(hdr = mime_hdr_find(headers, "content-type")) ||
  287.  !hdr->value) {
  288. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  289. PKCS7err(PKCS7_F_SMIME_READ_PKCS7, PKCS7_R_NO_SIG_CONTENT_TYPE);
  290. return NULL;
  291. }
  292. if(strcmp(hdr->value, "application/x-pkcs7-signature") &&
  293. strcmp(hdr->value, "application/pkcs7-signature")) {
  294. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  295. PKCS7err(PKCS7_F_SMIME_READ_PKCS7,PKCS7_R_SIG_INVALID_MIME_TYPE);
  296. ERR_add_error_data(2, "type: ", hdr->value);
  297. sk_BIO_pop_free(parts, BIO_vfree);
  298. return NULL;
  299. }
  300. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  301. /* Read in PKCS#7 */
  302. if(!(p7 = B64_read_PKCS7(p7in))) {
  303. PKCS7err(PKCS7_F_SMIME_READ_PKCS7,PKCS7_R_PKCS7_SIG_PARSE_ERROR);
  304. sk_BIO_pop_free(parts, BIO_vfree);
  305. return NULL;
  306. }
  307. if(bcont) {
  308. *bcont = sk_BIO_value(parts, 0);
  309. BIO_free(p7in);
  310. sk_BIO_free(parts);
  311. } else sk_BIO_pop_free(parts, BIO_vfree);
  312. return p7;
  313. }
  314. /* OK, if not multipart/signed try opaque signature */
  315. if (strcmp (hdr->value, "application/x-pkcs7-mime") &&
  316.     strcmp (hdr->value, "application/pkcs7-mime")) {
  317. PKCS7err(PKCS7_F_SMIME_READ_PKCS7,PKCS7_R_INVALID_MIME_TYPE);
  318. ERR_add_error_data(2, "type: ", hdr->value);
  319. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  320. return NULL;
  321. }
  322. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  323. if(!(p7 = B64_read_PKCS7(bio))) {
  324. PKCS7err(PKCS7_F_SMIME_READ_PKCS7, PKCS7_R_PKCS7_PARSE_ERROR);
  325. return NULL;
  326. }
  327. return p7;
  328. }
  329. /* Copy text from one BIO to another making the output CRLF at EOL */
  330. int SMIME_crlf_copy(BIO *in, BIO *out, int flags)
  331. {
  332. char eol;
  333. int len;
  334. char linebuf[MAX_SMLEN];
  335. if(flags & PKCS7_BINARY) {
  336. while((len = BIO_read(in, linebuf, MAX_SMLEN)) > 0)
  337. BIO_write(out, linebuf, len);
  338. return 1;
  339. }
  340. if(flags & PKCS7_TEXT)
  341. BIO_printf(out, "Content-Type: text/plainrnrn");
  342. while ((len = BIO_gets(in, linebuf, MAX_SMLEN)) > 0) {
  343. eol = strip_eol(linebuf, &len);
  344. if (len)
  345. BIO_write(out, linebuf, len);
  346. if(eol) BIO_write(out, "rn", 2);
  347. }
  348. return 1;
  349. }
  350. /* Strip off headers if they are text/plain */
  351. int SMIME_text(BIO *in, BIO *out)
  352. {
  353. char iobuf[4096];
  354. int len;
  355. STACK_OF(MIME_HEADER) *headers;
  356. MIME_HEADER *hdr;
  357. if (!(headers = mime_parse_hdr(in))) {
  358. PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_MIME_PARSE_ERROR);
  359. return 0;
  360. }
  361. if(!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) {
  362. PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_MIME_NO_CONTENT_TYPE);
  363. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  364. return 0;
  365. }
  366. if (strcmp (hdr->value, "text/plain")) {
  367. PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_INVALID_MIME_TYPE);
  368. ERR_add_error_data(2, "type: ", hdr->value);
  369. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  370. return 0;
  371. }
  372. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  373. while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
  374. BIO_write(out, iobuf, len);
  375. return 1;
  376. }
  377. /* Split a multipart/XXX message body into component parts: result is
  378.  * canonical parts in a STACK of bios
  379.  */
  380. static int multi_split(BIO *bio, char *bound, STACK_OF(BIO) **ret)
  381. {
  382. char linebuf[MAX_SMLEN];
  383. int len, blen;
  384. int eol = 0, next_eol = 0;
  385. BIO *bpart = NULL;
  386. STACK_OF(BIO) *parts;
  387. char state, part, first;
  388. blen = strlen(bound);
  389. part = 0;
  390. state = 0;
  391. first = 1;
  392. parts = sk_BIO_new_null();
  393. *ret = parts;
  394. while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
  395. state = mime_bound_check(linebuf, len, bound, blen);
  396. if(state == 1) {
  397. first = 1;
  398. part++;
  399. } else if(state == 2) {
  400. sk_BIO_push(parts, bpart);
  401. return 1;
  402. } else if(part) {
  403. /* Strip CR+LF from linebuf */
  404. next_eol = strip_eol(linebuf, &len);
  405. if(first) {
  406. first = 0;
  407. if(bpart) sk_BIO_push(parts, bpart);
  408. bpart = BIO_new(BIO_s_mem());
  409. BIO_set_mem_eof_return(bpart, 0);
  410. } else if (eol)
  411. BIO_write(bpart, "rn", 2);
  412. eol = next_eol;
  413. if (len)
  414. BIO_write(bpart, linebuf, len);
  415. }
  416. }
  417. return 0;
  418. }
  419. /* This is the big one: parse MIME header lines up to message body */
  420. #define MIME_INVALID 0
  421. #define MIME_START 1
  422. #define MIME_TYPE 2
  423. #define MIME_NAME 3
  424. #define MIME_VALUE 4
  425. #define MIME_QUOTE 5
  426. #define MIME_COMMENT 6
  427. static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio)
  428. {
  429. char *p, *q, c;
  430. char *ntmp;
  431. char linebuf[MAX_SMLEN];
  432. MIME_HEADER *mhdr = NULL;
  433. STACK_OF(MIME_HEADER) *headers;
  434. int len, state, save_state = 0;
  435. headers = sk_MIME_HEADER_new(mime_hdr_cmp);
  436. while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
  437. /* If whitespace at line start then continuation line */
  438. if(mhdr && isspace((unsigned char)linebuf[0])) state = MIME_NAME;
  439. else state = MIME_START;
  440. ntmp = NULL;
  441. /* Go through all characters */
  442. for(p = linebuf, q = linebuf; (c = *p) && (c!='r') && (c!='n'); p++) {
  443. /* State machine to handle MIME headers
  444.  * if this looks horrible that's because it *is*
  445.          */
  446. switch(state) {
  447. case MIME_START:
  448. if(c == ':') {
  449. state = MIME_TYPE;
  450. *p = 0;
  451. ntmp = strip_ends(q);
  452. q = p + 1;
  453. }
  454. break;
  455. case MIME_TYPE:
  456. if(c == ';') {
  457. mime_debug("Found End Valuen");
  458. *p = 0;
  459. mhdr = mime_hdr_new(ntmp, strip_ends(q));
  460. sk_MIME_HEADER_push(headers, mhdr);
  461. ntmp = NULL;
  462. q = p + 1;
  463. state = MIME_NAME;
  464. } else if(c == '(') {
  465. save_state = state;
  466. state = MIME_COMMENT;
  467. }
  468. break;
  469. case MIME_COMMENT:
  470. if(c == ')') {
  471. state = save_state;
  472. }
  473. break;
  474. case MIME_NAME:
  475. if(c == '=') {
  476. state = MIME_VALUE;
  477. *p = 0;
  478. ntmp = strip_ends(q);
  479. q = p + 1;
  480. }
  481. break ;
  482. case MIME_VALUE:
  483. if(c == ';') {
  484. state = MIME_NAME;
  485. *p = 0;
  486. mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
  487. ntmp = NULL;
  488. q = p + 1;
  489. } else if (c == '"') {
  490. mime_debug("Found Quoten");
  491. state = MIME_QUOTE;
  492. } else if(c == '(') {
  493. save_state = state;
  494. state = MIME_COMMENT;
  495. }
  496. break;
  497. case MIME_QUOTE:
  498. if(c == '"') {
  499. mime_debug("Found Match Quoten");
  500. state = MIME_VALUE;
  501. }
  502. break;
  503. }
  504. }
  505. if(state == MIME_TYPE) {
  506. mhdr = mime_hdr_new(ntmp, strip_ends(q));
  507. sk_MIME_HEADER_push(headers, mhdr);
  508. } else if(state == MIME_VALUE)
  509.  mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
  510. if(p == linebuf) break; /* Blank line means end of headers */
  511. }
  512. return headers;
  513. }
  514. static char *strip_ends(char *name)
  515. {
  516. return strip_end(strip_start(name));
  517. }
  518. /* Strip a parameter of whitespace from start of param */
  519. static char *strip_start(char *name)
  520. {
  521. char *p, c;
  522. /* Look for first non white space or quote */
  523. for(p = name; (c = *p) ;p++) {
  524. if(c == '"') {
  525. /* Next char is start of string if non null */
  526. if(p[1]) return p + 1;
  527. /* Else null string */
  528. return NULL;
  529. }
  530. if(!isspace((unsigned char)c)) return p;
  531. }
  532. return NULL;
  533. }
  534. /* As above but strip from end of string : maybe should handle brackets? */
  535. static char *strip_end(char *name)
  536. {
  537. char *p, c;
  538. if(!name) return NULL;
  539. /* Look for first non white space or quote */
  540. for(p = name + strlen(name) - 1; p >= name ;p--) {
  541. c = *p;
  542. if(c == '"') {
  543. if(p - 1 == name) return NULL;
  544. *p = 0;
  545. return name;
  546. }
  547. if(isspace((unsigned char)c)) *p = 0;
  548. else return name;
  549. }
  550. return NULL;
  551. }
  552. static MIME_HEADER *mime_hdr_new(char *name, char *value)
  553. {
  554. MIME_HEADER *mhdr;
  555. char *tmpname, *tmpval, *p;
  556. int c;
  557. if(name) {
  558. if(!(tmpname = BUF_strdup(name))) return NULL;
  559. for(p = tmpname ; *p; p++) {
  560. c = *p;
  561. if(isupper(c)) {
  562. c = tolower(c);
  563. *p = c;
  564. }
  565. }
  566. } else tmpname = NULL;
  567. if(value) {
  568. if(!(tmpval = BUF_strdup(value))) return NULL;
  569. for(p = tmpval ; *p; p++) {
  570. c = *p;
  571. if(isupper(c)) {
  572. c = tolower(c);
  573. *p = c;
  574. }
  575. }
  576. } else tmpval = NULL;
  577. mhdr = (MIME_HEADER *) OPENSSL_malloc(sizeof(MIME_HEADER));
  578. if(!mhdr) return NULL;
  579. mhdr->name = tmpname;
  580. mhdr->value = tmpval;
  581. if(!(mhdr->params = sk_MIME_PARAM_new(mime_param_cmp))) return NULL;
  582. return mhdr;
  583. }
  584. static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value)
  585. {
  586. char *tmpname, *tmpval, *p;
  587. int c;
  588. MIME_PARAM *mparam;
  589. if(name) {
  590. tmpname = BUF_strdup(name);
  591. if(!tmpname) return 0;
  592. for(p = tmpname ; *p; p++) {
  593. c = *p;
  594. if(isupper(c)) {
  595. c = tolower(c);
  596. *p = c;
  597. }
  598. }
  599. } else tmpname = NULL;
  600. if(value) {
  601. tmpval = BUF_strdup(value);
  602. if(!tmpval) return 0;
  603. } else tmpval = NULL;
  604. /* Parameter values are case sensitive so leave as is */
  605. mparam = (MIME_PARAM *) OPENSSL_malloc(sizeof(MIME_PARAM));
  606. if(!mparam) return 0;
  607. mparam->param_name = tmpname;
  608. mparam->param_value = tmpval;
  609. sk_MIME_PARAM_push(mhdr->params, mparam);
  610. return 1;
  611. }
  612. static int mime_hdr_cmp(const MIME_HEADER * const *a,
  613. const MIME_HEADER * const *b)
  614. {
  615. return(strcmp((*a)->name, (*b)->name));
  616. }
  617. static int mime_param_cmp(const MIME_PARAM * const *a,
  618. const MIME_PARAM * const *b)
  619. {
  620. return(strcmp((*a)->param_name, (*b)->param_name));
  621. }
  622. /* Find a header with a given name (if possible) */
  623. static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, char *name)
  624. {
  625. MIME_HEADER htmp;
  626. int idx;
  627. htmp.name = name;
  628. idx = sk_MIME_HEADER_find(hdrs, &htmp);
  629. if(idx < 0) return NULL;
  630. return sk_MIME_HEADER_value(hdrs, idx);
  631. }
  632. static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name)
  633. {
  634. MIME_PARAM param;
  635. int idx;
  636. param.param_name = name;
  637. idx = sk_MIME_PARAM_find(hdr->params, &param);
  638. if(idx < 0) return NULL;
  639. return sk_MIME_PARAM_value(hdr->params, idx);
  640. }
  641. static void mime_hdr_free(MIME_HEADER *hdr)
  642. {
  643. if(hdr->name) OPENSSL_free(hdr->name);
  644. if(hdr->value) OPENSSL_free(hdr->value);
  645. if(hdr->params) sk_MIME_PARAM_pop_free(hdr->params, mime_param_free);
  646. OPENSSL_free(hdr);
  647. }
  648. static void mime_param_free(MIME_PARAM *param)
  649. {
  650. if(param->param_name) OPENSSL_free(param->param_name);
  651. if(param->param_value) OPENSSL_free(param->param_value);
  652. OPENSSL_free(param);
  653. }
  654. /* Check for a multipart boundary. Returns:
  655.  * 0 : no boundary
  656.  * 1 : part boundary
  657.  * 2 : final boundary
  658.  */
  659. static int mime_bound_check(char *line, int linelen, char *bound, int blen)
  660. {
  661. if(linelen == -1) linelen = strlen(line);
  662. if(blen == -1) blen = strlen(bound);
  663. /* Quickly eliminate if line length too short */
  664. if(blen + 2 > linelen) return 0;
  665. /* Check for part boundary */
  666. if(!strncmp(line, "--", 2) && !strncmp(line + 2, bound, blen)) {
  667. if(!strncmp(line + blen + 2, "--", 2)) return 2;
  668. else return 1;
  669. }
  670. return 0;
  671. }
  672. static int strip_eol(char *linebuf, int *plen)
  673. {
  674. int len = *plen;
  675. char *p, c;
  676. int is_eol = 0;
  677. p = linebuf + len - 1;
  678. for (p = linebuf + len - 1; len > 0; len--, p--)
  679. {
  680. c = *p;
  681. if (c == 'n')
  682. is_eol = 1;
  683. else if (c != 'r')
  684. break;
  685. }
  686. *plen = len;
  687. return is_eol;
  688. }