1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthias Schmidt <matthias@dragonflybsd.org>, University of Marburg, 6 * Germany. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $DragonFly: src/libexec/dma/crypto.c,v 1.2 2008/03/04 11:36:08 matthias Exp $ 36 */ 37 38 #ifdef HAVE_CRYPTO 39 40 #include <openssl/x509.h> 41 #include <openssl/ssl.h> 42 #include <openssl/err.h> 43 #include <openssl/pem.h> 44 #include <openssl/rand.h> 45 46 #include <syslog.h> 47 48 #include "dma.h" 49 50 extern struct config *config; 51 52 static int 53 init_cert_file(struct qitem *it, SSL_CTX *ctx, const char *path) 54 { 55 int error; 56 57 /* Load certificate into ctx */ 58 error = SSL_CTX_use_certificate_chain_file(ctx, path); 59 if (error < 1) { 60 syslog(LOG_ERR, "%s: SSL: Cannot load certificate: %s", 61 it->queueid, path); 62 return (-1); 63 } 64 65 /* Add private key to ctx */ 66 error = SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM); 67 if (error < 1) { 68 syslog(LOG_ERR, "%s: SSL: Cannot load private key: %s", 69 it->queueid, path); 70 return (-1); 71 } 72 73 /* 74 * Check the consistency of a private key with the corresponding 75 * certificate 76 */ 77 error = SSL_CTX_check_private_key(ctx); 78 if (error < 1) { 79 syslog(LOG_ERR, "%s: SSL: Cannot check private key: %s", 80 it->queueid, path); 81 return (-1); 82 } 83 84 return (0); 85 } 86 87 int 88 smtp_init_crypto(struct qitem *it, int fd, int feature) 89 { 90 SSL_CTX *ctx = NULL; 91 SSL_METHOD *meth = NULL; 92 X509 *cert; 93 char buf[2048]; 94 int error; 95 96 /* Init SSL library */ 97 SSL_library_init(); 98 99 meth = TLSv1_client_method(); 100 101 ctx = SSL_CTX_new(meth); 102 if (ctx == NULL) { 103 syslog(LOG_ERR, "%s: remote delivery deferred:" 104 " SSL init failed: %m", it->queueid); 105 return (2); 106 } 107 108 /* User supplied a certificate */ 109 if (config->certfile != NULL) 110 init_cert_file(it, ctx, config->certfile); 111 112 /* 113 * If the user wants STARTTLS, we have to send EHLO here 114 */ 115 if (((feature & SECURETRANS) != 0) && 116 (feature & STARTTLS) != 0) { 117 /* TLS init phase, disable SSL_write */ 118 config->features |= NOSSL; 119 120 send_remote_command(fd, "EHLO %s", hostname()); 121 if (read_remote(fd) == 2) { 122 send_remote_command(fd, "STARTTLS"); 123 if (read_remote(fd) != 2) { 124 syslog(LOG_ERR, "%s: remote delivery failed:" 125 " STARTTLS not available: %m", it->queueid); 126 config->features &= ~NOSSL; 127 return (-1); 128 } 129 } 130 /* End of TLS init phase, enable SSL_write/read */ 131 config->features &= ~NOSSL; 132 } 133 134 config->ssl = SSL_new(ctx); 135 if (config->ssl == NULL) { 136 syslog(LOG_ERR, "%s: remote delivery deferred:" 137 " SSL struct creation failed:", it->queueid); 138 return (2); 139 } 140 141 /* Set ssl to work in client mode */ 142 SSL_set_connect_state(config->ssl); 143 144 /* Set fd for SSL in/output */ 145 error = SSL_set_fd(config->ssl, fd); 146 if (error == 0) { 147 error = SSL_get_error(config->ssl, error); 148 syslog(LOG_ERR, "%s: remote delivery deferred:" 149 " SSL set fd failed (%d): %m", it->queueid, error); 150 return (2); 151 } 152 153 /* Open SSL connection */ 154 error = SSL_connect(config->ssl); 155 if (error < 0) { 156 syslog(LOG_ERR, "%s: remote delivery failed:" 157 " SSL handshake fataly failed: %m", it->queueid); 158 return (-1); 159 } 160 161 /* Get peer certificate */ 162 cert = SSL_get_peer_certificate(config->ssl); 163 if (cert == NULL) { 164 syslog(LOG_ERR, "%s: remote delivery deferred:" 165 " Peer did not provied certificate: %m", it->queueid); 166 } 167 X509_free(cert); 168 169 return (0); 170 } 171 172 #if 0 173 /* 174 * CRAM-MD5 authentication 175 * 176 * XXX TODO implement me, I don't have a mail server with CRAM-MD5 available 177 */ 178 int 179 smtp_auth_md5(int fd, char *login, char *password) 180 { 181 } 182 #endif /* 0 */ 183 184 #endif /* HAVE_CRYPTO */ 185