asn_mime.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053
  1. /*
  2. * Copyright 2008-2025 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include <stdio.h>
  10. #include "crypto/ctype.h"
  11. #include "internal/cryptlib.h"
  12. #include <openssl/rand.h>
  13. #include <openssl/x509.h>
  14. #include <openssl/asn1.h>
  15. #include <openssl/asn1t.h>
  16. #include <openssl/cms.h>
  17. #include "crypto/evp.h"
  18. #include "internal/bio.h"
  19. #include "asn1_local.h"
  20. /*
  21. * Generalised MIME like utilities for streaming ASN1. Although many have a
  22. * PKCS7/CMS like flavour others are more general purpose.
  23. */
  24. /*
  25. * MIME format structures Note that all are translated to lower case apart
  26. * from parameter values. Quotes are stripped off
  27. */
  28. struct mime_param_st {
  29. char *param_name; /* Param name e.g. "micalg" */
  30. char *param_value; /* Param value e.g. "sha1" */
  31. };
  32. struct mime_header_st {
  33. char *name; /* Name of line e.g. "content-type" */
  34. char *value; /* Value of line e.g. "text/plain" */
  35. STACK_OF(MIME_PARAM) *params; /* Zero or more parameters */
  36. };
  37. static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
  38. const ASN1_ITEM *it);
  39. static char *strip_ends(char *name);
  40. static char *strip_start(char *name);
  41. static char *strip_end(char *name);
  42. static MIME_HEADER *mime_hdr_new(const char *name, const char *value);
  43. static int mime_hdr_addparam(MIME_HEADER *mhdr, const char *name, const char *value);
  44. static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio);
  45. static int mime_hdr_cmp(const MIME_HEADER *const *a,
  46. const MIME_HEADER *const *b);
  47. static int mime_param_cmp(const MIME_PARAM *const *a,
  48. const MIME_PARAM *const *b);
  49. static void mime_param_free(MIME_PARAM *param);
  50. static int mime_bound_check(char *line, int linelen, const char *bound, int blen);
  51. static int multi_split(BIO *bio, int flags, const char *bound, STACK_OF(BIO) **ret);
  52. static int strip_eol(char *linebuf, int *plen, int flags);
  53. static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, const char *name);
  54. static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, const char *name);
  55. static void mime_hdr_free(MIME_HEADER *hdr);
  56. #define MAX_SMLEN 1024
  57. #define mime_debug(x) /* x */
  58. /* Output an ASN1 structure in BER format streaming if necessary */
  59. /* unfortunately cannot constify this due to CMS_stream() and PKCS7_stream() */
  60. int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
  61. const ASN1_ITEM *it)
  62. {
  63. int rv = 1;
  64. /* If streaming create stream BIO and copy all content through it */
  65. if (flags & SMIME_STREAM) {
  66. BIO *bio, *tbio;
  67. bio = BIO_new_NDEF(out, val, it);
  68. if (!bio) {
  69. ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB);
  70. return 0;
  71. }
  72. if (!SMIME_crlf_copy(in, bio, flags)) {
  73. rv = 0;
  74. }
  75. (void)BIO_flush(bio);
  76. /* Free up successive BIOs until we hit the old output BIO */
  77. do {
  78. tbio = BIO_pop(bio);
  79. BIO_free(bio);
  80. bio = tbio;
  81. } while (bio != out);
  82. }
  83. /*
  84. * else just write out ASN1 structure which will have all content stored
  85. * internally
  86. */
  87. else
  88. rv = ASN1_item_i2d_bio(it, out, val);
  89. return rv;
  90. }
  91. /* Base 64 read and write of ASN1 structure */
  92. static int B64_write_ASN1(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
  93. const ASN1_ITEM *it)
  94. {
  95. BIO *b64;
  96. int r;
  97. b64 = BIO_new(BIO_f_base64());
  98. if (b64 == NULL) {
  99. ERR_raise(ERR_LIB_ASN1, ERR_R_BIO_LIB);
  100. return 0;
  101. }
  102. /*
  103. * prepend the b64 BIO so all data is base64 encoded.
  104. */
  105. out = BIO_push(b64, out);
  106. r = i2d_ASN1_bio_stream(out, val, in, flags, it);
  107. (void)BIO_flush(out);
  108. BIO_pop(out);
  109. BIO_free(b64);
  110. return r;
  111. }
  112. /* Streaming ASN1 PEM write */
  113. int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
  114. const char *hdr, const ASN1_ITEM *it)
  115. {
  116. int r;
  117. BIO_printf(out, "-----BEGIN %s-----\n", hdr);
  118. r = B64_write_ASN1(out, val, in, flags, it);
  119. BIO_printf(out, "-----END %s-----\n", hdr);
  120. return r;
  121. }
  122. static ASN1_VALUE *b64_read_asn1(BIO *bio, const ASN1_ITEM *it, ASN1_VALUE **x,
  123. OSSL_LIB_CTX *libctx, const char *propq)
  124. {
  125. BIO *b64;
  126. ASN1_VALUE *val;
  127. if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
  128. ERR_raise(ERR_LIB_ASN1, ERR_R_BIO_LIB);
  129. return 0;
  130. }
  131. bio = BIO_push(b64, bio);
  132. val = ASN1_item_d2i_bio_ex(it, bio, x, libctx, propq);
  133. if (!val)
  134. ERR_raise(ERR_LIB_ASN1, ASN1_R_DECODE_ERROR);
  135. (void)BIO_flush(bio);
  136. BIO_pop(bio);
  137. BIO_free(b64);
  138. return val;
  139. }
  140. /* Generate the MIME "micalg" parameter from RFC3851, RFC4490 */
  141. static int asn1_write_micalg(BIO *out, STACK_OF(X509_ALGOR) *mdalgs)
  142. {
  143. const EVP_MD *md;
  144. int i, have_unknown = 0, write_comma, ret = 0, md_nid;
  145. have_unknown = 0;
  146. write_comma = 0;
  147. for (i = 0; i < sk_X509_ALGOR_num(mdalgs); i++) {
  148. if (write_comma)
  149. BIO_write(out, ",", 1);
  150. write_comma = 1;
  151. md_nid = OBJ_obj2nid(sk_X509_ALGOR_value(mdalgs, i)->algorithm);
  152. /* RFC 8702 does not define a micalg for SHAKE, assuming "shake-<bitlen>" */
  153. if (md_nid == NID_shake128) {
  154. if (BIO_puts(out, "shake-128") < 0)
  155. goto err;
  156. continue;
  157. }
  158. if (md_nid == NID_shake256) {
  159. if (BIO_puts(out, "shake-256") < 0)
  160. goto err;
  161. continue;
  162. }
  163. md = EVP_get_digestbynid(md_nid);
  164. if (md && md->md_ctrl) {
  165. int rv;
  166. char *micstr;
  167. rv = md->md_ctrl(NULL, EVP_MD_CTRL_MICALG, 0, &micstr);
  168. if (rv > 0) {
  169. BIO_puts(out, micstr);
  170. OPENSSL_free(micstr);
  171. continue;
  172. }
  173. if (rv != -2)
  174. goto err;
  175. }
  176. switch (md_nid) {
  177. case NID_sha1:
  178. BIO_puts(out, "sha1");
  179. break;
  180. case NID_md5:
  181. BIO_puts(out, "md5");
  182. break;
  183. case NID_sha256:
  184. BIO_puts(out, "sha-256");
  185. break;
  186. case NID_sha384:
  187. BIO_puts(out, "sha-384");
  188. break;
  189. case NID_sha512:
  190. BIO_puts(out, "sha-512");
  191. break;
  192. case NID_id_GostR3411_94:
  193. BIO_puts(out, "gostr3411-94");
  194. break;
  195. case NID_id_GostR3411_2012_256:
  196. BIO_puts(out, "gostr3411-2012-256");
  197. break;
  198. case NID_id_GostR3411_2012_512:
  199. BIO_puts(out, "gostr3411-2012-512");
  200. break;
  201. default:
  202. if (have_unknown) {
  203. write_comma = 0;
  204. } else {
  205. BIO_puts(out, "unknown");
  206. have_unknown = 1;
  207. }
  208. break;
  209. }
  210. }
  211. ret = 1;
  212. err:
  213. return ret;
  214. }
  215. /* SMIME sender */
  216. int SMIME_write_ASN1_ex(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
  217. int ctype_nid, int econt_nid,
  218. STACK_OF(X509_ALGOR) *mdalgs, const ASN1_ITEM *it,
  219. OSSL_LIB_CTX *libctx, const char *propq)
  220. {
  221. char bound[33], c;
  222. int i;
  223. const char *mime_prefix, *mime_eol, *cname = "smime.p7m";
  224. const char *msg_type = NULL;
  225. if (flags & SMIME_OLDMIME)
  226. mime_prefix = "application/x-pkcs7-";
  227. else
  228. mime_prefix = "application/pkcs7-";
  229. if (flags & SMIME_CRLFEOL)
  230. mime_eol = "\r\n";
  231. else
  232. mime_eol = "\n";
  233. if ((flags & SMIME_DETACHED) && data) {
  234. /* We want multipart/signed */
  235. /* Generate a random boundary */
  236. if (RAND_bytes_ex(libctx, (unsigned char *)bound, 32, 0) <= 0)
  237. return 0;
  238. for (i = 0; i < 32; i++) {
  239. c = bound[i] & 0xf;
  240. if (c < 10)
  241. c += '0';
  242. else
  243. c += 'A' - 10;
  244. bound[i] = c;
  245. }
  246. bound[32] = 0;
  247. BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
  248. BIO_printf(bio, "Content-Type: multipart/signed;");
  249. BIO_printf(bio, " protocol=\"%ssignature\";", mime_prefix);
  250. BIO_puts(bio, " micalg=\"");
  251. if (!asn1_write_micalg(bio, mdalgs))
  252. return 0;
  253. BIO_printf(bio, "\"; boundary=\"----%s\"%s%s",
  254. bound, mime_eol, mime_eol);
  255. BIO_printf(bio, "This is an S/MIME signed message%s%s",
  256. mime_eol, mime_eol);
  257. /* Now write out the first part */
  258. BIO_printf(bio, "------%s%s", bound, mime_eol);
  259. if (!asn1_output_data(bio, data, val, flags, it))
  260. return 0;
  261. BIO_printf(bio, "%s------%s%s", mime_eol, bound, mime_eol);
  262. /* Headers for signature */
  263. BIO_printf(bio, "Content-Type: %ssignature;", mime_prefix);
  264. BIO_printf(bio, " name=\"smime.p7s\"%s", mime_eol);
  265. BIO_printf(bio, "Content-Transfer-Encoding: base64%s", mime_eol);
  266. BIO_printf(bio, "Content-Disposition: attachment;");
  267. BIO_printf(bio, " filename=\"smime.p7s\"%s%s", mime_eol, mime_eol);
  268. B64_write_ASN1(bio, val, NULL, 0, it);
  269. BIO_printf(bio, "%s------%s--%s%s", mime_eol, bound,
  270. mime_eol, mime_eol);
  271. return 1;
  272. }
  273. /* Determine smime-type header */
  274. if (ctype_nid == NID_pkcs7_enveloped) {
  275. msg_type = "enveloped-data";
  276. } else if (ctype_nid == NID_id_smime_ct_authEnvelopedData) {
  277. msg_type = "authEnveloped-data";
  278. } else if (ctype_nid == NID_pkcs7_signed) {
  279. if (econt_nid == NID_id_smime_ct_receipt)
  280. msg_type = "signed-receipt";
  281. else if (sk_X509_ALGOR_num(mdalgs) >= 0)
  282. msg_type = "signed-data";
  283. else
  284. msg_type = "certs-only";
  285. } else if (ctype_nid == NID_id_smime_ct_compressedData) {
  286. msg_type = "compressed-data";
  287. cname = "smime.p7z";
  288. }
  289. /* MIME headers */
  290. BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
  291. BIO_printf(bio, "Content-Disposition: attachment;");
  292. BIO_printf(bio, " filename=\"%s\"%s", cname, mime_eol);
  293. BIO_printf(bio, "Content-Type: %smime;", mime_prefix);
  294. if (msg_type)
  295. BIO_printf(bio, " smime-type=%s;", msg_type);
  296. BIO_printf(bio, " name=\"%s\"%s", cname, mime_eol);
  297. BIO_printf(bio, "Content-Transfer-Encoding: base64%s%s",
  298. mime_eol, mime_eol);
  299. if (!B64_write_ASN1(bio, val, data, flags, it))
  300. return 0;
  301. BIO_printf(bio, "%s", mime_eol);
  302. return 1;
  303. }
  304. int SMIME_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
  305. int ctype_nid, int econt_nid,
  306. STACK_OF(X509_ALGOR) *mdalgs, const ASN1_ITEM *it)
  307. {
  308. return SMIME_write_ASN1_ex(bio, val, data, flags, ctype_nid, econt_nid,
  309. mdalgs, it, NULL, NULL);
  310. }
  311. /* Handle output of ASN1 data */
  312. /* cannot constify val because of CMS_dataFinal() */
  313. static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
  314. const ASN1_ITEM *it)
  315. {
  316. BIO *tmpbio;
  317. const ASN1_AUX *aux = it->funcs;
  318. ASN1_STREAM_ARG sarg;
  319. int rv = 1;
  320. /*
  321. * If data is not detached or resigning then the output BIO is already
  322. * set up to finalise when it is written through.
  323. */
  324. if (!(flags & SMIME_DETACHED) || (flags & PKCS7_REUSE_DIGEST)) {
  325. return SMIME_crlf_copy(data, out, flags);
  326. }
  327. if (!aux || !aux->asn1_cb) {
  328. ERR_raise(ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED);
  329. return 0;
  330. }
  331. sarg.out = out;
  332. sarg.ndef_bio = NULL;
  333. sarg.boundary = NULL;
  334. /* Let ASN1 code prepend any needed BIOs */
  335. if (aux->asn1_cb(ASN1_OP_DETACHED_PRE, &val, it, &sarg) <= 0)
  336. return 0;
  337. /* Copy data across, passing through filter BIOs for processing */
  338. if (!SMIME_crlf_copy(data, sarg.ndef_bio, flags))
  339. rv = 0;
  340. /* Finalize structure */
  341. if (aux->asn1_cb(ASN1_OP_DETACHED_POST, &val, it, &sarg) <= 0)
  342. rv = 0;
  343. /* Now remove any digests prepended to the BIO */
  344. while (sarg.ndef_bio != out) {
  345. tmpbio = BIO_pop(sarg.ndef_bio);
  346. BIO_free(sarg.ndef_bio);
  347. sarg.ndef_bio = tmpbio;
  348. }
  349. return rv;
  350. }
  351. /*
  352. * SMIME reader: handle multipart/signed and opaque signing. in multipart
  353. * case the content is placed in a memory BIO pointed to by "bcont". In
  354. * opaque this is set to NULL
  355. */
  356. ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont,
  357. const ASN1_ITEM *it, ASN1_VALUE **x,
  358. OSSL_LIB_CTX *libctx, const char *propq)
  359. {
  360. BIO *asnin;
  361. STACK_OF(MIME_HEADER) *headers = NULL;
  362. STACK_OF(BIO) *parts = NULL;
  363. MIME_HEADER *hdr;
  364. MIME_PARAM *prm;
  365. ASN1_VALUE *val;
  366. int ret;
  367. if (bcont)
  368. *bcont = NULL;
  369. if ((headers = mime_parse_hdr(bio)) == NULL) {
  370. ERR_raise(ERR_LIB_ASN1, ASN1_R_MIME_PARSE_ERROR);
  371. return NULL;
  372. }
  373. if ((hdr = mime_hdr_find(headers, "content-type")) == NULL
  374. || hdr->value == NULL) {
  375. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  376. ERR_raise(ERR_LIB_ASN1, ASN1_R_NO_CONTENT_TYPE);
  377. return NULL;
  378. }
  379. /* Handle multipart/signed */
  380. if (strcmp(hdr->value, "multipart/signed") == 0) {
  381. /* Split into two parts */
  382. prm = mime_param_find(hdr, "boundary");
  383. if (prm == NULL || prm->param_value == NULL) {
  384. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  385. ERR_raise(ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BOUNDARY);
  386. return NULL;
  387. }
  388. ret = multi_split(bio, flags, prm->param_value, &parts);
  389. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  390. if (!ret || (sk_BIO_num(parts) != 2)) {
  391. ERR_raise(ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BODY_FAILURE);
  392. sk_BIO_pop_free(parts, BIO_vfree);
  393. return NULL;
  394. }
  395. /* Parse the signature piece */
  396. asnin = sk_BIO_value(parts, 1);
  397. if ((headers = mime_parse_hdr(asnin)) == NULL) {
  398. ERR_raise(ERR_LIB_ASN1, ASN1_R_MIME_SIG_PARSE_ERROR);
  399. sk_BIO_pop_free(parts, BIO_vfree);
  400. return NULL;
  401. }
  402. /* Get content type */
  403. if ((hdr = mime_hdr_find(headers, "content-type")) == NULL
  404. || hdr->value == NULL) {
  405. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  406. ERR_raise(ERR_LIB_ASN1, ASN1_R_NO_SIG_CONTENT_TYPE);
  407. sk_BIO_pop_free(parts, BIO_vfree);
  408. return NULL;
  409. }
  410. if (strcmp(hdr->value, "application/x-pkcs7-signature") &&
  411. strcmp(hdr->value, "application/pkcs7-signature")) {
  412. ERR_raise_data(ERR_LIB_ASN1, ASN1_R_SIG_INVALID_MIME_TYPE,
  413. "type: %s", hdr->value);
  414. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  415. sk_BIO_pop_free(parts, BIO_vfree);
  416. return NULL;
  417. }
  418. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  419. /* Read in ASN1 */
  420. if ((val = b64_read_asn1(asnin, it, x, libctx, propq)) == NULL) {
  421. ERR_raise(ERR_LIB_ASN1, ASN1_R_ASN1_SIG_PARSE_ERROR);
  422. sk_BIO_pop_free(parts, BIO_vfree);
  423. return NULL;
  424. }
  425. if (bcont) {
  426. *bcont = sk_BIO_value(parts, 0);
  427. BIO_free(asnin);
  428. sk_BIO_free(parts);
  429. } else {
  430. sk_BIO_pop_free(parts, BIO_vfree);
  431. }
  432. return val;
  433. }
  434. /* OK, if not multipart/signed try opaque signature */
  435. if (strcmp(hdr->value, "application/x-pkcs7-mime") &&
  436. strcmp(hdr->value, "application/pkcs7-mime")) {
  437. ERR_raise_data(ERR_LIB_ASN1, ASN1_R_INVALID_MIME_TYPE,
  438. "type: %s", hdr->value);
  439. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  440. return NULL;
  441. }
  442. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  443. if ((val = b64_read_asn1(bio, it, x, libctx, propq)) == NULL) {
  444. ERR_raise(ERR_LIB_ASN1, ASN1_R_ASN1_PARSE_ERROR);
  445. return NULL;
  446. }
  447. return val;
  448. }
  449. ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it)
  450. {
  451. return SMIME_read_ASN1_ex(bio, 0, bcont, it, NULL, NULL, NULL);
  452. }
  453. /* Copy text from one BIO to another making the output CRLF at EOL */
  454. int SMIME_crlf_copy(BIO *in, BIO *out, int flags)
  455. {
  456. BIO *bf;
  457. char eol;
  458. int len;
  459. char linebuf[MAX_SMLEN];
  460. int ret;
  461. if (in == NULL || out == NULL) {
  462. ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER);
  463. return 0;
  464. }
  465. /*
  466. * Buffer output so we don't write one line at a time. This is useful
  467. * when streaming as we don't end up with one OCTET STRING per line.
  468. */
  469. bf = BIO_new(BIO_f_buffer());
  470. if (bf == NULL) {
  471. ERR_raise(ERR_LIB_ASN1, ERR_R_BIO_LIB);
  472. return 0;
  473. }
  474. out = BIO_push(bf, out);
  475. if (flags & SMIME_BINARY) {
  476. while ((len = BIO_read(in, linebuf, MAX_SMLEN)) > 0)
  477. BIO_write(out, linebuf, len);
  478. } else {
  479. int eolcnt = 0;
  480. if (flags & SMIME_TEXT)
  481. BIO_printf(out, "Content-Type: text/plain\r\n\r\n");
  482. while ((len = BIO_gets(in, linebuf, MAX_SMLEN)) > 0) {
  483. eol = strip_eol(linebuf, &len, flags);
  484. if (len > 0) {
  485. /* Not EOF: write out all CRLF */
  486. if (flags & SMIME_ASCIICRLF) {
  487. int i;
  488. for (i = 0; i < eolcnt; i++)
  489. BIO_write(out, "\r\n", 2);
  490. eolcnt = 0;
  491. }
  492. BIO_write(out, linebuf, len);
  493. if (eol)
  494. BIO_write(out, "\r\n", 2);
  495. } else if (flags & SMIME_ASCIICRLF) {
  496. eolcnt++;
  497. } else if (eol) {
  498. BIO_write(out, "\r\n", 2);
  499. }
  500. }
  501. }
  502. ret = BIO_flush(out);
  503. BIO_pop(out);
  504. BIO_free(bf);
  505. if (ret <= 0)
  506. return 0;
  507. return 1;
  508. }
  509. /* Strip off headers if they are text/plain */
  510. int SMIME_text(BIO *in, BIO *out)
  511. {
  512. char iobuf[4096];
  513. int len;
  514. STACK_OF(MIME_HEADER) *headers;
  515. MIME_HEADER *hdr;
  516. if ((headers = mime_parse_hdr(in)) == NULL) {
  517. ERR_raise(ERR_LIB_ASN1, ASN1_R_MIME_PARSE_ERROR);
  518. return 0;
  519. }
  520. if ((hdr = mime_hdr_find(headers, "content-type")) == NULL
  521. || hdr->value == NULL) {
  522. ERR_raise(ERR_LIB_ASN1, ASN1_R_MIME_NO_CONTENT_TYPE);
  523. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  524. return 0;
  525. }
  526. if (strcmp(hdr->value, "text/plain")) {
  527. ERR_raise_data(ERR_LIB_ASN1, ASN1_R_INVALID_MIME_TYPE,
  528. "type: %s", hdr->value);
  529. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  530. return 0;
  531. }
  532. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  533. while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
  534. BIO_write(out, iobuf, len);
  535. if (len < 0)
  536. return 0;
  537. return 1;
  538. }
  539. /*
  540. * Split a multipart/XXX message body into component parts: result is
  541. * canonical parts in a STACK of bios
  542. */
  543. static int multi_split(BIO *bio, int flags, const char *bound, STACK_OF(BIO) **ret)
  544. {
  545. char linebuf[MAX_SMLEN];
  546. int len, blen;
  547. int eol = 0, next_eol = 0;
  548. BIO *bpart = NULL;
  549. STACK_OF(BIO) *parts;
  550. char state, part, first;
  551. blen = strlen(bound);
  552. part = 0;
  553. state = 0;
  554. first = 1;
  555. parts = sk_BIO_new_null();
  556. *ret = parts;
  557. if (*ret == NULL)
  558. return 0;
  559. while ((len = BIO_get_line(bio, linebuf, MAX_SMLEN)) > 0) {
  560. state = mime_bound_check(linebuf, len, bound, blen);
  561. if (state == 1) {
  562. first = 1;
  563. part++;
  564. } else if (state == 2) {
  565. if (!sk_BIO_push(parts, bpart)) {
  566. BIO_free(bpart);
  567. return 0;
  568. }
  569. return 1;
  570. } else if (part != 0) {
  571. /* Strip (possibly CR +) LF from linebuf */
  572. next_eol = strip_eol(linebuf, &len, flags);
  573. if (first) {
  574. first = 0;
  575. if (bpart)
  576. if (!sk_BIO_push(parts, bpart)) {
  577. BIO_free(bpart);
  578. return 0;
  579. }
  580. bpart = BIO_new(BIO_s_mem());
  581. if (bpart == NULL)
  582. return 0;
  583. BIO_set_mem_eof_return(bpart, 0);
  584. } else if (eol) {
  585. if (
  586. #ifndef OPENSSL_NO_CMS
  587. (flags & CMS_BINARY) == 0
  588. #else
  589. 1
  590. #endif
  591. || (flags & SMIME_CRLFEOL) != 0)
  592. BIO_write(bpart, "\r\n", 2);
  593. else
  594. BIO_write(bpart, "\n", 1);
  595. }
  596. eol = next_eol;
  597. if (len > 0)
  598. BIO_write(bpart, linebuf, len);
  599. }
  600. }
  601. BIO_free(bpart);
  602. return 0;
  603. }
  604. /* This is the big one: parse MIME header lines up to message body */
  605. #define MIME_INVALID 0
  606. #define MIME_START 1
  607. #define MIME_TYPE 2
  608. #define MIME_NAME 3
  609. #define MIME_VALUE 4
  610. #define MIME_QUOTE 5
  611. #define MIME_COMMENT 6
  612. static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio)
  613. {
  614. char *p, *q, c;
  615. char *ntmp;
  616. char linebuf[MAX_SMLEN];
  617. MIME_HEADER *mhdr = NULL, *new_hdr = NULL;
  618. STACK_OF(MIME_HEADER) *headers;
  619. int i, len, state, save_state = 0;
  620. headers = sk_MIME_HEADER_new(mime_hdr_cmp);
  621. if (headers == NULL)
  622. return NULL;
  623. while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
  624. /* If whitespace at line start then continuation line */
  625. if (mhdr && ossl_isspace(linebuf[0]))
  626. state = MIME_NAME;
  627. else
  628. state = MIME_START;
  629. ntmp = NULL;
  630. /* Go through all characters */
  631. for (p = linebuf, q = linebuf; (c = *p) && (c != '\r') && (c != '\n');
  632. p++) {
  633. /*
  634. * State machine to handle MIME headers if this looks horrible
  635. * that's because it *is*
  636. */
  637. switch (state) {
  638. case MIME_START:
  639. if (c == ':') {
  640. state = MIME_TYPE;
  641. *p = 0;
  642. ntmp = strip_ends(q);
  643. q = p + 1;
  644. }
  645. break;
  646. case MIME_TYPE:
  647. if (c == ';') {
  648. mime_debug("Found End Value\n");
  649. *p = 0;
  650. new_hdr = mime_hdr_new(ntmp, strip_ends(q));
  651. if (new_hdr == NULL)
  652. goto err;
  653. if (!sk_MIME_HEADER_push(headers, new_hdr))
  654. goto err;
  655. mhdr = new_hdr;
  656. new_hdr = NULL;
  657. ntmp = NULL;
  658. q = p + 1;
  659. state = MIME_NAME;
  660. } else if (c == '(') {
  661. save_state = state;
  662. state = MIME_COMMENT;
  663. }
  664. break;
  665. case MIME_COMMENT:
  666. if (c == ')') {
  667. state = save_state;
  668. }
  669. break;
  670. case MIME_NAME:
  671. if (c == '=') {
  672. state = MIME_VALUE;
  673. *p = 0;
  674. ntmp = strip_ends(q);
  675. q = p + 1;
  676. }
  677. break;
  678. case MIME_VALUE:
  679. if (c == ';') {
  680. state = MIME_NAME;
  681. *p = 0;
  682. mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
  683. ntmp = NULL;
  684. q = p + 1;
  685. } else if (c == '"') {
  686. mime_debug("Found Quote\n");
  687. state = MIME_QUOTE;
  688. } else if (c == '(') {
  689. save_state = state;
  690. state = MIME_COMMENT;
  691. }
  692. break;
  693. case MIME_QUOTE:
  694. if (c == '"') {
  695. mime_debug("Found Match Quote\n");
  696. state = MIME_VALUE;
  697. }
  698. break;
  699. }
  700. }
  701. if (state == MIME_TYPE) {
  702. new_hdr = mime_hdr_new(ntmp, strip_ends(q));
  703. if (new_hdr == NULL)
  704. goto err;
  705. if (!sk_MIME_HEADER_push(headers, new_hdr))
  706. goto err;
  707. mhdr = new_hdr;
  708. new_hdr = NULL;
  709. } else if (state == MIME_VALUE) {
  710. mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
  711. }
  712. if (p == linebuf)
  713. break; /* Blank line means end of headers */
  714. }
  715. /* Sort the headers and their params for faster searching */
  716. sk_MIME_HEADER_sort(headers);
  717. for (i = 0; i < sk_MIME_HEADER_num(headers); i++)
  718. if ((mhdr = sk_MIME_HEADER_value(headers, i)) != NULL
  719. && mhdr->params != NULL)
  720. sk_MIME_PARAM_sort(mhdr->params);
  721. return headers;
  722. err:
  723. mime_hdr_free(new_hdr);
  724. sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
  725. return NULL;
  726. }
  727. static char *strip_ends(char *name)
  728. {
  729. return strip_end(strip_start(name));
  730. }
  731. /* Strip a parameter of whitespace from start of param */
  732. static char *strip_start(char *name)
  733. {
  734. char *p, c;
  735. /* Look for first non whitespace or quote */
  736. for (p = name; (c = *p); p++) {
  737. if (c == '"') {
  738. /* Next char is start of string if non null */
  739. if (p[1])
  740. return p + 1;
  741. /* Else null string */
  742. return NULL;
  743. }
  744. if (!ossl_isspace(c))
  745. return p;
  746. }
  747. return NULL;
  748. }
  749. /* As above but strip from end of string : maybe should handle brackets? */
  750. static char *strip_end(char *name)
  751. {
  752. char *p, c;
  753. if (!name)
  754. return NULL;
  755. /* Look for first non whitespace or quote */
  756. for (p = name + strlen(name) - 1; p >= name; p--) {
  757. c = *p;
  758. if (c == '"') {
  759. if (p - 1 == name)
  760. return NULL;
  761. *p = 0;
  762. return name;
  763. }
  764. if (ossl_isspace(c))
  765. *p = 0;
  766. else
  767. return name;
  768. }
  769. return NULL;
  770. }
  771. static MIME_HEADER *mime_hdr_new(const char *name, const char *value)
  772. {
  773. MIME_HEADER *mhdr = NULL;
  774. char *tmpname = NULL, *tmpval = NULL, *p;
  775. if (name) {
  776. if ((tmpname = OPENSSL_strdup(name)) == NULL)
  777. return NULL;
  778. for (p = tmpname; *p; p++)
  779. *p = ossl_tolower(*p);
  780. }
  781. if (value) {
  782. if ((tmpval = OPENSSL_strdup(value)) == NULL)
  783. goto err;
  784. for (p = tmpval; *p; p++)
  785. *p = ossl_tolower(*p);
  786. }
  787. mhdr = OPENSSL_malloc(sizeof(*mhdr));
  788. if (mhdr == NULL)
  789. goto err;
  790. mhdr->name = tmpname;
  791. mhdr->value = tmpval;
  792. if ((mhdr->params = sk_MIME_PARAM_new(mime_param_cmp)) == NULL)
  793. goto err;
  794. return mhdr;
  795. err:
  796. OPENSSL_free(tmpname);
  797. OPENSSL_free(tmpval);
  798. OPENSSL_free(mhdr);
  799. return NULL;
  800. }
  801. static int mime_hdr_addparam(MIME_HEADER *mhdr, const char *name, const char *value)
  802. {
  803. char *tmpname = NULL, *tmpval = NULL, *p;
  804. MIME_PARAM *mparam = NULL;
  805. if (name) {
  806. tmpname = OPENSSL_strdup(name);
  807. if (!tmpname)
  808. goto err;
  809. for (p = tmpname; *p; p++)
  810. *p = ossl_tolower(*p);
  811. }
  812. if (value) {
  813. tmpval = OPENSSL_strdup(value);
  814. if (!tmpval)
  815. goto err;
  816. }
  817. /* Parameter values are case sensitive so leave as is */
  818. mparam = OPENSSL_malloc(sizeof(*mparam));
  819. if (mparam == NULL)
  820. goto err;
  821. mparam->param_name = tmpname;
  822. mparam->param_value = tmpval;
  823. if (!sk_MIME_PARAM_push(mhdr->params, mparam))
  824. goto err;
  825. return 1;
  826. err:
  827. OPENSSL_free(tmpname);
  828. OPENSSL_free(tmpval);
  829. OPENSSL_free(mparam);
  830. return 0;
  831. }
  832. static int mime_hdr_cmp(const MIME_HEADER *const *a,
  833. const MIME_HEADER *const *b)
  834. {
  835. if ((*a)->name == NULL || (*b)->name == NULL)
  836. return ((*a)->name != NULL) - ((*b)->name != NULL);
  837. return strcmp((*a)->name, (*b)->name);
  838. }
  839. static int mime_param_cmp(const MIME_PARAM *const *a,
  840. const MIME_PARAM *const *b)
  841. {
  842. if ((*a)->param_name == NULL || (*b)->param_name == NULL)
  843. return ((*a)->param_name != NULL) - ((*b)->param_name != NULL);
  844. return strcmp((*a)->param_name, (*b)->param_name);
  845. }
  846. /* Find a header with a given name (if possible) */
  847. static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, const char *name)
  848. {
  849. MIME_HEADER htmp;
  850. int idx;
  851. htmp.name = (char *)name;
  852. htmp.value = NULL;
  853. htmp.params = NULL;
  854. idx = sk_MIME_HEADER_find(hdrs, &htmp);
  855. return sk_MIME_HEADER_value(hdrs, idx);
  856. }
  857. static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, const char *name)
  858. {
  859. MIME_PARAM param;
  860. int idx;
  861. param.param_name = (char *)name;
  862. param.param_value = NULL;
  863. idx = sk_MIME_PARAM_find(hdr->params, &param);
  864. return sk_MIME_PARAM_value(hdr->params, idx);
  865. }
  866. static void mime_hdr_free(MIME_HEADER *hdr)
  867. {
  868. if (hdr == NULL)
  869. return;
  870. OPENSSL_free(hdr->name);
  871. OPENSSL_free(hdr->value);
  872. if (hdr->params)
  873. sk_MIME_PARAM_pop_free(hdr->params, mime_param_free);
  874. OPENSSL_free(hdr);
  875. }
  876. static void mime_param_free(MIME_PARAM *param)
  877. {
  878. OPENSSL_free(param->param_name);
  879. OPENSSL_free(param->param_value);
  880. OPENSSL_free(param);
  881. }
  882. /*-
  883. * Check for a multipart boundary. Returns:
  884. * 0 : no boundary
  885. * 1 : part boundary
  886. * 2 : final boundary
  887. */
  888. static int mime_bound_check(char *line, int linelen, const char *bound, int blen)
  889. {
  890. if (linelen == -1)
  891. linelen = strlen(line);
  892. if (blen == -1)
  893. blen = strlen(bound);
  894. /* Quickly eliminate if line length too short */
  895. if (blen + 2 > linelen)
  896. return 0;
  897. /* Check for part boundary */
  898. if ((CHECK_AND_SKIP_PREFIX(line, "--")) && strncmp(line, bound, blen) == 0)
  899. return HAS_PREFIX(line + blen, "--") ? 2 : 1;
  900. return 0;
  901. }
  902. static int strip_eol(char *linebuf, int *plen, int flags)
  903. {
  904. int len = *plen;
  905. char *p, c;
  906. int is_eol = 0;
  907. #ifndef OPENSSL_NO_CMS
  908. if ((flags & CMS_BINARY) != 0) {
  909. if (len <= 0 || linebuf[len - 1] != '\n')
  910. return 0;
  911. if ((flags & SMIME_CRLFEOL) != 0) {
  912. if (len <= 1 || linebuf[len - 2] != '\r')
  913. return 0;
  914. len--;
  915. }
  916. len--;
  917. *plen = len;
  918. return 1;
  919. }
  920. #endif
  921. for (p = linebuf + len - 1; len > 0; len--, p--) {
  922. c = *p;
  923. if (c == '\n') {
  924. is_eol = 1;
  925. } else if (is_eol && (flags & SMIME_ASCIICRLF) != 0 && c == 32) {
  926. /* Strip trailing space on a line; 32 == ASCII for ' ' */
  927. continue;
  928. } else if (c != '\r') {
  929. break;
  930. }
  931. }
  932. *plen = len;
  933. return is_eol;
  934. }