1 |
/** |
2 |
* dh.C: DH-BLOWFISH mechanism provider |
3 |
* |
4 |
* Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team |
5 |
* Rights to this code are as documented in COPYING. |
6 |
* |
7 |
* |
8 |
* Portions of this file were derived from sources bearing the following license: |
9 |
* Copyright © 2006 Atheme Development Group |
10 |
* Rights to this code are as documented in doc/pod/license.pod. |
11 |
* |
12 |
* $Id: dh-blowfish.C,v 1.7 2007-09-16 18:54:44 pippijn Exp $ |
13 |
*/ |
14 |
|
15 |
#include "atheme.h" |
16 |
#include <ermyth/module.h> |
17 |
#include <account/myuser.h> |
18 |
#include <sasl.h> |
19 |
|
20 |
#ifdef HAVE_OPENSSL |
21 |
|
22 |
#include <openssl/bn.h> |
23 |
#include <openssl/dh.h> |
24 |
#include <openssl/blowfish.h> |
25 |
#include <arpa/inet.h> |
26 |
|
27 |
static char const rcsid[] = "$Id: dh-blowfish.C,v 1.7 2007-09-16 18:54:44 pippijn Exp $"; |
28 |
|
29 |
REGISTER_MODULE ("saslserv/dh-blowfish", false, "The Ermyth Team <http://ermyth.xinutec.org>"); |
30 |
|
31 |
E list_t sasl_mechanisms; |
32 |
static node_t *mnode; |
33 |
|
34 |
static int mech_start (sasl_session_t *p, char **out, int *out_len); |
35 |
static int mech_step (sasl_session_t *p, char *message, int len, char **out, int *out_len); |
36 |
static void mech_finish (sasl_session_t *p); |
37 |
static sasl_mechanism_t mech ("DH-BLOWFISH", &mech_start, &mech_step, &mech_finish); |
38 |
|
39 |
bool |
40 |
_modinit (module *m) |
41 |
{ |
42 |
mnode = node_create (); |
43 |
node_add (&mech, mnode, &sasl_mechanisms); |
44 |
|
45 |
return true; |
46 |
} |
47 |
|
48 |
void |
49 |
_moddeinit () |
50 |
{ |
51 |
node_del (mnode, &sasl_mechanisms); |
52 |
node_free (mnode); |
53 |
} |
54 |
|
55 |
static int |
56 |
mech_start (sasl_session_t *p, char **out, int *out_len) |
57 |
{ |
58 |
DH *dh; |
59 |
char *ptr; |
60 |
|
61 |
if ((dh = DH_generate_parameters (256, 5, NULL, NULL)) == NULL) |
62 |
return ASASL_FAIL; |
63 |
|
64 |
if (!DH_generate_key (dh)) |
65 |
{ |
66 |
DH_free (dh); |
67 |
return ASASL_FAIL; |
68 |
} |
69 |
|
70 |
/* Serialize p, g, and pub_key */ |
71 |
*out = salloc<char> (BN_num_bytes (dh->p) + BN_num_bytes (dh->g) + BN_num_bytes (dh->pub_key) + 6); |
72 |
*out_len = BN_num_bytes (dh->p) + BN_num_bytes (dh->g) + BN_num_bytes (dh->pub_key) + 6; |
73 |
ptr = *out; |
74 |
|
75 |
/* p */ |
76 |
*((unsigned int *) ptr) = htons (BN_num_bytes (dh->p)); |
77 |
BN_bn2bin (dh->p, (unsigned char *) ptr + 2); |
78 |
ptr += 2 + BN_num_bytes (dh->p); |
79 |
|
80 |
/* g */ |
81 |
*((unsigned int *) ptr) = htons (BN_num_bytes (dh->g)); |
82 |
BN_bn2bin (dh->g, (unsigned char *) ptr + 2); |
83 |
ptr += 2 + BN_num_bytes (dh->g); |
84 |
|
85 |
/* pub_key */ |
86 |
*((unsigned int *) ptr) = htons (BN_num_bytes (dh->pub_key)); |
87 |
BN_bn2bin (dh->pub_key, (unsigned char *) ptr + 2); |
88 |
ptr += 2 + BN_num_bytes (dh->pub_key); |
89 |
|
90 |
p->mechdata = dh; |
91 |
return ASASL_MORE; |
92 |
} |
93 |
|
94 |
static int |
95 |
mech_step (sasl_session_t *p, char *message, int len, char **out, int *out_len) |
96 |
{ |
97 |
DH *dh = NULL; |
98 |
BF_KEY key; |
99 |
BIGNUM *their_key = NULL; |
100 |
myuser_t *mu; |
101 |
char *ptr, *secret = NULL, *password = NULL; |
102 |
int size, ret = ASASL_FAIL; |
103 |
|
104 |
if (!p->mechdata) |
105 |
return ASASL_FAIL; |
106 |
dh = (DH *) p->mechdata; |
107 |
|
108 |
/* Their pub_key */ |
109 |
if (len < 2) |
110 |
goto end; |
111 |
size = ntohs (*(unsigned int *) message); |
112 |
message += 2; |
113 |
len -= 2; |
114 |
if (size > len) |
115 |
goto end; |
116 |
if ((their_key = BN_bin2bn ((unsigned char *) message, size, NULL)) == NULL) |
117 |
goto end; |
118 |
message += size; |
119 |
len -= size; |
120 |
|
121 |
/* Username */ |
122 |
size = strlen (message); |
123 |
if (size >= NICKLEN) /* our base64 routines null-terminate - how polite */ |
124 |
goto end; |
125 |
p->username = strdup (message); |
126 |
message += size + 1; |
127 |
len -= size + 1; |
128 |
if ((mu = myuser_t::find (p->username)) == NULL) |
129 |
goto end; |
130 |
/* AES-encrypted password remains */ |
131 |
|
132 |
/* Compute shared secret */ |
133 |
secret = salloc<char> (DH_size (dh)); |
134 |
if ((size = DH_compute_key ((unsigned char *) secret, their_key, dh)) == -1) |
135 |
goto end; |
136 |
|
137 |
/* Data must be multiple of block size, and let's be reasonable about size */ |
138 |
if (len == 0 || len % 8 || len > 128) |
139 |
goto end; |
140 |
|
141 |
/* Decrypt! */ |
142 |
BF_set_key (&key, size, (unsigned char *) secret); |
143 |
ptr = password = salloc<char> (len + 1); |
144 |
password[len] = '\0'; |
145 |
while (len) |
146 |
{ |
147 |
BF_ecb_encrypt ((unsigned char *) message, (unsigned char *) ptr, &key, BF_DECRYPT); |
148 |
message += 8; |
149 |
ptr += 8; |
150 |
len -= 8; |
151 |
} |
152 |
|
153 |
if (mu->verify_password (password)) |
154 |
ret = ASASL_DONE; |
155 |
|
156 |
end: |
157 |
if (their_key) |
158 |
BN_free (their_key); |
159 |
sfree (secret); |
160 |
sfree (password); |
161 |
return ret; |
162 |
} |
163 |
|
164 |
static void |
165 |
mech_finish (sasl_session_t *p) |
166 |
{ |
167 |
if (p && p->mechdata) |
168 |
{ |
169 |
DH_free ((DH *) p->mechdata); |
170 |
p->mechdata = NULL; |
171 |
} |
172 |
} |
173 |
|
174 |
#endif /* HAVE_OPENSSL */ |