1 /* smime-vfy.c - Utility functions for performing S/MIME signature
2 * verification and decryption.
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, fixed double free in decryption --Sampo
14 * 14.11.1999, added verification of detached sigs, i.e. clear sigs --Sampo
15 *
16 * This module has adopted ideas and control flow from
17 * openssl-0.9.4/crypto/pkcs7/sign.c
18 * openssl-0.9.4/crypto/pkcs7/verify.c
19 * openssl-0.9.4/crypto/pkcs7/enc.c
20 * openssl-0.9.4/crypto/pkcs7/dec.c
21 * which are Copyright (c) 1995-1998 Eric Young (eay@cryptsoft.com),
22 * All rights reserved. See file LICENSE for conditions.
23 *
24 * This module has been developed to support a Lingo XTRA that is supposed
25 * to provide crypto functionality. It may, however, be useful for other
26 * purposes as well.
27 *
28 * This is a very simple S/MIME library. For example the multipart
29 * boundary separators are hard coded and no effort is made to verify
30 * that mime entities are in their canonical form before signing (the
31 * caller should make sure they are, canonical form means using CRLF
32 * as line termination, among other things). Also the multipart functionality
33 * only understands up to 3 attachments. For many tasks this is enough,
34 * but if its not, feel free to write more generic utilities.
35 *
36 * Memory management: most routines malloc the results. Freeing them is
37 * application's responsibility. I use libc malloc, but if in doubt
38 * it might be safer to just leak the memory (i.e. don't ever free it).
39 * This library works entirely in memory, so maximum memory consumption
40 * might be more than twice the total size of all files to be encrypted.
41 */
42
43 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
44 * All rights reserved.
45 *
46 * This package is an SSL implementation written
47 * by Eric Young (eay@cryptsoft.com).
48 * The implementation was written so as to conform with Netscapes SSL.
49 *
50 * This library is free for commercial and non-commercial use as long as
51 * the following conditions are aheared to. The following conditions
52 * apply to all code found in this distribution, be it the RC4, RSA,
53 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
54 * included with this distribution is covered by the same copyright terms
55 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
56 *
57 * Copyright remains Eric Young's, and as such any Copyright notices in
58 * the code are not to be removed.
59 * If this package is used in a product, Eric Young should be given attribution
60 * as the author of the parts of the library used.
61 * This can be in the form of a textual message at program startup or
62 * in documentation (online or textual) provided with the package.
63 *
64 * Redistribution and use in source and binary forms, with or without
65 * modification, are permitted provided that the following conditions
66 * are met:
67 * 1. Redistributions of source code must retain the copyright
68 * notice, this list of conditions and the following disclaimer.
69 * 2. Redistributions in binary form must reproduce the above copyright
70 * notice, this list of conditions and the following disclaimer in the
71 * documentation and/or other materials provided with the distribution.
72 * 3. All advertising materials mentioning features or use of this software
73 * must display the following acknowledgement:
74 * "This product includes cryptographic software written by
75 * Eric Young (eay@cryptsoft.com)"
76 * The word 'cryptographic' can be left out if the rouines from the library
77 * being used are not cryptographic related :-).
78 * 4. If you include any Windows specific code (or a derivative thereof) from
79 * the apps directory (application code) you must include an acknowledgement:
80 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
81 *
82 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
83 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
84 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
85 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
86 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
87 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
88 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
89 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
90 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
91 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
92 * SUCH DAMAGE.
93 *
94 * The licence and distribution terms for any publically available version or
95 * derivative of this code cannot be changed. i.e. this code cannot simply be
96 * copied and put under another distribution licence
97 * [including the GNU Public Licence.]
98 */
99
100 #include "platform.h"
101
102 #include <stdlib.h>
103 #include <string.h>
104 #include <time.h>
105
106 #if defined(macintosh) || defined(__INTEL__)
107 #include "macglue.h"
108 #endif
109
110 #include "logprint.h"
111
112 #include <openssl/crypto.h>
113 #include <openssl/buffer.h>
114 #include <openssl/stack.h>
115 #include <openssl/bio.h>
116 #include <openssl/x509.h>
117 #include <openssl/pem.h>
118 #include <openssl/err.h>
119
120 #define SMIME_INTERNALS /* we want also our internal helper functions */
121 #include "smimeutil.h"
122
123 /* ============= S I G N A T U R E V E R I F I C A T I O N ============== */
124 /* ==================== A N D D E C R Y P T I O N ======================= */
125
126 /* Called by: decrypt, smime_get_signer_info, smime_verify_signature */
127 static PKCS7*
get_pkcs7_from_pem(const char * enc_entity)128 get_pkcs7_from_pem(const char* enc_entity)
129 {
130 const char* p;
131 char* wrapped_enc_entity = NULL;
132 BIO* rbio = NULL;
133 PKCS7* p7 = NULL;
134
135 /* Check if encrypted entity is composed of raw data or if it has some
136 * headers. In the latter case, just skip the headers. Headers are
137 * separated from data by an empty line (hence sequence CRLF CRLF).*/
138
139 if ((p = strstr(enc_entity, CRLF CRLF))) {
140 enc_entity = p+4;
141 } else if ((p = strstr(enc_entity, LF LF))) {
142 enc_entity = p+2;
143 } else if ((p = strstr(enc_entity, CR CR))) {
144 enc_entity = p+2;
145 }
146
147 /* Make sure the pem markers are there */
148
149 LOG_PRINT("get_pkcs7_from_pem: wrapping in pem markers");
150
151 if (!(wrapped_enc_entity = wrap_in_pem_markers(enc_entity, "PKCS7")))
152 GOTO_ERR("no memory?");
153 LOG_PRINT("get_pkcs7_from_pem: wrapped.");
154
155 /* Set up BIO so encrypted/signed data can be read from pem file */
156
157 if (!(rbio = set_read_BIO_from_buf(wrapped_enc_entity, -1))) goto err;
158
159 LOG_PRINT("get_pkcs7_from_pem: ready to read PKCS7 bio...");
160
161 /* Load the PKCS7 object from a pem file to internal representation.
162 * this reads all of the data file. */
163
164 if (!(p7=PEM_read_bio_PKCS7(rbio,NULL/*&x*/,NULL/*callback*/,NULL/*arg*/)))
165 GOTO_ERR("11 corrupt PEM PKCS7 file? (PEM_read_bio_PKCS7)");
166
167 LOG_PRINT("get_pkcs7_from_pem: bio read");
168
169 BIO_free_all(rbio);
170 OPENSSL_free(wrapped_enc_entity);
171 return p7;
172 err:
173 if (rbio) BIO_free_all(rbio);
174 if (wrapped_enc_entity) OPENSSL_free(wrapped_enc_entity);
175 return NULL;
176 }
177
178 /* Typically receiver has to know in what order the signature and encryption
179 * were applied (usually encryption is outermost) and then call these
180 * functions in right order, e.g:
181 */
182
183 /* Called by: smime_decrypt */
184 int /* return size of data, -1 on failure */
decrypt(X509 * x509,EVP_PKEY * pkey,const char * enc_entity,char ** data_out)185 decrypt(X509* x509, EVP_PKEY* pkey, const char* enc_entity, char** data_out)
186 {
187 char buf[4096];
188 int i,n;
189 BIO* wbio = NULL;
190 BIO* p7bio = NULL;
191 PKCS7 *p7 = NULL;
192
193 if (data_out) *data_out = NULL;
194 if (!x509 || !pkey || !enc_entity || !data_out) GOTO_ERR("NULL arg(s)");
195 LOG_PRINT("decrypt: get_pkcs7_from_pem");
196 if (!(p7 = get_pkcs7_from_pem(enc_entity))) goto err;
197
198 /* Decrypt the symmetric key with private key and obtain symmetric
199 * cipher stream (BIO). The cert is needed here to look up one of
200 * possibly multiple recipient infos present in PKCS7 object. Issuer
201 * and serial number must match (these two fields form unique ID for
202 * cert). Actual public key part of the X509 cert is not used for
203 * anything here. */
204
205 LOG_PRINT("decrypt: dataDecode");
206 if (!(p7bio=PKCS7_dataDecode(p7,pkey,NULL/*detached*/,x509)))
207 GOTO_ERR("12 no recipient matches cert or private key could not decrypt, i.e. wrong key (PKCS7_dataDecode)");
208 LOG_PRINT("decrypt: ready to pump");
209
210 /* Pump data from p7bio to decrypt symmetric cipher */
211
212 if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
213
214 for (;;) {
215 if ((i=BIO_read(p7bio,buf,sizeof(buf))) <= 0) break;
216 BIO_write(wbio,buf,i);
217 }
218 BIO_flush(wbio);
219 BIO_free_all(p7bio);
220 p7bio = NULL;
221 PKCS7_free(p7);
222 p7 = NULL;
223
224 LOG_PRINT("decrypt: pump done");
225
226 /* Return data (this should now be easier because we just freed
227 * some memory) */
228
229 n = get_written_BIO_data(wbio, data_out);
230 BIO_free_all(wbio);
231 return n;
232
233 err:
234 if (p7) PKCS7_free(p7);
235 if (wbio) BIO_free_all(wbio);
236 if (p7bio) BIO_free_all(p7bio);
237 return -1;
238 }
239
240 /* Called by: main */
241 int /* return size of data, -1 on failure */
smime_decrypt(const char * privkey,const char * passwd,const char * enc_entity,char ** data_out)242 smime_decrypt(const char* privkey,
243 const char* passwd,
244 const char* enc_entity,
245 char** data_out)
246 {
247 int n = -1;
248 EVP_PKEY *pkey = NULL;
249 X509 *x509 = NULL;
250
251 if (data_out) *data_out = NULL;
252 if (!privkey || !passwd || !enc_entity || !data_out) GOTO_ERR("NULL arg(s)");
253 if (!(pkey = open_private_key(privkey, passwd))) goto err;
254 if (!(x509 = extract_certificate(privkey))) goto err;
255 n = decrypt(x509, pkey, enc_entity, data_out);
256
257 err:
258 if (pkey) EVP_PKEY_free(pkey);
259 if (x509) X509_free(x509);
260 return n;
261 }
262
263 /* ------------------------------------------------ */
264
265 #if 0
266 /* copied from verify.c */
267 /* should be X509* but we can just have them as char*. (??? --Sampo) */
268 /* Called by: */
269 static int
270 verify_callback(int ok, X509_STORE_CTX *ctx) {
271 char buf[256];
272 X509 *err_cert;
273 int err,depth;
274
275 err_cert=X509_STORE_CTX_get_current_cert(ctx);
276 err= X509_STORE_CTX_get_error(ctx);
277 depth= X509_STORE_CTX_get_error_depth(ctx);
278
279 X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buf));
280 fprintf(stderr,"depth=%d %s\n",depth,buf);
281 if (!ok) {
282 fprintf(stderr,"verify error:num=%d:%s\n",err,
283 X509_verify_cert_error_string(err));
284 if (depth < 6) {
285 ok=1;
286 X509_STORE_CTX_set_error(ctx,X509_V_OK);
287 } else {
288 ok=0;
289 X509_STORE_CTX_set_error(ctx,X509_V_ERR_CERT_CHAIN_TOO_LONG);
290 }
291 }
292 switch (ctx->error) {
293 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
294 X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,sizeof(buf));
295 fprintf(stderr,"issuer= %s\n",buf);
296 break;
297 #if 1
298 case X509_V_ERR_CERT_NOT_YET_VALID:
299 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
300 fprintf(stderr,"notBefore=");
301 /*ASN1_UTCTIME_print(bio_err,X509_get_notBefore(ctx->current_cert));
302 BIO_printf(bio_err,"\n");*/
303 break;
304 case X509_V_ERR_CERT_HAS_EXPIRED:
305 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
306 fprintf(stderr,"notAfter=");
307 /*ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ctx->current_cert));
308 BIO_printf(bio_err,"\n"); */
309 break;
310 #endif
311 }
312 fprintf(stderr,"verify return:%d\n",ok);
313 return(ok);
314 }
315
316 static int signed_seq2string_nid= -1;
317 /* For this case, I will malloc the return strings */
318 /* Called by: smime_verify_signature */
319 static int
320 get_signed_seq2string(PKCS7_SIGNER_INFO *si, char **str1, char **str2) {
321 #if 0
322 ASN1_TYPE *so;
323 if (signed_seq2string_nid == -1)
324 signed_seq2string_nid=
325 OBJ_create("1.9.9999","OID_example","Our example OID");
326 /* To retrieve */
327 so=PKCS7_get_signed_attribute(si,signed_seq2string_nid);
328 if (so && (so->type == V_ASN1_SEQUENCE))
329 {
330 ASN1_CTX c;
331 ASN1_STRING *s;
332 long length;
333 ASN1_OCTET_STRING *os1,*os2;
334
335 s=so->value.sequence;
336 c.p=ASN1_STRING_data(s);
337 c.max=c.p+ASN1_STRING_length(s);
338 if (!asn1_GetSequence(&c,&length)) GOTO_ERR("") err;
339 /* Length is the length of the seqence */
340
341 c.q=c.p;
342 if ((os1=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL)
343 GOTO_ERR("");
344 c.slen-=(c.p-c.q);
345
346 c.q=c.p;
347 if ((os2=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL)
348 GOTO_ERR("");
349 c.slen-=(c.p-c.q);
350
351 if (!asn1_Finish(&c)) GOTO_ERR("") err;
352 *str1=Malloc(os1->length+1);
353 *str2=Malloc(os2->length+1);
354 memcpy(*str1,os1->data,os1->length);
355 memcpy(*str2,os2->data,os2->length);
356 (*str1)[os1->length]='\0';
357 (*str2)[os2->length]='\0';
358 ASN1_OCTET_STRING_free(os1);
359 ASN1_OCTET_STRING_free(os2);
360 return(1);
361 }
362 err:
363 #endif
364 return(0);
365 }
366 #endif
367
368 /* Called by: main */
369 long /* return serial on success, -1 on failure */
smime_get_signer_info(const char * signed_entity,int info_ix,char ** issuer)370 smime_get_signer_info(const char* signed_entity,
371 int info_ix, /* 0 = first signer */
372 char** issuer) /* DN of the issuer */
373 {
374 int serial = -1;
375 PKCS7* p7 = NULL;
376 STACK_OF(PKCS7_SIGNER_INFO)* sigs = NULL;
377 PKCS7_SIGNER_INFO* si;
378
379 if (!signed_entity || !issuer) GOTO_ERR("NULL arg(s)");
380 *issuer = NULL;
381
382 if (!(p7 = get_pkcs7_from_pem(signed_entity))) goto err;
383 if (!(sigs=PKCS7_get_signer_info(p7)))
384 GOTO_ERR("13 no sigs? (PKCS7_get_signer_info)");
385
386 if (info_ix >= sk_PKCS7_SIGNER_INFO_num(sigs))
387 GOTO_ERR("No more signers. info_ix too large.");
388
389 if (!(si=sk_PKCS7_SIGNER_INFO_value(sigs,info_ix)))
390 GOTO_ERR("NULL signer info");
391
392 *issuer = X509_NAME_oneline(si->issuer_and_serial->issuer, NULL,0);
393 serial = ASN1_INTEGER_get(si->issuer_and_serial->serial);
394
395 err:
396 if (p7) PKCS7_free(p7);
397 return serial;
398 }
399
400 /* Called by: main x3 */
401 char* /* returns contents of the signed message, NULL if error */
smime_verify_signature(const char * pubkey,const char * sig_entity,const char * detached_data,int detached_data_len)402 smime_verify_signature(const char* pubkey,
403 const char* sig_entity, /* signed entity
404 or just the sigature */
405 const char* detached_data, /* possibly NULL */
406 int detached_data_len)
407 {
408 X509* x509 = NULL;
409 PKCS7* p7 = NULL;
410 STACK_OF(PKCS7_SIGNER_INFO)* sigs = NULL;
411 X509_STORE* certs=NULL;
412 BIO* detached = NULL;
413 BIO* p7bio = NULL;
414 BIO* wbio = NULL;
415 char* data = NULL;
416 char buf[4096];
417 int i,x;
418
419 if (!sig_entity || !pubkey) GOTO_ERR("NULL arg(s)");
420 if (!(p7 = get_pkcs7_from_pem(sig_entity))) goto err;
421
422 /* Hmm, if its clear signed, we already provided the detached sig, but
423 * if its one sig blob, may be PKCS7_get_detached() provides BIO connected
424 * to the detached part. Go figure.
425 */
426
427 if (detached_data && detached_data_len) {
428 if (!(detached = set_read_BIO_from_buf(detached_data, detached_data_len)))
429 goto err;
430 } else {
431 if (!PKCS7_get_detached(p7))
432 GOTO_ERR("15 cant extract signed data from signed entity (PKCS7_get_detached)");
433 }
434 if (!(p7bio=PKCS7_dataInit(p7,detached))) GOTO_ERR("PKCS7_dataInit");
435
436 if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
437
438 /* We now have to 'read' from p7bio to calculate message digest(s).
439 * I also take the opportunity to save the signed data. */
440 for (;;) {
441 i = BIO_read(p7bio,buf,sizeof(buf));
442 if (i <= 0) break;
443 BIO_write(wbio, buf, i);
444 }
445
446 if (get_written_BIO_data(wbio, &data)==-1) goto err;
447 BIO_free_all(wbio);
448 wbio = NULL;
449
450 /* We can now verify signatures */
451 if (!(sigs=PKCS7_get_signer_info(p7)))
452 GOTO_ERR("13 no sigs? (PKCS7_get_signer_info)");
453
454 /* Ok, first we need to, for each subject entry, see if we can verify */
455 for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sigs); i++) {
456 PKCS7_SIGNER_INFO *si;
457
458 si=sk_PKCS7_SIGNER_INFO_value(sigs,i);
459
460 /* The bio is needed here only to lookup the message digest context
461 * which presumably now contains the message digest. It will not be
462 * read, and hence its good for any number of iterations. This is so
463 * because MD bios pass the data right thru so they can be stacked
464 * to calculate multiple message digests simultaneously. Clever, eh?
465 */
466
467 #if 0
468 /* *** this is currently broken and thus disabled. --Sampo */
469 /* verifies by looking up the certificate from certs database,
470 * verifying the validity of the certificate, and finally
471 * validity of the signature */
472
473 X509_STORE_CTX cert_ctx;
474 x=PKCS7_dataVerify(certs, &cert_ctx, p7bio, p7, si);
475 #else
476 /* just verify the signature, given that we already have certificate
477 * candidate (see crypto/pk7_doit.c around line 675) */
478
479 if (!(x509 = extract_certificate(pubkey))) goto err;
480 x=PKCS7_signatureVerify(p7bio, p7, si, x509);
481 #endif
482 if (x <= 0) GOTO_ERR("14 sig verify failed");
483
484 #if 0
485 ASN1_UTCTIME *tm;
486 if ((tm=get_signed_time(si)) != NULL) {
487 //fprintf(stderr,"Signed time:");
488 //ASN1_UTCTIME_print(bio_out,tm);
489 ASN1_UTCTIME_free(tm);
490 //BIO_printf(bio_out,"\n");
491 }
492 #endif
493 #if 0
494 char *str1,*str2;
495 if (get_signed_seq2string(si,&str1,&str2)) {
496 fprintf(stderr,"String 1 is %s\n",str1);
497 fprintf(stderr,"String 2 is %s\n",str2);
498 }
499 #endif
500 }
501
502 BIO_free_all(p7bio);
503 PKCS7_free(p7);
504 X509_STORE_free(certs);
505 return data; /* return the signed plain text */
506
507 err:
508 if (wbio) BIO_free_all(wbio);
509 if (p7bio) BIO_free_all(p7bio);
510 if (p7) PKCS7_free(p7);
511 if (certs) X509_STORE_free(certs);
512 if (data) OPENSSL_free(data);
513 return NULL;
514 }
515
516 /* =========== C E R T V E R I F I C A T I O N =========== */
517
518 /* Called by: smime_verify_cert */
519 int /* returns -1 if error, 0 if verfy fail, and 1 if verify OK */
verify_cert(X509 * ca_cert,X509 * cert)520 verify_cert(X509* ca_cert, X509* cert)
521 {
522 EVP_PKEY* pkey = NULL;
523 if (!ca_cert || !cert) GOTO_ERR("NULL arg(s)");
524 if (!(pkey=X509_get_pubkey(ca_cert))) GOTO_ERR("no memory?");
525 return X509_verify(cert, pkey);
526 err:
527 return -1;
528 }
529
530 /* Called by: main */
531 int /* returns -1 if error, 0 if verfy fail, and 1 if verify OK */
smime_verify_cert(const char * ca_cert_pem,const char * cert_pem)532 smime_verify_cert(const char* ca_cert_pem, const char* cert_pem)
533 {
534 X509* ca_cert = NULL;
535 X509* cert = NULL;
536 int ret = -1;
537 if (!ca_cert_pem || !cert_pem) GOTO_ERR("NULL arg(s)");
538 if (!(ca_cert = extract_certificate(ca_cert_pem))) goto err;
539 if (!(cert = extract_certificate(cert_pem))) goto err;
540 ret = verify_cert(ca_cert, cert);
541 err:
542 if (ca_cert) X509_free(ca_cert);
543 if (cert) X509_free(cert);
544 return ret;
545 }
546
547 /* EOF - smime-vfy.c */
548