Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 315 lines (276 sloc) 9.426 kb
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
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 *
c507d89 Silence warnings.
Sascha Wildner authored
35 * $DragonFly: src/libexec/dma/crypto.c,v 1.4 2008/09/30 17:47:21 swildner Exp $
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
36 */
37
38 #include <openssl/x509.h>
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
39 #include <openssl/md5.h>
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
40 #include <openssl/ssl.h>
41 #include <openssl/err.h>
42 #include <openssl/pem.h>
43 #include <openssl/rand.h>
44
45 #include <syslog.h>
46
47 #include "dma.h"
48
49 extern struct config *config;
50
51 static int
52 init_cert_file(struct qitem *it, SSL_CTX *ctx, const char *path)
53 {
54 int error;
55
56 /* Load certificate into ctx */
57 error = SSL_CTX_use_certificate_chain_file(ctx, path);
58 if (error < 1) {
53885e5 @corecode dma: pass over the code and improve error handling
authored
59 syslog(LOG_ERR, "%s: SSL: Cannot load certificate `%s': %s",
60 it->queueid, path, ssl_errstr());
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
61 return (-1);
62 }
63
64 /* Add private key to ctx */
65 error = SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM);
66 if (error < 1) {
53885e5 @corecode dma: pass over the code and improve error handling
authored
67 syslog(LOG_ERR, "%s: SSL: Cannot load private key `%s': %s",
68 it->queueid, path, ssl_errstr());
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
69 return (-1);
70 }
71
72 /*
73 * Check the consistency of a private key with the corresponding
74 * certificate
75 */
76 error = SSL_CTX_check_private_key(ctx);
77 if (error < 1) {
78 syslog(LOG_ERR, "%s: SSL: Cannot check private key: %s",
53885e5 @corecode dma: pass over the code and improve error handling
authored
79 it->queueid, ssl_errstr());
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
80 return (-1);
81 }
82
83 return (0);
84 }
85
86 int
87 smtp_init_crypto(struct qitem *it, int fd, int feature)
88 {
89 SSL_CTX *ctx = NULL;
90 SSL_METHOD *meth = NULL;
91 X509 *cert;
92 int error;
93
8aea09c @corecode dma: note that we will have to clean up SSL state
authored
94 /* XXX clean up on error/close */
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
95 /* Init SSL library */
96 SSL_library_init();
53885e5 @corecode dma: pass over the code and improve error handling
authored
97 SSL_load_error_strings();
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
98
99 meth = TLSv1_client_method();
100
101 ctx = SSL_CTX_new(meth);
102 if (ctx == NULL) {
53885e5 @corecode dma: pass over the code and improve error handling
authored
103 syslog(LOG_WARNING, "%s: remote delivery deferred: SSL init failed: %s",
104 it->queueid, ssl_errstr());
105 return (1);
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
106 }
107
108 /* User supplied a certificate */
53885e5 @corecode dma: pass over the code and improve error handling
authored
109 if (config->certfile != NULL) {
110 error = init_cert_file(it, ctx, config->certfile);
111 if (error) {
112 syslog(LOG_WARNING, "%s: remote delivery deferred", it->queueid);
113 return (1);
114 }
115 }
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
116
117 /*
118 * If the user wants STARTTLS, we have to send EHLO here
119 */
120 if (((feature & SECURETRANS) != 0) &&
121 (feature & STARTTLS) != 0) {
122 /* TLS init phase, disable SSL_write */
50c8e68 Rework some bits of the networking code.
Matthias Schmidt authored
123 config->features |= NOSSL;
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
124
125 send_remote_command(fd, "EHLO %s", hostname());
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
126 if (read_remote(fd, 0, NULL) == 2) {
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
127 send_remote_command(fd, "STARTTLS");
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
128 if (read_remote(fd, 0, NULL) != 2) {
53885e5 @corecode dma: pass over the code and improve error handling
authored
129 syslog(LOG_ERR, "%s: remote delivery deferred:"
7a73c46 @corecode dma: properly log last remote status message
authored
130 " STARTTLS not available: %s", it->queueid,
131 neterr);
50c8e68 Rework some bits of the networking code.
Matthias Schmidt authored
132 config->features &= ~NOSSL;
53885e5 @corecode dma: pass over the code and improve error handling
authored
133 return (1);
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
134 }
135 }
136 /* End of TLS init phase, enable SSL_write/read */
50c8e68 Rework some bits of the networking code.
Matthias Schmidt authored
137 config->features &= ~NOSSL;
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
138 }
139
140 config->ssl = SSL_new(ctx);
141 if (config->ssl == NULL) {
53885e5 @corecode dma: pass over the code and improve error handling
authored
142 syslog(LOG_NOTICE, "%s: remote delivery deferred: SSL struct creation failed: %s",
143 it->queueid, ssl_errstr());
144 return (1);
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
145 }
146
147 /* Set ssl to work in client mode */
148 SSL_set_connect_state(config->ssl);
149
150 /* Set fd for SSL in/output */
151 error = SSL_set_fd(config->ssl, fd);
152 if (error == 0) {
53885e5 @corecode dma: pass over the code and improve error handling
authored
153 syslog(LOG_NOTICE, "%s: remote delivery deferred: SSL set fd failed: %s",
154 it->queueid, ssl_errstr());
155 return (1);
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
156 }
157
158 /* Open SSL connection */
159 error = SSL_connect(config->ssl);
160 if (error < 0) {
53885e5 @corecode dma: pass over the code and improve error handling
authored
161 syslog(LOG_ERR, "%s: remote delivery deferred: SSL handshake failed fatally: %s",
162 it->queueid, ssl_errstr());
163 return (1);
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
164 }
165
166 /* Get peer certificate */
167 cert = SSL_get_peer_certificate(config->ssl);
168 if (cert == NULL) {
53885e5 @corecode dma: pass over the code and improve error handling
authored
169 syslog(LOG_WARNING, "%s: remote delivery deferred: Peer did not provide certificate: %s",
170 it->queueid, ssl_errstr());
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
171 }
172 X509_free(cert);
173
174 return (0);
175 }
176
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
177 /*
178 * hmac_md5() taken out of RFC 2104. This RFC was written by H. Krawczyk,
179 * M. Bellare and R. Canetti.
c507d89 Silence warnings.
Sascha Wildner authored
180 *
181 * text pointer to data stream
182 * text_len length of data stream
183 * key pointer to authentication key
184 * key_len length of authentication key
185 * digest caller digest to be filled int
186 */
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
187 void
c507d89 Silence warnings.
Sascha Wildner authored
188 hmac_md5(unsigned char *text, int text_len, unsigned char *key, int key_len,
189 caddr_t digest)
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
190 {
191 MD5_CTX context;
192 unsigned char k_ipad[65]; /* inner padding -
193 * key XORd with ipad
194 */
195 unsigned char k_opad[65]; /* outer padding -
196 * key XORd with opad
197 */
198 unsigned char tk[16];
199 int i;
200 /* if key is longer than 64 bytes reset it to key=MD5(key) */
201 if (key_len > 64) {
202
203 MD5_CTX tctx;
204
205 MD5_Init(&tctx);
206 MD5_Update(&tctx, key, key_len);
207 MD5_Final(tk, &tctx);
208
209 key = tk;
210 key_len = 16;
211 }
212
213 /*
214 * the HMAC_MD5 transform looks like:
215 *
216 * MD5(K XOR opad, MD5(K XOR ipad, text))
217 *
218 * where K is an n byte key
219 * ipad is the byte 0x36 repeated 64 times
220 *
221 * opad is the byte 0x5c repeated 64 times
222 * and text is the data being protected
223 */
224
225 /* start out by storing key in pads */
226 bzero( k_ipad, sizeof k_ipad);
227 bzero( k_opad, sizeof k_opad);
228 bcopy( key, k_ipad, key_len);
229 bcopy( key, k_opad, key_len);
230
231 /* XOR key with ipad and opad values */
232 for (i=0; i<64; i++) {
233 k_ipad[i] ^= 0x36;
234 k_opad[i] ^= 0x5c;
235 }
236 /*
237 * perform inner MD5
238 */
239 MD5_Init(&context); /* init context for 1st
240 * pass */
241 MD5_Update(&context, k_ipad, 64); /* start with inner pad */
242 MD5_Update(&context, text, text_len); /* then text of datagram */
243 MD5_Final(digest, &context); /* finish up 1st pass */
244 /*
245 * perform outer MD5
246 */
247 MD5_Init(&context); /* init context for 2nd
248 * pass */
249 MD5_Update(&context, k_opad, 64); /* start with outer pad */
250 MD5_Update(&context, digest, 16); /* then results of 1st
251 * hash */
252 MD5_Final(digest, &context); /* finish up 2nd pass */
253 }
254
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
255 /*
256 * CRAM-MD5 authentication
257 */
258 int
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
259 smtp_auth_md5(struct qitem *it, int fd, char *login, char *password)
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
260 {
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
261 unsigned char buffer[BUF_SIZE], digest[BUF_SIZE], ascii_digest[33];
262 char *temp;
263 int len, i;
264 static char hextab[] = "0123456789abcdef";
265
266 temp = calloc(BUF_SIZE, 1);
267 memset(buffer, 0, sizeof(buffer));
268 memset(digest, 0, sizeof(digest));
269 memset(ascii_digest, 0, sizeof(ascii_digest));
270
271 /* Send AUTH command according to RFC 2554 */
272 send_remote_command(fd, "AUTH CRAM-MD5");
273 if (read_remote(fd, sizeof(buffer), buffer) != 3) {
196b1b3 @corecode dma: clean up network code
authored
274 syslog(LOG_DEBUG, "%s: smarthost authentification:"
7a73c46 @corecode dma: properly log last remote status message
authored
275 " AUTH cram-md5 not available: %s", it->queueid,
276 neterr);
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
277 /* if cram-md5 is not available */
278 return (-1);
279 }
280
281 /* skip 3 char status + 1 char space */
282 base64_decode(buffer + 4, temp);
283 hmac_md5(temp, strlen(temp), password, strlen(password), digest);
196b1b3 @corecode dma: clean up network code
authored
284 free(temp);
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
285
286 ascii_digest[32] = 0;
287 for (i = 0; i < 16; i++) {
288 ascii_digest[2*i] = hextab[digest[i] >> 4];
289 ascii_digest[2*i+1] = hextab[digest[i] & 15];
290 }
291
292 /* prepare answer */
293 snprintf(buffer, BUF_SIZE, "%s %s", login, ascii_digest);
294
295 /* encode answer */
296 len = base64_encode(buffer, strlen(buffer), &temp);
196b1b3 @corecode dma: clean up network code
authored
297 if (len < 0) {
298 syslog(LOG_ERR, "%s: can not encode auth reply: %m",
299 it->queueid);
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
300 return (-1);
196b1b3 @corecode dma: clean up network code
authored
301 }
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
302
303 /* send answer */
304 send_remote_command(fd, "%s", temp);
196b1b3 @corecode dma: clean up network code
authored
305 free(temp);
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
306 if (read_remote(fd, 0, NULL) != 2) {
791d1a9 @corecode dma: adjust syslog logging levels
authored
307 syslog(LOG_WARNING, "%s: remote delivery deferred:"
7a73c46 @corecode dma: properly log last remote status message
authored
308 " AUTH cram-md5 failed: %s", it->queueid,
309 neterr);
bf28fcc Add CRAM-MD5 authentication support for the DragonFly Mail Agent. This i...
Matthias Schmidt authored
310 return (-2);
311 }
312
313 return (0);
86e4d16 Add the DragonFly Mail Agent dma(8) to the base.
Matthias Schmidt authored
314 }
Something went wrong with that request. Please try again.