2 ** Copyright 1998 - 2008 Double Precision, Inc. See COPYING for
3 ** distribution information.
7 #include "courier_auth_config.h"
13 #include "courierauthsasl.h"
14 #include "courierauth.h"
15 #include "courierauthdebug.h"
16 #include "libhmac/hmac.h"
18 static int nybble(int c
)
20 if (c
>= '0' && c
<= '9') return (c
-'0');
21 if (c
>= 'a' && c
<= 'f') return (c
-'a'+10);
22 if (c
>= 'A' && c
<= 'F') return (c
-'A'+10);
26 static int do_auth_verify_cram(struct hmac_hashinfo
*hash
,
27 const char *challenge
, const char *response
,
28 const char *hashsecret
)
30 unsigned char *context
;
33 if (strlen(hashsecret
) != hash
->hh_L
*4 ||
34 strlen(response
) != hash
->hh_L
*2)
37 if ((context
=malloc(hash
->hh_L
*3)) == 0) return (-1);
39 for (i
=0; i
<hash
->hh_L
*2; i
++)
41 int a
=nybble(hashsecret
[i
*2]), b
=nybble(hashsecret
[i
*2+1]);
51 hmac_hashtext(hash
, challenge
, strlen(challenge
),
52 context
, context
+hash
->hh_L
,
53 context
+hash
->hh_L
*2);
55 for (i
=0; i
<hash
->hh_L
; i
++)
57 int a
=nybble(response
[i
*2]), b
=nybble(response
[i
*2+1]);
59 if ( (unsigned char)(a
*16+b
) !=
60 context
[hash
->hh_L
*2+i
])
70 int auth_verify_cram(struct hmac_hashinfo
*hash
,
71 const char *challenge
, const char *response
,
72 const char *hashsecret
)
76 rc
= do_auth_verify_cram(hash
, challenge
, response
, hashsecret
);
77 DPRINTF(rc
? "cram validation failed" : "cram validation succeeded");
81 static int do_auth_get_cram(const char *authtype
, char *authdata
,
82 struct cram_callback_info
*craminfo
, int logerr
)
88 if (strncmp(authtype
, "cram-", 5) ||
89 (craminfo
->challenge
=strtok(authdata
, "\n")) == 0 ||
90 (craminfo
->response
=strtok(0, "\n")) == 0)
94 DPRINTF("Unsupported authentication type: %s", authtype
);
100 for (i
=0; hmac_list
[i
]; i
++)
101 if (strcmp(hmac_list
[i
]->hh_name
, authtype
+5) == 0)
106 DPRINTF("cram: challenge=%s, response=%s", craminfo
->challenge
,
110 if (hmac_list
[i
] == 0
111 || (challenge_l
=authsasl_frombase64(craminfo
->challenge
)) < 0
112 || (response_l
=authsasl_frombase64(craminfo
->response
)) < 0)
116 DPRINTF("cram: invalid base64 encoding, or unknown method: %s",
122 craminfo
->h
=hmac_list
[i
];
124 for (i
=response_l
; i
> 0; )
126 if (craminfo
->response
[i
-1] == ' ')
135 DPRINTF("cram: invalid base64 encoding");
140 craminfo
->response
[i
-1]=0;
141 craminfo
->user
= craminfo
->response
;
142 craminfo
->response
+= i
;
145 /* Since base64decoded data is always lesser in size (at least),
146 ** we can do the following:
148 craminfo
->challenge
[challenge_l
]=0;
149 craminfo
->response
[response_l
]=0;
153 /* we rely on DPRINTF doing a "safe" print here */
154 DPRINTF("cram: decoded challenge/response, username '%s'",
160 int auth_cram_callback(struct authinfo
*a
, void *vp
)
162 struct cram_callback_info
*cci
=(struct cram_callback_info
*)vp
;
163 unsigned char *hashbuf
;
166 static const char hex
[]="0123456789abcdef";
173 hmac->hh_L*2 will be the size of the binary hash.
175 hmac->hh_L*4+1 will therefore be size of the binary hash,
176 as a hexadecimal string.
179 if ((hashbuf
=malloc(cci
->h
->hh_L
*6+1)) == 0)
182 hmac_hashkey(cci
->h
, a
->clearpasswd
, strlen(a
->clearpasswd
),
183 hashbuf
, hashbuf
+cci
->h
->hh_L
);
185 p
=hashbuf
+cci
->h
->hh_L
*2;
187 for (i
=0; i
<cci
->h
->hh_L
*2; i
++)
191 c
= hex
[ (hashbuf
[i
] >> 4) & 0x0F];
194 c
= hex
[ hashbuf
[i
] & 0x0F];
200 rc
=auth_verify_cram(cci
->h
, cci
->challenge
, cci
->response
,
201 (const char *)hashbuf
+cci
->h
->hh_L
*2);
206 return (*cci
->callback_func
)(a
, cci
->callback_arg
);
209 int auth_get_cram(const char *authtype
, char *authdata
,
210 struct cram_callback_info
*craminfo
)
212 return do_auth_get_cram(authtype
, authdata
, craminfo
, 1);
215 int auth_get_cram_silent(const char *authtype
, char *authdata
,
216 struct cram_callback_info
*craminfo
)
218 return do_auth_get_cram(authtype
, authdata
, craminfo
, 0);