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 */
smime_init(const char * random_file,const char * randomness,int randlen)82 int smime_init(const char* random_file, const char* randomness, int randlen)
83 {
84 time_t t;
85 OpenSSL_add_all_algorithms(); /* calling this multiple times does not seem to have any negative effect. */
86 OpenSSL_add_all_ciphers(); /* Needed to avoid 10069:error:0906B072:PEM routines:PEM_get_EVP_CIPHER_INFO:unsupported encryption:pem_lib.c:481: */
87 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 t = time(NULL);
96 RAND_seed(&t,sizeof(t));
97 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 if (random_file) {
104 strncpy(randomfile, random_file, sizeof(randomfile));
105 randomfile[sizeof(randomfile)-1] = '\0';
106 }
107 if (RAND_load_file(randomfile,1024L*1024L)) {
108 RAND_seed(&t,sizeof(t));
109 strcpy(smime_error_buf, SMIME_VERSION " randomness initialized");
110 return 0;
111 }
112 strcpy(smime_error_buf, SMIME_VERSION " no randomfile");
113 RAND_seed(&t,sizeof(t));
114 RAND_write_file(randomfile); /* create random file if possible */
115
116 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 */
set_read_BIO_from_buf(const char * buf,int len)122 BIO* set_read_BIO_from_buf(const char* buf, int len)
123 {
124 BIO* rbio;
125 BUF_MEM* bm;
126 if (!buf) GOTO_ERR("NULL file buffer");
127 if (len == -1) len = strlen(buf);
128 LOG_PRINT3("set_read_BIO_from_buf %x, len %d", buf, len);
129 if (!(rbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
130 if (!(bm = BUF_MEM_new())) GOTO_ERR("no memory?");
131 if (!BUF_MEM_grow(bm, len)) GOTO_ERR("no memory?");
132 memcpy(bm->data, buf, len);
133 BIO_set_mem_buf(rbio, bm, 0 /*not used*/);
134 LOG_PRINT("ok");
135 return rbio;
136 err:
137 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 */
get_written_BIO_data(BIO * wbio,char ** data)144 int get_written_BIO_data(BIO* wbio, char** data)
145 {
146 int n;
147 char* p;
148 if (!data) GOTO_ERR("NULL arg");
149 *data = NULL;
150 BIO_flush(wbio);
151 n = BIO_get_mem_data(wbio,&p);
152 LOG_PRINT3("get_written_BIO_data: %x %d bytes", p, n);
153 if (!((*data)=(char*)OPENSSL_malloc(n+1))) GOTO_ERR("no memory?");
154 memcpy(*data, p, n);
155 (*data)[n] = '\0';
156 return n;
157 err:
158 return -1;
159 }
160
161 /* Callback for supplying the pesky password. */
162
163 /* Called by: */
password_callback(char * buf,int buf_size,int x,void * password)164 int password_callback(char* buf, int buf_size, int x /*not used*/, void* password)
165 {
166 int n;
167 if (!password) {
168 strcpy(buf, "");
169 return 0;
170 }
171 n = strlen((char*)password);
172 if (n >= buf_size) n = buf_size-1;
173 memcpy(buf, (char*)password, n);
174 buf[n] = '\0';
175 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 */
open_private_key(const char * privatekey_pem,const char * password)181 EVP_PKEY* open_private_key(const char* privatekey_pem, const char* password)
182 {
183 EVP_PKEY* pkey = NULL;
184 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 if (!(rbio = set_read_BIO_from_buf(privatekey_pem, -1))) goto err;
191 if (!(pkey=PEM_read_bio_PrivateKey(rbio,NULL, password_callback,
192 (void*)password)))
193 GOTO_ERR("01 bad password or badly formatted private key pem file (PEM_read_bio_PrivateKey)");
194 LOG_PRINT("done");
195 BIO_free(rbio);
196 #ifdef CR_PARANOIA
197 if (privatekey_pem) Free((void*)privatekey_pem);
198 #endif
199 return pkey;
200
201 err:
202 #ifdef CR_PARANOIA
203 if (privatekey_pem) Free((void*)privatekey_pem);
204 #endif
205 if (pkey) EVP_PKEY_free(pkey);
206 if (rbio) BIO_free(rbio);
207 LOG_PRINT("error");
208 return NULL;
209 }
210
211 /* Called by: smime_keygen, smime_pkcs12_to_pem */
write_private_key(EVP_PKEY * pkey,const char * passwd,char ** priv_pem_OUT)212 int write_private_key(EVP_PKEY* pkey, const char* passwd, char** priv_pem_OUT)
213 {
214 int len = -1;
215 BIO* wbio=NULL;
216 if (!passwd || !priv_pem_OUT || !pkey) GOTO_ERR("NULL arg(s)");
217 *priv_pem_OUT = NULL;
218 if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
219 LOG_PRINT("write_private_key");
220 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 GOTO_ERR("PEM_write_bio_PrivateKey (bad passwd, no memory?)");
224 len = get_written_BIO_data(wbio, priv_pem_OUT);
225 err:
226 if (wbio) BIO_free_all(wbio);
227 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 */
extract_certificate(const char * cert_pem)233 X509* extract_certificate(const char* cert_pem)
234 {
235 X509* x509 = NULL;
236 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 if (!(rbio = set_read_BIO_from_buf(cert_pem, -1))) goto err;
243 if (!(x509=PEM_read_bio_X509(rbio,NULL,NULL,NULL)))
244 GOTO_ERR("10 badly formatted X509 certificate pem file (PEM_read_bio_X509)");
245 LOG_PRINT("done");
246 err:
247 #ifdef CR_PARANOIA
248 if (cert_pem) Free((void*)cert_pem);
249 #endif
250 if (rbio) BIO_free(rbio);
251 return x509;
252 }
253
254 /* Called by: smime_ca, smime_keygen, smime_pkcs12_to_pem */
write_certificate(X509 * x509,char ** x509_cert_pem_OUT)255 int write_certificate(X509* x509, char** x509_cert_pem_OUT)
256 {
257 BIO* wbio = NULL;
258 int len = -1;
259 if (!x509 || !x509_cert_pem_OUT) GOTO_ERR("NULL arg");
260 *x509_cert_pem_OUT = NULL;
261 if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
262 LOG_PRINT("write_certificate");
263 PEM_write_bio_X509(wbio, x509);
264 len = get_written_BIO_data(wbio, x509_cert_pem_OUT);
265 err:
266 if (wbio) BIO_free_all(wbio);
267 return len;
268 }
269
270 /* Called by: smime_ca, smime_get_req_attr, smime_get_req_modulus, smime_get_req_name */
extract_request(const char * req_pem)271 X509_REQ* extract_request(const char* req_pem)
272 {
273 X509_REQ* x509_req = NULL;
274 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 if (!(rbio = set_read_BIO_from_buf(req_pem, -1))) goto err;
281 if (!(x509_req = PEM_read_bio_X509_REQ(rbio,NULL,NULL,NULL)))
282 GOTO_ERR("04 badly formatted certificate request pem file (PEM_read_bio_x509_REQ)");
283 LOG_PRINT("done");
284 err:
285 #ifdef CR_PARANOIA
286 if (req_pem) Free((void*)req_pem);
287 #endif
288 if (rbio) BIO_free(rbio);
289 return x509_req;
290 }
291
292 /* Called by: smime_keygen */
write_request(X509_REQ * x509_req,char ** x509_req_pem_OUT)293 int write_request(X509_REQ* x509_req, char** x509_req_pem_OUT)
294 {
295 BIO* wbio = NULL;
296 int len = -1;
297 if (!x509_req || !x509_req_pem_OUT) GOTO_ERR("NULL arg");
298 *x509_req_pem_OUT = NULL;
299 if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
300 LOG_PRINT("write_request");
301 PEM_write_bio_X509_REQ(wbio, x509_req);
302 len = get_written_BIO_data(wbio, x509_req_pem_OUT);
303 err:
304 if (wbio) BIO_free_all(wbio);
305 return len;
306 }
307
308 /* Called by: smime_pkcs12_to_pem */
load_PKCS12(const char * pkcs12,int pkcs12_len)309 PKCS12* load_PKCS12(const char* pkcs12, int pkcs12_len)
310 {
311 BIO* rbio = NULL;
312 PKCS12* p12 = NULL;
313 if (!(rbio = set_read_BIO_from_buf((char*)pkcs12, pkcs12_len))) goto err;
314 if (!(p12 = d2i_PKCS12_bio(rbio, NULL)))
315 GOTO_ERR("02 bad PKCS12 file format (d2i_PKCS12_bio)");
316 err:
317 if (rbio) BIO_free(rbio);
318 return p12;
319
320 }
321
322 /* Called by: */
save_PKCS12(PKCS12 * p12,char ** pkcs12_out)323 int save_PKCS12(PKCS12* p12, char** pkcs12_out)
324 {
325 BIO* wbio = NULL;
326 int len = -1;
327 if (!p12 || !pkcs12_out) GOTO_ERR("NULL arg(s)");
328 *pkcs12_out = NULL;
329 if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
330 i2d_PKCS12_bio(wbio, p12); /* der encode it */
331 len = get_written_BIO_data(wbio, pkcs12_out);
332 err:
333 if (wbio) BIO_free_all(wbio);
334 return len;
335 }
336
337 /* Called by: get_cert_info */
smime_dotted_hex(const char * data,int len)338 char* smime_dotted_hex(const char* data, int len)
339 {
340 int j;
341 char* p;
342 char* buf;
343 if (!data || !len) GOTO_ERR("NULL or bad arg");
344 if (!(buf = p = (char*)OPENSSL_malloc(len*3+1))) GOTO_ERR("no memory?");
345 for (j=0; j<len; j++) {
346 sprintf(p,"%02X:",(unsigned char)data[j]);
347 p+=3;
348 }
349 p[-1] = '\0'; /* change last : to \0 */
350 return buf;
351 err:
352 return NULL;
353 }
354
355 /* Called by: smime_md5 */
smime_hex(const char * data,int len)356 char* smime_hex(const char* data, int len)
357 {
358 int j;
359 char* p;
360 char* buf;
361 if (!data || !len) GOTO_ERR("NULL or bad arg");
362 if (!(buf = p = (char*)OPENSSL_malloc(len*2+1))) GOTO_ERR("no memory?");
363 for (j=0; j<len; j++) {
364 sprintf(p,"%02X",(unsigned char)data[j]);
365 p+=2;
366 }
367 return buf;
368 err:
369 return NULL;
370 }
371
372 /* Called by: main x28 */
smime_get_errors()373 char* smime_get_errors()
374 {
375 BIO* wbio;
376 char* p;
377 if (!(wbio = BIO_new(BIO_s_mem()))) return smime_error_buf;
378 BIO_puts(wbio, smime_error_buf);
379 ERR_load_crypto_strings();
380 ERR_print_errors(wbio);
381 BIO_get_mem_data(wbio,&p);
382 return p; /* just leak the wbio */
383 }
384
385 /* EOF - smimeutil.c */
386