2 * S-nail - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 typedef int avoid_empty_file_compiler_warning
;
44 #elif defined USE_OPENSSL
52 static struct termios otio
;
53 static sigjmp_buf ssljmp
;
55 #include <openssl/crypto.h>
56 #include <openssl/ssl.h>
57 #include <openssl/err.h>
58 #include <openssl/x509v3.h>
59 #include <openssl/x509.h>
60 #include <openssl/pem.h>
61 #include <openssl/rand.h>
69 #include <sys/socket.h>
71 #include <netinet/in.h>
72 #ifdef HAVE_ARPA_INET_H
73 #include <arpa/inet.h>
74 #endif /* HAVE_ARPA_INET_H */
81 * Mail -- a mail program
87 * OpenSSL client implementation according to: John Viega, Matt Messier,
88 * Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
91 static int initialized
;
93 static int message_number
;
94 static int verify_error_found
;
96 static void sslcatch(int s
);
97 static int ssl_rand_init(void);
98 static void ssl_init(void);
99 static int ssl_verify_cb(int success
, X509_STORE_CTX
*store
);
100 static const SSL_METHOD
*ssl_select_method(const char *uhp
);
101 static void ssl_load_verifications(struct sock
*sp
);
102 static void ssl_certificate(struct sock
*sp
, const char *uhp
);
103 static enum okay
ssl_check_host(const char *server
, struct sock
*sp
);
105 static int smime_verify(struct message
*m
, int n
, STACK_OF(X509
) *chain
,
108 static int smime_verify(struct message
*m
, int n
, STACK
*chain
,
111 static EVP_CIPHER
*smime_cipher(const char *name
);
112 static int ssl_password_cb(char *buf
, int size
, int rwflag
, void *userdata
);
113 static FILE *smime_sign_cert(const char *xname
, const char *xname2
, int warn
);
114 static char *smime_sign_include_certs(char *name
);
116 static int smime_sign_include_chain_creat(STACK_OF(X509
) **chain
, char *cfiles
);
118 static int smime_sign_include_chain_creat(STACK
**chain
, char *cfiles
);
120 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
121 static enum okay
load_crl1(X509_STORE
*store
, const char *name
);
123 static enum okay
load_crls(X509_STORE
*store
, const char *vfile
,
130 tcsetattr(0, TCSADRAIN
, &otio
);
131 siglongjmp(ssljmp
, s
);
140 if ((cp
= value("ssl-rand-egd")) != NULL
) {
141 if ((cp
= file_expand(cp
)) == NULL
)
143 else if (RAND_egd(cp
) == -1)
144 fprintf(stderr
, tr(245,
145 "entropy daemon at \"%s\" not available\n"),
149 } else if ((cp
= value("ssl-rand-file")) != NULL
) {
150 if ((cp
= file_expand(cp
)) == NULL
)
152 else if (RAND_load_file(cp
, 1024) == -1)
153 fprintf(stderr
, tr(246,
154 "entropy file at \"%s\" not available\n"), cp
);
158 if (stat(cp
, &st
) == 0 && S_ISREG(st
.st_mode
) &&
159 access(cp
, W_OK
) == 0) {
160 if (RAND_write_file(cp
) == -1) {
161 fprintf(stderr
, catgets(catd
, CATSET
,
163 "writing entropy data to \"%s\" failed\n"), cp
);
175 verbose
= value("verbose") != NULL
;
176 if (initialized
== 0) {
181 rand_init
= ssl_rand_init();
185 ssl_verify_cb(int success
, X509_STORE_CTX
*store
)
189 X509
*cert
= X509_STORE_CTX_get_current_cert(store
);
190 int depth
= X509_STORE_CTX_get_error_depth(store
);
191 int err
= X509_STORE_CTX_get_error(store
);
193 verify_error_found
= 1;
195 fprintf(stderr
, "Message %d: ", message_number
);
196 fprintf(stderr
, catgets(catd
, CATSET
, 229,
197 "Error with certificate at depth: %i\n"),
199 X509_NAME_oneline(X509_get_issuer_name(cert
), data
,
201 fprintf(stderr
, catgets(catd
, CATSET
, 230, " issuer = %s\n"),
203 X509_NAME_oneline(X509_get_subject_name(cert
), data
,
205 fprintf(stderr
, catgets(catd
, CATSET
, 231, " subject = %s\n"),
207 fprintf(stderr
, catgets(catd
, CATSET
, 232, " err %i: %s\n"),
208 err
, X509_verify_cert_error_string(err
));
209 if (ssl_vrfy_decide() != OKAY
)
215 static const SSL_METHOD
*
216 ssl_select_method(const char *uhp
)
218 const SSL_METHOD
*method
;
221 cp
= ssl_method_string(uhp
);
223 #ifndef OPENSSL_NO_SSL2
224 if (strcmp(cp
, "ssl2") == 0)
225 method
= SSLv2_client_method();
228 if (strcmp(cp
, "ssl3") == 0)
229 method
= SSLv3_client_method();
230 else if (strcmp(cp
, "tls1") == 0)
231 method
= TLSv1_client_method();
233 fprintf(stderr
, tr(244, "Invalid SSL method \"%s\"\n"),
235 method
= SSLv23_client_method();
238 method
= SSLv23_client_method();
243 ssl_load_verifications(struct sock
*sp
)
245 char *ca_dir
, *ca_file
;
248 if (ssl_vrfy_level
== VRFY_IGNORE
)
250 if ((ca_dir
= value("ssl-ca-dir")) != NULL
)
251 ca_dir
= file_expand(ca_dir
);
252 if ((ca_file
= value("ssl-ca-file")) != NULL
)
253 ca_file
= file_expand(ca_file
);
254 if (ca_dir
|| ca_file
) {
255 if (SSL_CTX_load_verify_locations(sp
->s_ctx
,
256 ca_file
, ca_dir
) != 1) {
257 fprintf(stderr
, catgets(catd
, CATSET
, 233,
260 fprintf(stderr
, catgets(catd
, CATSET
, 234,
263 fprintf(stderr
, catgets(catd
, CATSET
,
267 fprintf(stderr
, catgets(catd
, CATSET
, 236,
269 fprintf(stderr
, catgets(catd
, CATSET
, 237, "\n"));
272 if (value("ssl-no-default-ca") == NULL
) {
273 if (SSL_CTX_set_default_verify_paths(sp
->s_ctx
) != 1)
274 fprintf(stderr
, catgets(catd
, CATSET
, 243,
275 "Error loading default CA locations\n"));
277 verify_error_found
= 0;
279 SSL_CTX_set_verify(sp
->s_ctx
, SSL_VERIFY_PEER
, ssl_verify_cb
);
280 store
= SSL_CTX_get_cert_store(sp
->s_ctx
);
281 load_crls(store
, "ssl-crl-file", "ssl-crl-dir");
285 ssl_certificate(struct sock
*sp
, const char *uhp
)
287 char *certvar
, *keyvar
, *cert
, *key
, *x
;
289 certvar
= ac_alloc(strlen(uhp
) + 10);
290 strcpy(certvar
, "ssl-cert-");
291 strcpy(&certvar
[9], uhp
);
292 if ((cert
= value(certvar
)) != NULL
||
293 (cert
= value("ssl-cert")) != NULL
) {
295 if ((cert
= file_expand(cert
)) == NULL
) {
298 } else if (SSL_CTX_use_certificate_chain_file(sp
->s_ctx
, cert
)
300 keyvar
= ac_alloc(strlen(uhp
) + 9);
301 strcpy(keyvar
, "ssl-key-");
302 if ((key
= value(keyvar
)) == NULL
&&
303 (key
= value("ssl-key")) == NULL
)
305 else if ((x
= key
, key
= file_expand(key
)) == NULL
) {
309 if (SSL_CTX_use_PrivateKey_file(sp
->s_ctx
, key
,
310 SSL_FILETYPE_PEM
) != 1)
311 jbkey
: fprintf(stderr
, tr(238,
312 "cannot load private key from file "
316 jbcert
: fprintf(stderr
, tr(239,
317 "cannot load certificate from file %s\n"),
324 ssl_check_host(const char *server
, struct sock
*sp
)
330 STACK_OF(GENERAL_NAME
) *gens
;
332 /*GENERAL_NAMES*/STACK
*gens
;
337 if ((cert
= SSL_get_peer_certificate(sp
->s_ssl
)) == NULL
) {
338 fprintf(stderr
, catgets(catd
, CATSET
, 248,
339 "no certificate from \"%s\"\n"), server
);
342 gens
= X509_get_ext_d2i(cert
, NID_subject_alt_name
, NULL
, NULL
);
344 for (i
= 0; i
< sk_GENERAL_NAME_num(gens
); i
++) {
345 gen
= sk_GENERAL_NAME_value(gens
, i
);
346 if (gen
->type
== GEN_DNS
) {
349 "Comparing DNS name: \"%s\"\n",
351 if (rfc2595_hostname_match(server
,
352 (char *)gen
->d
.ia5
->data
)
358 if ((subj
= X509_get_subject_name(cert
)) != NULL
&&
359 X509_NAME_get_text_by_NID(subj
, NID_commonName
,
360 data
, sizeof data
) > 0) {
361 data
[sizeof data
- 1] = 0;
363 fprintf(stderr
, "Comparing common name: \"%s\"\n",
365 if (rfc2595_hostname_match(server
, data
) == OKAY
)
370 found
: X509_free(cert
);
375 ssl_open(const char *server
, struct sock
*sp
, const char *uhp
)
381 ssl_set_vrfy_level(uhp
);
383 SSL_CTX_new((SSL_METHOD
*)ssl_select_method(uhp
))) == NULL
) {
384 ssl_gen_err(catgets(catd
, CATSET
, 261, "SSL_CTX_new() failed"));
387 #ifdef SSL_MODE_AUTO_RETRY
388 /* available with OpenSSL 0.9.6 or later */
389 SSL_CTX_set_mode(sp
->s_ctx
, SSL_MODE_AUTO_RETRY
);
390 #endif /* SSL_MODE_AUTO_RETRY */
391 options
= SSL_OP_ALL
;
392 if (value("ssl-v2-allow") == NULL
)
393 options
|= SSL_OP_NO_SSLv2
;
394 SSL_CTX_set_options(sp
->s_ctx
, options
);
395 ssl_load_verifications(sp
);
396 ssl_certificate(sp
, uhp
);
397 if ((cp
= value("ssl-cipher-list")) != NULL
) {
398 if (SSL_CTX_set_cipher_list(sp
->s_ctx
, cp
) != 1)
399 fprintf(stderr
, catgets(catd
, CATSET
, 240,
400 "invalid ciphers: %s\n"), cp
);
402 if ((sp
->s_ssl
= SSL_new(sp
->s_ctx
)) == NULL
) {
403 ssl_gen_err(catgets(catd
, CATSET
, 262, "SSL_new() failed"));
406 SSL_set_fd(sp
->s_ssl
, sp
->s_fd
);
407 if (SSL_connect(sp
->s_ssl
) < 0) {
408 ssl_gen_err(catgets(catd
, CATSET
, 263,
409 "could not initiate SSL/TLS connection"));
412 if (ssl_vrfy_level
!= VRFY_IGNORE
) {
413 if (ssl_check_host(server
, sp
) != OKAY
) {
414 fprintf(stderr
, catgets(catd
, CATSET
, 249,
415 "host certificate does not match \"%s\"\n"),
417 if (ssl_vrfy_decide() != OKAY
)
426 ssl_gen_err(const char *fmt
, ...)
431 vfprintf(stderr
, fmt
, ap
);
433 SSL_load_error_strings();
434 fprintf(stderr
, ": %s\n",
435 (ERR_error_string(ERR_get_error(), NULL
)));
439 smime_sign(FILE *ip
, struct header
*headp
)
441 FILE *sp
, *fp
, *bp
, *hp
;
445 STACK_OF(X509
) *chain
= NULL
;
454 if ((addr
= myorigin(headp
)) == NULL
) {
455 fprintf(stderr
, "No \"from\" address for signing specified\n");
458 if ((fp
= smime_sign_cert(addr
, NULL
, 1)) == NULL
)
460 if ((pkey
= PEM_read_PrivateKey(fp
, NULL
, ssl_password_cb
, NULL
))
462 ssl_gen_err("Error reading private key from");
467 if ((cert
= PEM_read_X509(fp
, NULL
, ssl_password_cb
, NULL
)) == NULL
) {
468 ssl_gen_err("Error reading signer certificate from");
474 if ((cp
= smime_sign_include_certs(addr
)) != NULL
&&
475 !smime_sign_include_chain_creat(&chain
, cp
)) {
480 if ((sp
= Ftemp(&cp
, "Rs", "w+", 0600, 1)) == NULL
) {
483 sk_X509_pop_free(chain
, X509_free
);
491 if (smime_split(ip
, &hp
, &bp
, -1, 0) == STOP
) {
494 sk_X509_pop_free(chain
, X509_free
);
499 if ((bb
= BIO_new_fp(bp
, BIO_NOCLOSE
)) == NULL
||
500 (sb
= BIO_new_fp(sp
, BIO_NOCLOSE
)) == NULL
) {
501 ssl_gen_err("Error creating BIO signing objects");
504 sk_X509_pop_free(chain
, X509_free
);
509 if ((pkcs7
= PKCS7_sign(cert
, pkey
, chain
, bb
,
510 PKCS7_DETACHED
)) == NULL
) {
511 ssl_gen_err("Error creating the PKCS#7 signing object");
516 sk_X509_pop_free(chain
, X509_free
);
521 if (PEM_write_bio_PKCS7(sb
, pkcs7
) == 0) {
522 ssl_gen_err("Error writing signed S/MIME data");
527 sk_X509_pop_free(chain
, X509_free
);
535 sk_X509_pop_free(chain
, X509_free
);
541 return smime_sign_assemble(hp
, bp
, sp
);
546 smime_verify(struct message
*m
, int n
, STACK_OF(X509
) *chain
, X509_STORE
*store
)
548 smime_verify(struct message
*m
, int n
, STACK
*chain
, X509_STORE
*store
)
552 char *cp
, *sender
, *to
, *cc
, *cnttype
;
559 STACK_OF(X509
) *certs
;
560 STACK_OF(GENERAL_NAME
) *gens
;
569 verify_error_found
= 0;
571 loop
: sender
= getsender(m
);
572 to
= hfield1("to", m
);
573 cc
= hfield1("cc", m
);
574 cnttype
= hfield1("content-type", m
);
575 if ((ip
= setinput(&mb
, m
, NEED_BODY
)) == NULL
)
577 if (cnttype
&& strncmp(cnttype
, "application/x-pkcs7-mime", 24) == 0) {
578 if ((x
= smime_decrypt(m
, to
, cc
, 1)) == NULL
)
580 if (x
!= (struct message
*)-1) {
586 if ((fp
= Ftemp(&cp
, "Rv", "w+", 0600, 1)) == NULL
) {
598 if ((fb
= BIO_new_fp(fp
, BIO_NOCLOSE
)) == NULL
) {
599 ssl_gen_err("Error creating BIO verification object "
600 "for message %d", n
);
604 if ((pkcs7
= SMIME_read_PKCS7(fb
, &pb
)) == NULL
) {
605 ssl_gen_err("Error reading PKCS#7 object for message %d", n
);
610 if (PKCS7_verify(pkcs7
, chain
, store
, pb
, NULL
, 0) != 1) {
611 ssl_gen_err("Error verifying message %d", n
);
618 if (sender
== NULL
) {
620 "Warning: Message %d has no sender.\n", n
);
623 certs
= PKCS7_get0_signers(pkcs7
, chain
, 0);
625 fprintf(stderr
, "No certificates found in message %d.\n", n
);
628 for (i
= 0; i
< sk_X509_num(certs
); i
++) {
629 cert
= sk_X509_value(certs
, i
);
630 gens
= X509_get_ext_d2i(cert
, NID_subject_alt_name
, NULL
, NULL
);
632 for (j
= 0; j
< sk_GENERAL_NAME_num(gens
); j
++) {
633 gen
= sk_GENERAL_NAME_value(gens
, j
);
634 if (gen
->type
== GEN_EMAIL
) {
640 if (!asccasecmp((char *)
647 if ((subj
= X509_get_subject_name(cert
)) != NULL
&&
648 X509_NAME_get_text_by_NID(subj
,
649 NID_pkcs9_emailAddress
,
650 data
, sizeof data
) > 0) {
651 data
[sizeof data
- 1] = 0;
653 fprintf(stderr
, "Comparing address: \"%s\"\n",
655 if (asccasecmp(data
, sender
) == 0)
659 fprintf(stderr
, "Message %d: certificate does not match <%s>\n",
662 found
: if (verify_error_found
== 0)
663 printf("Message %d was verified successfully.\n", n
);
664 return verify_error_found
;
670 int *msgvec
= vp
, *ip
;
673 STACK_OF(X509
) *chain
= NULL
;
678 char *ca_dir
, *ca_file
;
681 ssl_vrfy_level
= VRFY_STRICT
;
682 if ((store
= X509_STORE_new()) == NULL
) {
683 ssl_gen_err("Error creating X509 store");
686 X509_STORE_set_verify_cb_func(store
, ssl_verify_cb
);
687 if ((ca_dir
= value("smime-ca-dir")) != NULL
)
688 ca_dir
= file_expand(ca_dir
);
689 if ((ca_file
= value("smime-ca-file")) != NULL
)
690 ca_file
= file_expand(ca_file
);
691 if (ca_dir
|| ca_file
) {
692 if (X509_STORE_load_locations(store
, ca_file
, ca_dir
) != 1) {
693 ssl_gen_err("Error loading %s",
694 ca_file
? ca_file
: ca_dir
);
698 if (value("smime-no-default-ca") == NULL
) {
699 if (X509_STORE_set_default_paths(store
) != 1) {
700 ssl_gen_err("Error loading default CA locations");
704 if (load_crls(store
, "smime-crl-file", "smime-crl-dir") != OKAY
)
706 for (ip
= msgvec
; *ip
; ip
++) {
707 setdot(&message
[*ip
-1]);
708 ec
|= smime_verify(&message
[*ip
-1], *ip
, chain
, store
);
714 smime_cipher(const char *name
)
716 const EVP_CIPHER
*cipher
;
720 vn
= ac_alloc(vs
= strlen(name
) + 30);
721 snprintf(vn
, vs
, "smime-cipher-%s", name
);
722 if ((cp
= value(vn
)) != NULL
) {
723 if (strcmp(cp
, "rc2-40") == 0)
724 cipher
= EVP_rc2_40_cbc();
725 else if (strcmp(cp
, "rc2-64") == 0)
726 cipher
= EVP_rc2_64_cbc();
727 else if (strcmp(cp
, "des") == 0)
728 cipher
= EVP_des_cbc();
729 else if (strcmp(cp
, "des-ede3") == 0)
730 cipher
= EVP_des_ede3_cbc();
732 fprintf(stderr
, "Invalid cipher \"%s\".\n", cp
);
736 cipher
= EVP_des_ede3_cbc();
738 return (EVP_CIPHER
*)cipher
;
742 smime_encrypt(FILE *ip
, const char *xcertfile
, const char *to
)
744 char *certfile
= (char*)xcertfile
, *cp
;
745 FILE *yp
, *fp
, *bp
, *hp
;
750 STACK_OF(X509
) *certs
;
756 if ((certfile
= file_expand(certfile
)) == NULL
)
760 if ((cipher
= smime_cipher(to
)) == NULL
)
762 if ((fp
= Fopen(certfile
, "r")) == NULL
) {
766 if ((cert
= PEM_read_X509(fp
, NULL
, ssl_password_cb
, NULL
)) == NULL
) {
767 ssl_gen_err("Error reading encryption certificate from \"%s\"",
773 certs
= sk_X509_new_null();
774 sk_X509_push(certs
, cert
);
775 if ((yp
= Ftemp(&cp
, "Ry", "w+", 0600, 1)) == NULL
) {
782 if (smime_split(ip
, &hp
, &bp
, -1, 0) == STOP
) {
786 if ((bb
= BIO_new_fp(bp
, BIO_NOCLOSE
)) == NULL
||
787 (yb
= BIO_new_fp(yp
, BIO_NOCLOSE
)) == NULL
) {
788 ssl_gen_err("Error creating BIO encryption objects");
792 if ((pkcs7
= PKCS7_encrypt(certs
, bb
, cipher
, 0)) == NULL
) {
793 ssl_gen_err("Error creating the PKCS#7 encryption object");
799 if (PEM_write_bio_PKCS7(yb
, pkcs7
) == 0) {
800 ssl_gen_err("Error writing encrypted S/MIME data");
811 return smime_encrypt_assemble(hp
, yp
);
815 smime_decrypt(struct message
*m
, const char *to
, const char *cc
, int signcall
)
817 FILE *fp
, *bp
, *hp
, *op
;
821 EVP_PKEY
*pkey
= NULL
;
823 long size
= m
->m_size
;
826 if ((yp
= setinput(&mb
, m
, NEED_BODY
)) == NULL
)
829 if ((fp
= smime_sign_cert(to
, cc
, 0)) != NULL
) {
830 if ((pkey
= PEM_read_PrivateKey(fp
, NULL
, ssl_password_cb
,
832 ssl_gen_err("Error reading private key");
837 if ((cert
= PEM_read_X509(fp
, NULL
, ssl_password_cb
,
839 ssl_gen_err("Error reading decryption certificate");
846 if ((op
= Ftemp(&cp
, "Rp", "w+", 0600, 1)) == NULL
) {
856 if (smime_split(yp
, &hp
, &bp
, size
, 1) == STOP
) {
864 if ((ob
= BIO_new_fp(op
, BIO_NOCLOSE
)) == NULL
||
865 (bb
= BIO_new_fp(bp
, BIO_NOCLOSE
)) == NULL
) {
866 ssl_gen_err("Error creating BIO decryption objects");
874 if ((pkcs7
= SMIME_read_PKCS7(bb
, &pb
)) == NULL
) {
875 ssl_gen_err("Error reading PKCS#7 object");
883 if (PKCS7_type_is_signed(pkcs7
)) {
894 setinput(&mb
, m
, NEED_BODY
);
895 return (struct message
*)-1;
897 if (PKCS7_verify(pkcs7
, NULL
, NULL
, NULL
, ob
,
898 PKCS7_NOVERIFY
|PKCS7_NOSIGS
) != 1)
900 fseek(hp
, 0L, SEEK_END
);
901 fprintf(hp
, "X-Encryption-Cipher: none\n");
904 } else if (pkey
== NULL
) {
905 fprintf(stderr
, "No appropriate private key found.\n");
907 } else if (cert
== NULL
) {
908 fprintf(stderr
, "No appropriate certificate found.\n");
910 } else if (PKCS7_decrypt(pkcs7
, pkey
, cert
, ob
, 0) != 1) {
911 err
: ssl_gen_err("Error decrypting PKCS#7 object");
932 return smime_decrypt_assemble(m
, hp
, op
);
937 ssl_password_cb(char *buf
, int size
, int rwflag
, void *userdata
)
939 sighandler_type saveint
;
945 saveint
= safe_signal(SIGINT
, SIG_IGN
);
946 if (sigsetjmp(ssljmp
, 1) == 0) {
947 if (saveint
!= SIG_IGN
)
948 safe_signal(SIGINT
, sslcatch
);
949 pass
= getpassword(&otio
, &reset_tio
, "PEM pass phrase:");
951 safe_signal(SIGINT
, saveint
);
957 memcpy(buf
, pass
, len
);
962 smime_sign_cert(const char *xname
, const char *xname2
, int warn
)
968 const char *name
= xname
, *name2
= xname2
;
971 np
= lextract(name
, GTO
|GSKIN
);
974 * This needs to be more intelligent since it will
975 * currently take the first name for which a private
976 * key is available regardless of whether it is the
977 * right one for the message.
979 vn
= ac_alloc(vs
= strlen(np
->n_name
) + 30);
980 snprintf(vn
, vs
, "smime-sign-cert-%s", np
->n_name
);
981 if ((cp
= value(vn
)) != NULL
)
991 if ((cp
= value("smime-sign-cert")) != NULL
)
994 fprintf(stderr
, "Could not find a certificate for %s", xname
);
996 fprintf(stderr
, "or %s", xname2
);
1001 if ((cp
= file_expand(cp
)) == NULL
)
1003 if ((fp
= Fopen(cp
, "r")) == NULL
) {
1011 smime_sign_include_certs(char *name
)
1013 /* See comments in smime_sign_cert() for algorithm pitfalls */
1015 struct name
*np
= lextract(name
, GTO
|GSKIN
);
1018 char *vn
= ac_alloc(vs
= strlen(np
->n_name
) + 30);
1019 snprintf(vn
, vs
, "smime-sign-include-certs-%s",
1021 if ((name
= value(vn
)) != NULL
)
1026 return value("smime-sign-include-certs");
1030 smime_sign_include_chain_creat(
1031 #ifdef HAVE_STACK_OF
1032 STACK_OF(X509
) **chain
,
1038 *chain
= sk_X509_new_null();
1043 char *ncf
= strchr(cfiles
, ',');
1046 /* This fails for '=,file' constructs, but those are sick */
1050 if ((cfiles
= file_expand(cfiles
)) != NULL
)
1052 if ((fp
= Fopen(cfiles
, "r")) == NULL
) {
1056 if ((tmp
= PEM_read_X509(fp
, NULL
, ssl_password_cb
, NULL
)
1058 ssl_gen_err("Error reading certificate from \"%s\"",
1063 sk_X509_push(*chain
, tmp
);
1071 if (sk_X509_num(*chain
) == 0) {
1072 fprintf(stderr
, "smime-sign-include-certs defined but empty\n");
1076 jleave
: return (*chain
!= NULL
);
1078 jerr
: sk_X509_pop_free(*chain
, X509_free
);
1084 smime_certsave(struct message
*m
, int n
, FILE *op
)
1087 char *cp
, *to
, *cc
, *cnttype
;
1093 #ifdef HAVE_STACK_OF
1094 STACK_OF(X509
) *certs
;
1095 STACK_OF(X509
) *chain
= NULL
;
1098 STACK
*chain
= NULL
;
1101 enum okay ok
= OKAY
;
1104 loop
: to
= hfield1("to", m
);
1105 cc
= hfield1("cc", m
);
1106 cnttype
= hfield1("content-type", m
);
1107 if ((ip
= setinput(&mb
, m
, NEED_BODY
)) == NULL
)
1109 if (cnttype
&& strncmp(cnttype
, "application/x-pkcs7-mime", 24) == 0) {
1110 if ((x
= smime_decrypt(m
, to
, cc
, 1)) == NULL
)
1112 if (x
!= (struct message
*)-1) {
1118 if ((fp
= Ftemp(&cp
, "Rv", "w+", 0600, 1)) == NULL
) {
1124 while (size
-- > 0) {
1130 if ((fb
= BIO_new_fp(fp
, BIO_NOCLOSE
)) == NULL
) {
1131 ssl_gen_err("Error creating BIO object for message %d", n
);
1135 if ((pkcs7
= SMIME_read_PKCS7(fb
, &pb
)) == NULL
) {
1136 ssl_gen_err("Error reading PKCS#7 object for message %d", n
);
1143 certs
= PKCS7_get0_signers(pkcs7
, chain
, 0);
1144 if (certs
== NULL
) {
1145 fprintf(stderr
, "No certificates found in message %d.\n", n
);
1148 for (i
= 0; i
< sk_X509_num(certs
); i
++) {
1149 cert
= sk_X509_value(certs
, i
);
1150 if (X509_print_fp(op
, cert
) == 0 ||
1151 PEM_write_X509(op
, cert
) == 0) {
1152 ssl_gen_err("Error writing certificate %d from "
1153 "message %d", i
, n
);
1160 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1162 load_crl1(X509_STORE
*store
, const char *name
)
1164 X509_LOOKUP
*lookup
;
1167 printf("Loading CRL from \"%s\".\n", name
);
1168 if ((lookup
= X509_STORE_add_lookup(store
,
1169 X509_LOOKUP_file())) == NULL
) {
1170 ssl_gen_err("Error creating X509 lookup object");
1173 if (X509_load_crl_file(lookup
, name
, X509_FILETYPE_PEM
) != 1) {
1174 ssl_gen_err("Error loading CRL from \"%s\"", name
);
1179 #endif /* new OpenSSL */
1182 load_crls(X509_STORE
*store
, const char *vfile
, const char *vdir
)
1184 char *crl_file
, *crl_dir
;
1185 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1190 #endif /* new OpenSSL */
1192 if ((crl_file
= value(vfile
)) != NULL
) {
1193 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1194 if ((crl_file
= file_expand(crl_file
)) == NULL
||
1195 load_crl1(store
, crl_file
) != OKAY
)
1197 #else /* old OpenSSL */
1199 "This OpenSSL version is too old to use CRLs.\n");
1201 #endif /* old OpenSSL */
1203 if ((crl_dir
= value(vdir
)) != NULL
) {
1204 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1206 if ((x
= file_expand(crl_dir
)) == NULL
||
1207 (dirfd
= opendir(crl_dir
= x
)) == NULL
) {
1211 ds
= strlen(crl_dir
);
1212 fn
= smalloc(fs
= ds
+ 20);
1213 strcpy(fn
, crl_dir
);
1215 while ((dp
= readdir(dirfd
)) != NULL
) {
1216 if (dp
->d_name
[0] == '.' &&
1217 (dp
->d_name
[1] == '\0' ||
1218 (dp
->d_name
[1] == '.' &&
1219 dp
->d_name
[2] == '\0')))
1221 if (dp
->d_name
[0] == '.')
1223 if (ds
+ (es
= strlen(dp
->d_name
)) + 2 < fs
)
1224 fn
= srealloc(fn
, fs
= ds
+ es
+ 20);
1225 strcpy(&fn
[ds
+1], dp
->d_name
);
1226 if (load_crl1(store
, fn
) != OKAY
) {
1234 #else /* old OpenSSL */
1236 "This OpenSSL version is too old to use CRLs.\n");
1238 #endif /* old OpenSSL */
1240 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1241 if (crl_file
|| crl_dir
)
1242 X509_STORE_set_flags(store
, X509_V_FLAG_CRL_CHECK
|
1243 X509_V_FLAG_CRL_CHECK_ALL
);
1244 #endif /* old OpenSSL */
1248 #else /* !NSS && !USE_OPENSSL */
1255 fprintf(stderr
, "No S/MIME support compiled in.\n");
1260 smime_sign(FILE *fp
)
1278 smime_encrypt(FILE *fp
, const char *certfile
, const char *to
)
1289 smime_decrypt(struct message
*m
, const char *to
, const char *cc
, int signcall
)
1307 #endif /* !USE_NSS && !USE_OPENSSL */