Branch data Line data Source code
1 : : /* smimeutil.c - Utility functions for performing S/MIME signatures
2 : : * and encryption.
3 : : *
4 : : * Copyright (c) 1999,2004 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, divided to smime-enc.c, smime-vfy.c, smimemime.c and smimeutil.c
13 : : * 9.10.1999, reviewed for double frees --Sampo
14 : : * 18.10.1999, added CR_PARANOIA ifdefs. THis define is useful on platforms
15 : : * like Mac that use CR as line termination. OpenSSL PEM
16 : : * parsing routines do not grog CR so we need to preconvert
17 : : * CR to CRLF to guarantee easy operation. --Sampo
18 : : * 10.10.2004, fixed long term annoyance where empty password did still encypt. Now
19 : : * empty password causes no encryption what so ever. --Sampo
20 : : *
21 : : * This module has been developed to support a Lingo XTRA that is supposed
22 : : * to provide crypto functionality. It may, however, be useful for other
23 : : * purposes as well.
24 : : *
25 : : * This is a very simple S/MIME library. For example the multipart
26 : : * boundary separators are hard coded and no effort is made to verify
27 : : * that mime entities are in their canonical form before signing (the
28 : : * caller should make sure they are, canonical form means using CRLF
29 : : * as line termination, among other things). Also the multipart functionality
30 : : * only understands up to 3 attachments. For many tasks this is enough,
31 : : * but if its not, feel free to write more generic utilities.
32 : : *
33 : : * Memory management: most routines malloc the results. Freeing them is
34 : : * application's responsibility. I use libc malloc, but if in doubt
35 : : * it might be safer to just leak the memory (i.e. don't ever free it).
36 : : * This library works entirely in memory, so maximum memory consumption
37 : : * might be more than twice the total size of all files to be encrypted.
38 : : */
39 : :
40 : : #include "platform.h"
41 : :
42 : : #include <stdio.h>
43 : : #include <string.h>
44 : : #include <time.h>
45 : :
46 : : #if defined(macintosh) || defined(__MWERKS__)
47 : : #include "macglue.h"
48 : : #endif
49 : :
50 : : #include "logprint.h"
51 : :
52 : : #include <openssl/crypto.h>
53 : : #include <openssl/buffer.h>
54 : : #include <openssl/bio.h>
55 : : #include <openssl/x509.h>
56 : : #include <openssl/pem.h>
57 : : #include <openssl/err.h>
58 : : #include <openssl/rand.h>
59 : :
60 : : #define SMIME_INTERNALS /* we want also our internal helper functions */
61 : : #include "smimeutil.h"
62 : :
63 : : /* ======================= U T I L I T I E S ======================= */
64 : :
65 : : char smime_error_buf[256]; /* stores smime library-level error */
66 : : char randomfile[256] = "random.txt";
67 : :
68 : : #ifdef DEBUGLOG
69 : : FILE* Log = NULL;
70 : : #endif
71 : :
72 : : /* initializes EVP algorithm tables and injects randomness into
73 : : * system. If random file existed it is read as well and 0 (for
74 : : * success) is returned. If random file did not exist, it will be
75 : : * created (if permissions allow) and -1 is returned. On that occasion
76 : : * it is advisable to arrange some real randomness (such as movements of
77 : : * mouse, times between key presses, /dev/random, etc.) and call
78 : : * init again.
79 : : */
80 : :
81 : : /* Called by: main */
82 : : int smime_init(const char* random_file, const char* randomness, int randlen)
83 : 35 : {
84 : : time_t t;
85 : 35 : OpenSSL_add_all_algorithms(); /* calling this multiple times does not seem to have any negative effect. */
86 : 35 : OpenSSL_add_all_ciphers(); /* Needed to avoid 10069:error:0906B072:PEM routines:PEM_get_EVP_CIPHER_INFO:unsupported encryption:pem_lib.c:481: */
87 : 35 : OpenSSL_add_all_digests();
88 : :
89 : : #ifdef DEBUGLOG
90 : : Log = fopen("smimeutil.log", "w");
91 : : LOG("Log opened");
92 : : #endif
93 : :
94 : : LOG_PRINT("smime_init");
95 : 35 : t = time(NULL);
96 : 35 : RAND_seed(&t,sizeof(t));
97 [ + - ]: 35 : if (randomness) RAND_seed(randomness, randlen);
98 : :
99 : : #ifdef WINDOWS
100 : : LOG_PRINT("RAND_screen...");
101 : : RAND_screen(); /* Loading video display memory into random state */
102 : : #endif
103 [ + - ]: 35 : if (random_file) {
104 : 35 : strncpy(randomfile, random_file, sizeof(randomfile));
105 : 35 : randomfile[sizeof(randomfile)-1] = '\0';
106 : : }
107 [ + - ]: 35 : if (RAND_load_file(randomfile,1024L*1024L)) {
108 : 35 : RAND_seed(&t,sizeof(t));
109 : 35 : strcpy(smime_error_buf, SMIME_VERSION " randomness initialized");
110 : 35 : return 0;
111 : : }
112 : 0 : strcpy(smime_error_buf, SMIME_VERSION " no randomfile");
113 : 0 : RAND_seed(&t,sizeof(t));
114 : 0 : RAND_write_file(randomfile); /* create random file if possible */
115 : :
116 : 0 : return -1;
117 : : }
118 : :
119 : : /* Initialize a memory BIO to have certain content */
120 : :
121 : : /* Called by: encrypt1, extract_certificate, extract_request, get_pkcs7_from_pem, load_PKCS12, open_private_key, smime_base64, smime_pkcs12_to_pem_generic, smime_sign_engine, smime_verify_signature */
122 : : BIO* set_read_BIO_from_buf(const char* buf, int len)
123 : 33 : {
124 : : BIO* rbio;
125 : : BUF_MEM* bm;
126 [ - + ]: 33 : if (!buf) GOTO_ERR("NULL file buffer");
127 [ + + ]: 33 : if (len == -1) len = strlen(buf);
128 : : LOG_PRINT3("set_read_BIO_from_buf %x, len %d", buf, len);
129 [ - + ]: 33 : if (!(rbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
130 [ - + ]: 33 : if (!(bm = BUF_MEM_new())) GOTO_ERR("no memory?");
131 [ + + ]: 33 : if (!BUF_MEM_grow(bm, len)) GOTO_ERR("no memory?");
132 : 29 : memcpy(bm->data, buf, len);
133 : 29 : BIO_set_mem_buf(rbio, bm, 0 /*not used*/);
134 : : LOG_PRINT("ok");
135 : 29 : return rbio;
136 : 4 : err:
137 : 4 : return NULL;
138 : : }
139 : :
140 : : /* Flushes a write BIO and returns the accumulated data as one malloc'd blob
141 : : * returns length or -1 if error */
142 : :
143 : : /* Called by: decrypt, get_cert_info, get_req_modulus, save_PKCS12, smime_base64, smime_pkcs12_to_pem_generic x2, smime_verify_signature, write_certificate, write_private_key, write_request */
144 : : int get_written_BIO_data(BIO* wbio, char** data)
145 : 12 : {
146 : : int n;
147 : : char* p;
148 [ - + ]: 12 : if (!data) GOTO_ERR("NULL arg");
149 : 12 : *data = NULL;
150 : 12 : BIO_flush(wbio);
151 : 12 : n = BIO_get_mem_data(wbio,&p);
152 : : LOG_PRINT3("get_written_BIO_data: %x %d bytes", p, n);
153 [ - + ]: 12 : if (!((*data)=(char*)OPENSSL_malloc(n+1))) GOTO_ERR("no memory?");
154 : 12 : memcpy(*data, p, n);
155 : 12 : (*data)[n] = '\0';
156 : 12 : return n;
157 : 0 : err:
158 : 0 : return -1;
159 : : }
160 : :
161 : : /* Callback for supplying the pesky password. */
162 : :
163 : : /* Called by: */
164 : : int password_callback(char* buf, int buf_size, int x /*not used*/, void* password)
165 : 0 : {
166 : : int n;
167 [ # # ]: 0 : if (!password) {
168 : 0 : strcpy(buf, "");
169 : 0 : return 0;
170 : : }
171 : 0 : n = strlen((char*)password);
172 [ # # ]: 0 : if (n >= buf_size) n = buf_size-1;
173 : 0 : memcpy(buf, (char*)password, n);
174 : 0 : buf[n] = '\0';
175 : 0 : return n;
176 : : }
177 : :
178 : : /* Get private key from buffer full of encrypted stuff */
179 : :
180 : : /* Called by: smime_ca, smime_clear_sign, smime_decrypt, smime_sign */
181 : : EVP_PKEY* open_private_key(const char* privatekey_pem, const char* password)
182 : 9 : {
183 : 9 : EVP_PKEY* pkey = NULL;
184 : 9 : BIO* rbio = NULL;
185 : : LOG_PRINT3("open_private_key: %x %x", privatekey_pem, password);
186 : : #ifdef CR_PARANOIA
187 : : if (!(privatekey_pem = mime_canon(privatekey_pem))) GOTO_ERR("no memory?");
188 : : LOG_PRINT("CR paranoia enabled");
189 : : #endif
190 [ + - ]: 9 : if (!(rbio = set_read_BIO_from_buf(privatekey_pem, -1))) goto err;
191 [ + - ]: 9 : if (!(pkey=PEM_read_bio_PrivateKey(rbio,NULL, password_callback,
192 : : (void*)password)))
193 : 9 : GOTO_ERR("01 bad password or badly formatted private key pem file (PEM_read_bio_PrivateKey)");
194 : : LOG_PRINT("done");
195 : 0 : BIO_free(rbio);
196 : : #ifdef CR_PARANOIA
197 : : if (privatekey_pem) Free((void*)privatekey_pem);
198 : : #endif
199 : 0 : return pkey;
200 : :
201 : 9 : err:
202 : : #ifdef CR_PARANOIA
203 : : if (privatekey_pem) Free((void*)privatekey_pem);
204 : : #endif
205 [ - + ]: 9 : if (pkey) EVP_PKEY_free(pkey);
206 [ + - ]: 9 : if (rbio) BIO_free(rbio);
207 : : LOG_PRINT("error");
208 : 9 : return NULL;
209 : : }
210 : :
211 : : /* Called by: smime_keygen, smime_pkcs12_to_pem */
212 : : int write_private_key(EVP_PKEY* pkey, const char* passwd, char** priv_pem_OUT)
213 : 2 : {
214 : 2 : int len = -1;
215 : 2 : BIO* wbio=NULL;
216 [ + - + - : 2 : if (!passwd || !priv_pem_OUT || !pkey) GOTO_ERR("NULL arg(s)");
- + ]
217 : 2 : *priv_pem_OUT = NULL;
218 [ - + ]: 2 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
219 : : LOG_PRINT("write_private_key");
220 [ + - + - : 2 : if (!PEM_write_bio_PrivateKey(wbio, pkey, *passwd ? EVP_des_ede3_cbc() : 0,
- + ]
221 : : *passwd ? (unsigned char*)passwd:0, strlen(passwd),
222 : : NULL,NULL))
223 : 0 : GOTO_ERR("PEM_write_bio_PrivateKey (bad passwd, no memory?)");
224 : 2 : len = get_written_BIO_data(wbio, priv_pem_OUT);
225 : 2 : err:
226 [ + - ]: 2 : if (wbio) BIO_free_all(wbio);
227 : 2 : return len;
228 : : }
229 : :
230 : : /* Extract a certificate from pem encoding */
231 : :
232 : : /* Called by: smime_ca, smime_clear_sign, smime_decrypt, smime_encrypt, smime_get_cert_info, smime_get_cert_names, smime_sign, smime_verify_cert x2, smime_verify_signature */
233 : : X509* extract_certificate(const char* cert_pem)
234 : 8 : {
235 : 8 : X509* x509 = NULL;
236 : 8 : BIO* rbio = NULL;
237 : : LOG_PRINT2("extract_certificate %x", cert_pem);
238 : : #ifdef CR_PARANOIA
239 : : if (!(cert_pem = mime_canon(cert_pem))) GOTO_ERR("no memory?");
240 : : LOG_PRINT("CR paranoia enabled");
241 : : #endif
242 [ + + ]: 8 : if (!(rbio = set_read_BIO_from_buf(cert_pem, -1))) goto err;
243 [ + + ]: 7 : if (!(x509=PEM_read_bio_X509(rbio,NULL,NULL,NULL)))
244 : 1 : GOTO_ERR("10 badly formatted X509 certificate pem file (PEM_read_bio_X509)");
245 : : LOG_PRINT("done");
246 : 8 : err:
247 : : #ifdef CR_PARANOIA
248 : : if (cert_pem) Free((void*)cert_pem);
249 : : #endif
250 [ + + ]: 8 : if (rbio) BIO_free(rbio);
251 : 8 : return x509;
252 : : }
253 : :
254 : : /* Called by: smime_ca, smime_keygen, smime_pkcs12_to_pem */
255 : : int write_certificate(X509* x509, char** x509_cert_pem_OUT)
256 : 2 : {
257 : 2 : BIO* wbio = NULL;
258 : 2 : int len = -1;
259 [ + - - + ]: 2 : if (!x509 || !x509_cert_pem_OUT) GOTO_ERR("NULL arg");
260 : 2 : *x509_cert_pem_OUT = NULL;
261 [ - + ]: 2 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
262 : : LOG_PRINT("write_certificate");
263 : 2 : PEM_write_bio_X509(wbio, x509);
264 : 2 : len = get_written_BIO_data(wbio, x509_cert_pem_OUT);
265 : 2 : err:
266 [ + - ]: 2 : if (wbio) BIO_free_all(wbio);
267 : 2 : return len;
268 : : }
269 : :
270 : : /* Called by: smime_ca, smime_get_req_attr, smime_get_req_modulus, smime_get_req_name */
271 : : X509_REQ* extract_request(const char* req_pem)
272 : 1 : {
273 : 1 : X509_REQ* x509_req = NULL;
274 : 1 : BIO* rbio = NULL;
275 : : LOG_PRINT2("extract_request %x", req_pem);
276 : : #ifdef CR_PARANOIA
277 : : if (!(req_pem = mime_canon(req_pem))) GOTO_ERR("no memory?");
278 : : LOG_PRINT("CR paranoia enabled");
279 : : #endif
280 [ + - ]: 1 : if (!(rbio = set_read_BIO_from_buf(req_pem, -1))) goto err;
281 [ + - ]: 1 : if (!(x509_req = PEM_read_bio_X509_REQ(rbio,NULL,NULL,NULL)))
282 : 1 : GOTO_ERR("04 badly formatted certificate request pem file (PEM_read_bio_x509_REQ)");
283 : : LOG_PRINT("done");
284 : 1 : err:
285 : : #ifdef CR_PARANOIA
286 : : if (req_pem) Free((void*)req_pem);
287 : : #endif
288 [ + - ]: 1 : if (rbio) BIO_free(rbio);
289 : 1 : return x509_req;
290 : : }
291 : :
292 : : /* Called by: smime_keygen */
293 : : int write_request(X509_REQ* x509_req, char** x509_req_pem_OUT)
294 : 2 : {
295 : 2 : BIO* wbio = NULL;
296 : 2 : int len = -1;
297 [ + - - + ]: 2 : if (!x509_req || !x509_req_pem_OUT) GOTO_ERR("NULL arg");
298 : 2 : *x509_req_pem_OUT = NULL;
299 [ - + ]: 2 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
300 : : LOG_PRINT("write_request");
301 : 2 : PEM_write_bio_X509_REQ(wbio, x509_req);
302 : 2 : len = get_written_BIO_data(wbio, x509_req_pem_OUT);
303 : 2 : err:
304 [ + - ]: 2 : if (wbio) BIO_free_all(wbio);
305 : 2 : return len;
306 : : }
307 : :
308 : : /* Called by: smime_pkcs12_to_pem */
309 : : PKCS12* load_PKCS12(const char* pkcs12, int pkcs12_len)
310 : 1 : {
311 : 1 : BIO* rbio = NULL;
312 : 1 : PKCS12* p12 = NULL;
313 [ - + ]: 1 : if (!(rbio = set_read_BIO_from_buf((char*)pkcs12, pkcs12_len))) goto err;
314 [ # # ]: 0 : if (!(p12 = d2i_PKCS12_bio(rbio, NULL)))
315 : 0 : GOTO_ERR("02 bad PKCS12 file format (d2i_PKCS12_bio)");
316 : 1 : err:
317 [ - + ]: 1 : if (rbio) BIO_free(rbio);
318 : 1 : return p12;
319 : :
320 : : }
321 : :
322 : : /* Called by: */
323 : : int save_PKCS12(PKCS12* p12, char** pkcs12_out)
324 : 0 : {
325 : 0 : BIO* wbio = NULL;
326 : 0 : int len = -1;
327 [ # # # # ]: 0 : if (!p12 || !pkcs12_out) GOTO_ERR("NULL arg(s)");
328 : 0 : *pkcs12_out = NULL;
329 [ # # ]: 0 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
330 : 0 : i2d_PKCS12_bio(wbio, p12); /* der encode it */
331 : 0 : len = get_written_BIO_data(wbio, pkcs12_out);
332 : 0 : err:
333 [ # # ]: 0 : if (wbio) BIO_free_all(wbio);
334 : 0 : return len;
335 : : }
336 : :
337 : : /* Called by: get_cert_info */
338 : : char* smime_dotted_hex(const char* data, int len)
339 : 0 : {
340 : : int j;
341 : : char* p;
342 : : char* buf;
343 [ # # # # ]: 0 : if (!data || !len) GOTO_ERR("NULL or bad arg");
344 [ # # ]: 0 : if (!(buf = p = (char*)OPENSSL_malloc(len*3+1))) GOTO_ERR("no memory?");
345 [ # # ]: 0 : for (j=0; j<len; j++) {
346 : 0 : sprintf(p,"%02X:",(unsigned char)data[j]);
347 : 0 : p+=3;
348 : : }
349 : 0 : p[-1] = '\0'; /* change last : to \0 */
350 : 0 : return buf;
351 : 0 : err:
352 : 0 : return NULL;
353 : : }
354 : :
355 : : /* Called by: smime_md5 */
356 : : char* smime_hex(const char* data, int len)
357 : 0 : {
358 : : int j;
359 : : char* p;
360 : : char* buf;
361 [ # # # # ]: 0 : if (!data || !len) GOTO_ERR("NULL or bad arg");
362 [ # # ]: 0 : if (!(buf = p = (char*)OPENSSL_malloc(len*2+1))) GOTO_ERR("no memory?");
363 [ # # ]: 0 : for (j=0; j<len; j++) {
364 : 0 : sprintf(p,"%02X",(unsigned char)data[j]);
365 : 0 : p+=2;
366 : : }
367 : 0 : return buf;
368 : 0 : err:
369 : 0 : return NULL;
370 : : }
371 : :
372 : : /* Called by: main x28 */
373 : : char* smime_get_errors()
374 : 18 : {
375 : : BIO* wbio;
376 : : char* p;
377 [ - + ]: 18 : if (!(wbio = BIO_new(BIO_s_mem()))) return smime_error_buf;
378 : 18 : BIO_puts(wbio, smime_error_buf);
379 : 18 : ERR_load_crypto_strings();
380 : 18 : ERR_print_errors(wbio);
381 : 18 : BIO_get_mem_data(wbio,&p);
382 : 18 : return p; /* just leak the wbio */
383 : : }
384 : :
385 : : /* EOF - smimeutil.c */
|