Branch data Line data Source code
1 : : /* smime-enc.c - Utility functions for performing S/MIME signatures
2 : : * and encryption.
3 : : *
4 : : * Copyright (c) 1999 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved.
5 : : * License: This software may be distributed under the same license
6 : : * terms as openssl (i.e. free, but mandatory attribution).
7 : : * See file LICENSE for details.
8 : : *
9 : : * 11.9.1999, Created. --Sampo
10 : : * 13.9.1999, 0.1 released. Now adding verify. --Sampo
11 : : * 1.10.1999, improved error handling, fixed decrypt --Sampo
12 : : * 6.10.1999, separated from smimeutil.c --Sampo
13 : : * 9.10.1999, reviewed for free problems --Sampo
14 : : *
15 : : * This module has adopted ideas and control flow from
16 : : * openssl-0.9.4/crypto/pkcs7/sign.c
17 : : * openssl-0.9.4/crypto/pkcs7/verify.c
18 : : * openssl-0.9.4/crypto/pkcs7/enc.c
19 : : * openssl-0.9.4/crypto/pkcs7/dec.c
20 : : * which are Copyright (c) 1995-1998 Eric Young (eay@cryptsoft.com),
21 : : * All rights reserved. See file LICENSE for conditions.
22 : : *
23 : : * This module has been developed to support a Lingo XTRA that is supposed
24 : : * to provide crypto functionality. It may, however, be useful for other
25 : : * purposes as well.
26 : : *
27 : : * This is a very simple S/MIME library. For example the multipart
28 : : * boundary separators are hard coded and no effort is made to verify
29 : : * that mime entities are in their canonical form before signing (the
30 : : * caller should make sure they are, canonical form means using CRLF
31 : : * as line termination, among other things). Also the multipart functionality
32 : : * only understands up to 3 attachments. For many tasks this is enough,
33 : : * but if its not, feel free to write more generic utilities.
34 : : *
35 : : * Memory management: most routines malloc the results. Freeing them is
36 : : * application's responsibility. I use libc malloc, but if in doubt
37 : : * it might be safer to just leak the memory (i.e. don't ever free it).
38 : : * This library works entirely in memory, so maximum memory consumption
39 : : * might be more than twice the total size of all files to be encrypted.
40 : : */
41 : :
42 : : /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
43 : : * All rights reserved.
44 : : *
45 : : * This package is an SSL implementation written
46 : : * by Eric Young (eay@cryptsoft.com).
47 : : * The implementation was written so as to conform with Netscapes SSL.
48 : : *
49 : : * This library is free for commercial and non-commercial use as long as
50 : : * the following conditions are aheared to. The following conditions
51 : : * apply to all code found in this distribution, be it the RC4, RSA,
52 : : * lhash, DES, etc., code; not just the SSL code. The SSL documentation
53 : : * included with this distribution is covered by the same copyright terms
54 : : * except that the holder is Tim Hudson (tjh@cryptsoft.com).
55 : : *
56 : : * Copyright remains Eric Young's, and as such any Copyright notices in
57 : : * the code are not to be removed.
58 : : * If this package is used in a product, Eric Young should be given attribution
59 : : * as the author of the parts of the library used.
60 : : * This can be in the form of a textual message at program startup or
61 : : * in documentation (online or textual) provided with the package.
62 : : *
63 : : * Redistribution and use in source and binary forms, with or without
64 : : * modification, are permitted provided that the following conditions
65 : : * are met:
66 : : * 1. Redistributions of source code must retain the copyright
67 : : * notice, this list of conditions and the following disclaimer.
68 : : * 2. Redistributions in binary form must reproduce the above copyright
69 : : * notice, this list of conditions and the following disclaimer in the
70 : : * documentation and/or other materials provided with the distribution.
71 : : * 3. All advertising materials mentioning features or use of this software
72 : : * must display the following acknowledgement:
73 : : * "This product includes cryptographic software written by
74 : : * Eric Young (eay@cryptsoft.com)"
75 : : * The word 'cryptographic' can be left out if the rouines from the library
76 : : * being used are not cryptographic related :-).
77 : : * 4. If you include any Windows specific code (or a derivative thereof) from
78 : : * the apps directory (application code) you must include an acknowledgement:
79 : : * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
80 : : *
81 : : * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
82 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
83 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
84 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
85 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
86 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
87 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
88 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
89 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
90 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
91 : : * SUCH DAMAGE.
92 : : *
93 : : * The licence and distribution terms for any publically available version or
94 : : * derivative of this code cannot be changed. i.e. this code cannot simply be
95 : : * copied and put under another distribution licence
96 : : * [including the GNU Public Licence.]
97 : : */
98 : :
99 : : #include "platform.h"
100 : :
101 : : #include <stdio.h>
102 : : #include <string.h>
103 : : #include <time.h>
104 : :
105 : : #if defined(macintosh) || defined(__INTEL__)
106 : : #include "macglue.h"
107 : : #endif
108 : :
109 : : #include "logprint.h"
110 : :
111 : : #include <openssl/buffer.h>
112 : : #include <openssl/bio.h>
113 : : #include <openssl/x509.h>
114 : : #include <openssl/pem.h>
115 : : #include <openssl/err.h>
116 : : #include <openssl/rand.h>
117 : :
118 : : #define SMIME_INTERNALS /* we want also our internal helper functions */
119 : : #include "smimeutil.h"
120 : :
121 : : /* ============= S I G N I N G & E N C R Y P T I O N ============= */
122 : :
123 : : /* Typically signing and encryption involves a sequence of calls like
124 : : *
125 : : * msg = smime_encrypt(pubkey,
126 : : * smime_clear_sign(privkey, password,
127 : : * mime_mk_multipart(text, file1, len1, type1, name1,
128 : : * NULL, 0, NULL, NULL,
129 : : * NULL, 0, NULL, NULL)));
130 : : */
131 : :
132 : : /* Helper function for signing and signature verification. */
133 : :
134 : : /* Called by: clear_sign, sign */
135 : : static BIO*
136 : : smime_sign_engine(X509* x509, EVP_PKEY* pkey,
137 : : const char* mime_entity, int detach)
138 : 0 : {
139 : : int i;
140 : : char buf[4096];
141 : 0 : BIO* p7bio = NULL;
142 : 0 : BIO* bio = NULL;
143 : 0 : PKCS7* p7 = NULL;
144 : : PKCS7_SIGNER_INFO* si;
145 : :
146 : : /* Set up BIOs and PKCS7 machinery */
147 : :
148 : : LOG_PRINT3("sig engine %x %x", x509, pkey);
149 : : LOG_PRINT3(" %x %d", mime_entity, detach);
150 [ # # # # : 0 : if (!x509 || !pkey || !mime_entity) GOTO_ERR("NULL arg(s)");
# # ]
151 [ # # ]: 0 : if (!(bio = set_read_BIO_from_buf(mime_entity, -1))) goto err;
152 : : LOG_PRINT("PKCS7_new");
153 : : /*Log_malloc = Log;*/
154 [ # # ]: 0 : if (!(p7=PKCS7_new())) GOTO_ERR("no memory?");
155 : : LOG_PRINT("PKCS7_set_type");
156 : 0 : PKCS7_set_type(p7,NID_pkcs7_signed);
157 : : /*Log_malloc = NULL;*/
158 : : LOG_PRINT("Adding sig");
159 [ # # ]: 0 : if (!(si=PKCS7_add_signature(p7,x509,pkey,EVP_sha1())))
160 : 0 : GOTO_ERR("PKCS7_add_signature");
161 : :
162 : : LOG_PRINT("Adding signed attribute");
163 : : /* If you do this then you get signing time automatically added */
164 : 0 : PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT,
165 : : OBJ_nid2obj(NID_pkcs7_data));
166 : : /*PKCS7_add_certificate(p7,x509);*/
167 [ # # ]: 0 : if (detach) PKCS7_set_detached(p7,1);
168 : :
169 : : /* Set the content of the signed to 'data' */
170 : 0 : PKCS7_content_new(p7,NID_pkcs7_data);
171 : :
172 [ # # ]: 0 : if (!(p7bio=PKCS7_dataInit(p7,NULL))) GOTO_ERR("PKCS7_dataInit");
173 : :
174 : : /* pump data from file to special PKCS7 BIO. This hashes it. */
175 : :
176 : : LOG_PRINT("pumping");
177 : :
178 : : for (;;) {
179 : 0 : i=BIO_read(bio,buf,sizeof(buf));
180 [ # # ]: 0 : if (i <= 0) break;
181 : 0 : BIO_write(p7bio,buf,i);
182 : 0 : }
183 : 0 : BIO_flush(p7bio);
184 : :
185 : : LOG_PRINT("data final...");
186 [ # # ]: 0 : if (!PKCS7_dataFinal(p7,p7bio)) GOTO_ERR("PKCS7_dataFinal");
187 : 0 : BIO_free_all(p7bio);
188 : 0 : p7bio = NULL;
189 : 0 : BIO_free_all(bio);
190 : :
191 [ # # ]: 0 : if (!(bio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
192 : : LOG_PRINT("Writing data to bio");
193 : 0 : PEM_write_bio_PKCS7(bio,p7);
194 : 0 : BIO_flush(bio);
195 : 0 : PKCS7_free(p7);
196 : :
197 : : LOG_PRINT2("sig engine done %x", bio);
198 : 0 : return bio; /* return written memory bio (must be freed by caller)
199 : : * caller will extract the data from buffer. */
200 : :
201 : 0 : err:
202 [ # # ]: 0 : if (p7bio) BIO_free_all(p7bio);
203 [ # # ]: 0 : if (p7) PKCS7_free(p7);
204 [ # # ]: 0 : if (bio) BIO_free_all(bio);
205 : : LOG_PRINT("sig engine error");
206 : 0 : return NULL;
207 : : }
208 : :
209 : : /* Sign a mime entity, such as produced by mime_mk_multipart(). Signature
210 : : * is stored as separate mime entity so the message proper stays visible.
211 : : * I canonicalize the entity (LF->CRLF) because correct signature
212 : : * verification depends on this.
213 : : */
214 : :
215 : : /*
216 : : MIME-Version: 1.0
217 : : Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg
218 : : =sha1; boundary=sig42
219 : :
220 : : --sig42
221 : : Content-Type: text/plain
222 : :
223 : : message to be signed
224 : : --sig42
225 : : Content-Type: application/x-pkcs7-signature; name="smime.p7s"
226 : : Content-Transfer-Encoding: base64
227 : : Content-Disposition: attachment; filename="smime.p7s"
228 : : Content-Description: S/MIME Clear Signed Message
229 : :
230 : : MIAGCSqGSIb3DQEHA6CAMIIIZQIBADGCATcwggEzAgEAMIGbMIGVMQswCQYDVQQG
231 : : EwJQVDEPMA0GA1UEBxMGTGlzYm9hMRcwFQYDVQQKEw5OZXVyb25pbywgTGRhLjEZ
232 : : G0DXAj0zd/4AAAAA==
233 : : --sig42--
234 : : */
235 : :
236 : : /* Called by: smime_clear_sign */
237 : : char* /* returns smime encoded clear signed blob, or NULL if error */
238 : : clear_sign(X509* x509, EVP_PKEY* pkey, const char* mime_entity)
239 : 0 : {
240 : : char* b;
241 : : char* b64;
242 : 0 : BIO* wbio = 0;
243 : : int n;
244 : :
245 : : LOG_PRINT("clear sig, canon entity...");
246 [ # # ]: 0 : if (!(mime_entity = mime_canon(mime_entity))) goto err;
247 : : LOG_PRINT("clear sig, entity canoned. Now sig engine");
248 : :
249 : : /* Run crypto stuff over the mime_entity */
250 : :
251 [ # # ]: 0 : if (!(wbio = smime_sign_engine(x509, pkey, mime_entity, 1))) goto err;
252 : : LOG_PRINT("clear sig: signed, now get data");
253 : 0 : n = BIO_get_mem_data(wbio,&b64);
254 : : LOG_PRINT("clear sig: cut pem markers...");
255 [ # # ]: 0 : if (!(b64 = cut_pem_markers_off(b64, n, "PKCS7"))) goto err;
256 : :
257 : : /* Wrap up the result in multipart/signed object */
258 : :
259 [ # # ]: 0 : if (!(b = smime_mk_multipart_signed(mime_entity, b64))) goto err;
260 : :
261 : : LOG_PRINT("clear sig: done. free bio");
262 : 0 : BIO_free_all(wbio); /* this will also free b64 because b64 hangs from bio */
263 : 0 : return b;
264 : :
265 : 0 : err:
266 [ # # ]: 0 : if (wbio) BIO_free_all(wbio);
267 : 0 : return NULL;
268 : : }
269 : :
270 : : /* Called by: main x2 */
271 : : char*
272 : : smime_clear_sign(const char* privkey,
273 : : const char* password,
274 : : const char* mime_entity)
275 : 5 : {
276 : 5 : char* b = NULL;
277 : 5 : X509* x509 = NULL;
278 : 5 : EVP_PKEY* pkey = NULL;
279 : :
280 : : /* Get key and certificate (why do we need both?) */
281 : :
282 [ - + ]: 5 : if (!(pkey = open_private_key(privkey, password))) goto err;
283 [ # # ]: 0 : if (!(x509 = extract_certificate(privkey))) goto err;
284 : 0 : if (!(b = clear_sign(x509, pkey, mime_entity))) goto err;
285 : :
286 : 5 : err:
287 [ - + ]: 5 : if (pkey) EVP_PKEY_free(pkey);
288 [ - + ]: 5 : if (x509) X509_free(x509);
289 : 5 : return b;
290 : : }
291 : :
292 : : /* Sign a mime entity, such as produced by mime_mk_multipart(). Signature
293 : : * and entity are output as one base64 blob so the entity is not trivially
294 : : * visible. */
295 : :
296 : : /*
297 : : MIME-Version: 1.0
298 : : Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name="smime.p7m"
299 : : Content-Transfer-Encoding: base64
300 : : Content-Disposition: attachment; filename="smime.p7m"
301 : : Content-Description: S/MIME Signed Message
302 : :
303 : : MIAGCSqGSIb3DQEHA6CAMIIIZQIBADGCATcwggEzAgEAMIGbMIGVMQswCQYDVQQG
304 : : EwJQVDEPMA0GA1UEBxMGTGlzYm9hMRcwFQYDVQQKEw5OZXVyb25pbywgTGRhLjEZ
305 : : G0DXAj0zd/4AAAAA==
306 : : */
307 : :
308 : : /* Called by: smime_sign */
309 : : char* /* returns smime blob, NULL if error */
310 : : sign(X509* x509, EVP_PKEY* pkey, const char* mime_entity)
311 : 0 : {
312 : : char* b;
313 : : char* b64;
314 : : BIO* wbio;
315 : : int n;
316 : :
317 : 0 : mime_entity = mime_canon(mime_entity);
318 : :
319 : : /* Run crypto stuff over the mime_entity */
320 : :
321 [ # # ]: 0 : if (!(wbio = smime_sign_engine(x509, pkey, mime_entity, 0))) goto err;
322 : 0 : n = BIO_get_mem_data(wbio,&b64);
323 [ # # ]: 0 : if (!(b64 = cut_pem_markers_off(b64, n, "PKCS7"))) goto err;
324 : :
325 : : /* Add headers */
326 : :
327 [ # # ]: 0 : if (!(b = strdup("Content-type: application/x-pkcs7-mime; name=\"smime.p7m\"" CRLF
328 : : "Content-transfer-encoding: base64" CRLF
329 : : "Content-Disposition: attachment; filename=\"smime.p7m\"" CRLF
330 : 0 : CRLF))) GOTO_ERR("no memory?");
331 [ # # ]: 0 : if (!(b = concat(b, b64))) GOTO_ERR("no memory?");
332 : :
333 : 0 : BIO_free_all(wbio); /* also frees b64 */
334 : 0 : return b;
335 : :
336 : 0 : err:
337 [ # # ]: 0 : if (wbio) BIO_free_all(wbio);
338 : 0 : return NULL;
339 : : }
340 : :
341 : : /* Called by: main */
342 : : char*
343 : : smime_sign(const char* privkey, const char* password, const char* mime_entity)
344 : 1 : {
345 : 1 : char* b = NULL;
346 : 1 : X509* x509 = NULL;
347 : 1 : EVP_PKEY* pkey = NULL;
348 : :
349 : : /* Get key and certificate (why do we need both?) */
350 : :
351 [ - + ]: 1 : if (!(pkey = open_private_key(privkey, password))) goto err;
352 [ # # ]: 0 : if (!(x509 = extract_certificate(privkey))) goto err;
353 : 0 : if (!(b = sign(x509, pkey, mime_entity))) goto err;
354 : :
355 : 1 : err:
356 [ - + ]: 1 : if (pkey) EVP_PKEY_free(pkey);
357 [ - + ]: 1 : if (x509) X509_free(x509);
358 : 1 : return b;
359 : : }
360 : :
361 : : /* Encrypt a mime entity such as produced by smime_clear_sign(). */
362 : :
363 : : /*
364 : : MIME-Version: 1.0
365 : : Content-Type: application/x-pkcs7-mime; name="smime.p7m"
366 : : Content-Transfer-Encoding: base64
367 : : Content-Disposition: attachment; filename="smime.p7m"
368 : : Content-Description: S/MIME Encrypted Message
369 : :
370 : : MIAGCSqGSIb3DQEHA6CAMIIIZQIBADGCATcwggEzAgEAMIGbMIGVMQswCQYDVQQG
371 : : EwJQVDEPMA0GA1UEBxMGTGlzYm9hMRcwFQYDVQQKEw5OZXVyb25pbywgTGRhLjEZ
372 : : G0DXAj0zd/4AAAAA==
373 : : */
374 : :
375 : : /* Called by: smime_encrypt */
376 : : char*
377 : : encrypt1(X509* x509, const char* mime_entity)
378 : 5 : {
379 : : time_t t;
380 : : char* b;
381 : : char* b64;
382 : : int i, n;
383 : : char buf[4096];
384 : 5 : BIO* p7bio = NULL;
385 : 5 : BIO* rbio = NULL;
386 : 5 : BIO* wbio = NULL;
387 : 5 : PKCS7* p7 = NULL;;
388 : :
389 : 5 : t = time(NULL);
390 : 5 : RAND_seed(&t,sizeof(t));
391 : : #ifdef WINDOWS
392 : : RAND_screen(); /* Loading video display memory into random state */
393 : : #endif
394 : :
395 : : LOG_PRINT3("encrypt1", x509, mime_entity);
396 : :
397 : : /* Set up BIOs and PKCS7 machinery */
398 : :
399 [ + + ]: 5 : if (!(rbio = set_read_BIO_from_buf(mime_entity, -1))) goto err;
400 : :
401 [ - + ]: 3 : if (!(p7=PKCS7_new())) GOTO_ERR("no memory?");
402 : 3 : PKCS7_set_type(p7,NID_pkcs7_enveloped);
403 : :
404 : : #if 1
405 [ - + ]: 3 : if (!PKCS7_set_cipher(p7,EVP_des_ede3_cbc()))
406 : 0 : GOTO_ERR("PKCS7_set_cipher des-ede3-cbc");
407 : : #else
408 : : /* SECURITY CAVEAT: weak cipher by default */
409 : : if (!PKCS7_set_cipher(p7,EVP_rc2_40_cbc()))
410 : : GOTO_ERR("PKCS7_set_cipher rc2-40-cbc");
411 : : #endif
412 : :
413 : : LOG_PRINT("encrypt1: add recipient");
414 : :
415 [ - + ]: 3 : if (!PKCS7_add_recipient(p7,x509)) GOTO_ERR("PKCS7_add_recipient");
416 : :
417 : : LOG_PRINT("encrypt1: data init");
418 [ - + ]: 3 : if (!(p7bio=PKCS7_dataInit(p7,NULL))) GOTO_ERR("PKCS7_dataInit");
419 : :
420 : : /* pump data from file to special PKCS7 BIO. This encrypts it. */
421 : :
422 : : LOG_PRINT("encrypt1: pump");
423 : : for (;;) {
424 : 6 : i=BIO_read(rbio,buf,sizeof(buf));
425 [ + + ]: 6 : if (i <= 0) break;
426 : 3 : BIO_write(p7bio,buf,i);
427 : 3 : }
428 : 3 : BIO_flush(p7bio);
429 : :
430 : : LOG_PRINT("encrypt1: dataFinal");
431 [ - + ]: 3 : if (!PKCS7_dataFinal(p7,p7bio)) GOTO_ERR("PKCS7_dataFinal");
432 : 3 : BIO_free_all(rbio);
433 : 3 : BIO_free_all(p7bio);
434 : 3 : rbio = p7bio = NULL;
435 : :
436 [ - + ]: 3 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
437 : : LOG_PRINT("encrypt1: write bio");
438 : 3 : PEM_write_bio_PKCS7(wbio,p7);
439 : 3 : BIO_flush(wbio);
440 : 3 : PKCS7_free(p7);
441 : 3 : p7 = NULL;
442 : :
443 : : LOG_PRINT("encrypt1: cutting markers");
444 : 3 : n = BIO_get_mem_data(wbio,&b64);
445 : 3 : b64 = cut_pem_markers_off(b64, n, "PKCS7");
446 : :
447 : : LOG_PRINT("encrypt1: wrapping in headers");
448 [ - + ]: 3 : if (!(b = strdup("Content-type: application/x-pkcs7-mime; name=\"smime.p7m\""
449 : : CRLF
450 : : "Content-transfer-encoding: base64" CRLF
451 : : "Content-Disposition: attachment; filename=\"smime.p7m\""
452 : 0 : CRLF CRLF))) GOTO_ERR("no memory?");
453 [ - + ]: 3 : if (!(b = concat(b, b64))) GOTO_ERR("no memory?");
454 : :
455 : 3 : BIO_free_all(wbio); /* also frees b64 */
456 : : LOG_PRINT("encrypt1: OK");
457 : :
458 : 3 : t = time(NULL);
459 : 3 : RAND_seed(&t,sizeof(t));
460 : 3 : RAND_write_file(randomfile);
461 : :
462 : 3 : return b; /* return value must be freed by caller */
463 : :
464 : 2 : err:
465 [ - + ]: 2 : if (rbio) BIO_free_all(rbio);
466 [ - + ]: 2 : if (p7bio) BIO_free_all(p7bio);
467 [ - + ]: 2 : if (wbio) BIO_free_all(wbio);
468 [ - + ]: 2 : if (p7) PKCS7_free(p7);
469 : 2 : return NULL;
470 : : }
471 : :
472 : : /* Called by: main */
473 : : char*
474 : : smime_encrypt(const char* pubkey, const char* mime_entity)
475 : 5 : {
476 : 5 : char* b = NULL;
477 : : X509* x509;
478 : :
479 : : /* Get certificate */
480 : :
481 [ + - ]: 5 : if (!(x509 = extract_certificate(pubkey))) goto err;
482 : 5 : b = encrypt1(x509, mime_entity);
483 : :
484 : 5 : err:
485 : : //if (x509) X509_free(x509);
486 : 5 : return b; /* return value must be freed by caller */
487 : : }
488 : :
489 : : /* ================= base64 encoding and decoding ================= */
490 : :
491 : : /* Called by: attach, main x2, mime_base64_entity */
492 : : int /* returns number of bytes in result. b64 is NULL terminated */
493 : : smime_base64(int encp /* true == encode */, const char* data, int len, char** out)
494 : 6 : {
495 : : BIO* b64bio;
496 : 6 : BIO* rbio = NULL;
497 : 6 : BIO* wbio = NULL;
498 : : char buf[4096];
499 : 6 : int n = -1;
500 : :
501 [ + - ]: 6 : if (out) *out = NULL;
502 [ + - - + ]: 6 : if (!data || !out) GOTO_ERR("NULL arg");
503 : :
504 : : /* create two memory buffer BIOs */
505 : :
506 [ + - ]: 6 : if (!(rbio = set_read_BIO_from_buf(data, len))) goto err;
507 [ - + ]: 6 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
508 : :
509 : : /* insert base64 filter */
510 : :
511 [ - + ]: 6 : if (!(b64bio=BIO_new(BIO_f_base64()))) GOTO_ERR("no memory?");
512 [ + + ]: 6 : if (encp)
513 : 5 : wbio=BIO_push(b64bio,wbio);
514 : : else
515 : 1 : rbio=BIO_push(b64bio,rbio);
516 : :
517 : : /* pump stuff through filter */
518 : :
519 : : for (;;) {
520 [ + + ]: 12 : if ((n=BIO_read(rbio,buf,sizeof(buf))) <= 0) break;
521 [ - + ]: 6 : if (BIO_write(wbio, buf,n) != n) GOTO_ERR("no memory? (base64 pump)");
522 : 6 : }
523 : :
524 : : /* free BIOs and return base64 encoded block */
525 : :
526 : 6 : n = get_written_BIO_data(wbio, out); /* if error (-1) will just propagate */
527 : :
528 : 6 : err:
529 [ + - ]: 6 : if (wbio) BIO_free_all(wbio); /* b64bio is freed as part of the stack */
530 [ + - ]: 6 : if (rbio) BIO_free_all(rbio);
531 : 6 : return n;
532 : : }
533 : :
534 : : /* EOF - smime-enc.c */
|