Imported Debian patch 0.66.1-1
[hcoop/debian/courier-authlib.git] / cramlib.c
CommitLineData
d9898ee8 1/*
ac40fd9e 2** Copyright 1998 - 2008 Double Precision, Inc. See COPYING for
d9898ee8 3** distribution information.
4*/
5
6#if HAVE_CONFIG_H
7#include "courier_auth_config.h"
8#endif
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <errno.h>
13#include "courierauthsasl.h"
14#include "cramlib.h"
15#include "courierauthdebug.h"
d9898ee8 16#include "libhmac/hmac.h"
17#include "cramlib.h"
18
19static int nybble(int c)
20{
21 if (c >= '0' && c <= '9') return (c-'0');
22 if (c >= 'a' && c <= 'f') return (c-'a'+10);
23 if (c >= 'A' && c <= 'F') return (c-'A'+10);
24 return (-1);
25}
26
27static int do_auth_verify_cram(struct hmac_hashinfo *hash,
28 const char *challenge, const char *response,
29 const char *hashsecret)
30{
31unsigned char *context;
32unsigned i;
33
34 if (strlen(hashsecret) != hash->hh_L*4 ||
35 strlen(response) != hash->hh_L*2)
36 return (-1);
37
38 if ((context=malloc(hash->hh_L*3)) == 0) return (-1);
39
40 for (i=0; i<hash->hh_L*2; i++)
41 {
42 int a=nybble(hashsecret[i*2]), b=nybble(hashsecret[i*2+1]);
43
44 if (a < 0 || b < 0)
45 {
46 free(context);
47 return (-1);
48 }
49 context[i]= a*16 + b;
50 }
51
52 hmac_hashtext(hash, challenge, strlen(challenge),
53 context, context+hash->hh_L,
54 context+hash->hh_L*2);
55
56 for (i=0; i<hash->hh_L; i++)
57 {
58 int a=nybble(response[i*2]), b=nybble(response[i*2+1]);
59
60 if ( (unsigned char)(a*16+b) !=
61 context[hash->hh_L*2+i])
62 {
63 free(context);
64 return (-1);
65 }
66 }
67 free(context);
68 return (0);
69}
70
71int auth_verify_cram(struct hmac_hashinfo *hash,
72 const char *challenge, const char *response,
73 const char *hashsecret)
74{
75int rc;
76
77 rc = do_auth_verify_cram(hash, challenge, response, hashsecret);
78 DPRINTF(rc ? "cram validation failed" : "cram validation succeeded");
79 return rc;
80}
81
b0322a85
CE
82static int do_auth_get_cram(const char *authtype, char *authdata,
83 struct cram_callback_info *craminfo, int logerr)
d9898ee8 84{
85int i;
86int challenge_l;
87int response_l;
88
89 if (strncmp(authtype, "cram-", 5) ||
90 (craminfo->challenge=strtok(authdata, "\n")) == 0 ||
91 (craminfo->response=strtok(0, "\n")) == 0)
92 {
b0322a85
CE
93 if (logerr)
94 {
95 DPRINTF("Unsupported authentication type: %s", authtype);
96 }
d9898ee8 97 errno=EPERM;
98 return (-1);
99 }
100
101 for (i=0; hmac_list[i]; i++)
102 if (strcmp(hmac_list[i]->hh_name, authtype+5) == 0)
103 break;
104
b0322a85
CE
105 if (logerr)
106 {
107 DPRINTF("cram: challenge=%s, response=%s", craminfo->challenge,
108 craminfo->response);
109 }
d9898ee8 110
111 if (hmac_list[i] == 0
112 || (challenge_l=authsasl_frombase64(craminfo->challenge)) < 0
113 || (response_l=authsasl_frombase64(craminfo->response)) < 0)
114 {
b0322a85
CE
115 if (logerr)
116 {
117 DPRINTF("cram: invalid base64 encoding, or unknown method: %s",
118 authtype);
119 }
d9898ee8 120 errno=EACCES;
121 return (-1);
122 }
123 craminfo->h=hmac_list[i];
124
125 for (i=response_l; i > 0; )
126 {
127 if (craminfo->response[i-1] == ' ')
128 break;
129 --i;
130 }
131
132 if (i == 0)
133 {
b0322a85
CE
134 if (logerr)
135 {
136 DPRINTF("cram: invalid base64 encoding");
137 }
d9898ee8 138 errno=EACCES;
139 return (-1);
140 }
141 craminfo->response[i-1]=0;
142 craminfo->user = craminfo->response;
143 craminfo->response += i;
144 response_l -= i;
145
146 /* Since base64decoded data is always lesser in size (at least),
147 ** we can do the following:
148 */
149 craminfo->challenge[challenge_l]=0;
150 craminfo->response[response_l]=0;
151
b0322a85
CE
152 if (logerr)
153 {
154 /* we rely on DPRINTF doing a "safe" print here */
155 DPRINTF("cram: decoded challenge/response, username '%s'",
156 craminfo->user);
157 }
d9898ee8 158 return (0);
159}
160
161int auth_cram_callback(struct authinfo *a, void *vp)
162{
163struct cram_callback_info *cci=(struct cram_callback_info *)vp;
164unsigned char *hashbuf;
165unsigned char *p;
166unsigned i;
167static const char hex[]="0123456789abcdef";
168int rc;
169
170 if (!a->clearpasswd)
171 return (-1);
172
173 /*
174 hmac->hh_L*2 will be the size of the binary hash.
175
176 hmac->hh_L*4+1 will therefore be size of the binary hash,
177 as a hexadecimal string.
178 */
179
180 if ((hashbuf=malloc(cci->h->hh_L*6+1)) == 0)
181 return (1);
182
183 hmac_hashkey(cci->h, a->clearpasswd, strlen(a->clearpasswd),
184 hashbuf, hashbuf+cci->h->hh_L);
185
186 p=hashbuf+cci->h->hh_L*2;
187
188 for (i=0; i<cci->h->hh_L*2; i++)
189 {
190 char c;
191
192 c = hex[ (hashbuf[i] >> 4) & 0x0F];
193 *p++=c;
194
195 c = hex[ hashbuf[i] & 0x0F];
196 *p++=c;
197
198 *p=0;
199 }
200
201 rc=auth_verify_cram(cci->h, cci->challenge, cci->response,
202 (const char *)hashbuf+cci->h->hh_L*2);
203 free(hashbuf);
204
205 if (rc) return (rc);
206
207 return (*cci->callback_func)(a, cci->callback_arg);
208}
b0322a85
CE
209
210int auth_get_cram(const char *authtype, char *authdata,
211 struct cram_callback_info *craminfo)
212{
213 return do_auth_get_cram(authtype, authdata, craminfo, 1);
214}
215
216int auth_get_cram_silent(const char *authtype, char *authdata,
217 struct cram_callback_info *craminfo)
218{
219 return do_auth_get_cram(authtype, authdata, craminfo, 0);
220}