Import Debian package 0.61.0-1+lenny1
[hcoop/debian/courier-authlib.git] / cramlib.c
CommitLineData
d9898ee8 1/*
0fde1ce3 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
82int auth_get_cram(const char *authtype, char *authdata,
83 struct cram_callback_info *craminfo)
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 {
0fde1ce3 93 DPRINTF("Unsupported authentication type: %s", authtype);
d9898ee8 94 errno=EPERM;
95 return (-1);
96 }
97
98 for (i=0; hmac_list[i]; i++)
99 if (strcmp(hmac_list[i]->hh_name, authtype+5) == 0)
100 break;
101
102 DPRINTF("cram: challenge=%s, response=%s", craminfo->challenge,
103 craminfo->response);
104
105 if (hmac_list[i] == 0
106 || (challenge_l=authsasl_frombase64(craminfo->challenge)) < 0
107 || (response_l=authsasl_frombase64(craminfo->response)) < 0)
108 {
109 DPRINTF("cram: invalid base64 encoding, or unknown method: %s",
110 authtype);
111 errno=EACCES;
112 return (-1);
113 }
114 craminfo->h=hmac_list[i];
115
116 for (i=response_l; i > 0; )
117 {
118 if (craminfo->response[i-1] == ' ')
119 break;
120 --i;
121 }
122
123 if (i == 0)
124 {
125 DPRINTF("cram: invalid base64 encoding");
126 errno=EACCES;
127 return (-1);
128 }
129 craminfo->response[i-1]=0;
130 craminfo->user = craminfo->response;
131 craminfo->response += i;
132 response_l -= i;
133
134 /* Since base64decoded data is always lesser in size (at least),
135 ** we can do the following:
136 */
137 craminfo->challenge[challenge_l]=0;
138 craminfo->response[response_l]=0;
139
140 /* we rely on DPRINTF doing a "safe" print here */
141 DPRINTF("cram: decoded challenge/response, username '%s'",
142 craminfo->user);
143 return (0);
144}
145
146int auth_cram_callback(struct authinfo *a, void *vp)
147{
148struct cram_callback_info *cci=(struct cram_callback_info *)vp;
149unsigned char *hashbuf;
150unsigned char *p;
151unsigned i;
152static const char hex[]="0123456789abcdef";
153int rc;
154
155 if (!a->clearpasswd)
156 return (-1);
157
158 /*
159 hmac->hh_L*2 will be the size of the binary hash.
160
161 hmac->hh_L*4+1 will therefore be size of the binary hash,
162 as a hexadecimal string.
163 */
164
165 if ((hashbuf=malloc(cci->h->hh_L*6+1)) == 0)
166 return (1);
167
168 hmac_hashkey(cci->h, a->clearpasswd, strlen(a->clearpasswd),
169 hashbuf, hashbuf+cci->h->hh_L);
170
171 p=hashbuf+cci->h->hh_L*2;
172
173 for (i=0; i<cci->h->hh_L*2; i++)
174 {
175 char c;
176
177 c = hex[ (hashbuf[i] >> 4) & 0x0F];
178 *p++=c;
179
180 c = hex[ hashbuf[i] & 0x0F];
181 *p++=c;
182
183 *p=0;
184 }
185
186 rc=auth_verify_cram(cci->h, cci->challenge, cci->response,
187 (const char *)hashbuf+cci->h->hh_L*2);
188 free(hashbuf);
189
190 if (rc) return (rc);
191
192 return (*cci->callback_func)(a, cci->callback_arg);
193}