1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright 2001 Ximian, Inc. (www.ximian.com)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
31 #include <glib/gi18n-lib.h>
33 #include <libedataserver/md5-utils.h>
35 #include "camel-mime-utils.h"
36 #include "camel-sasl-cram-md5.h"
37 #include "camel-service.h"
39 CamelServiceAuthType camel_sasl_cram_md5_authtype = {
42 N_("This option will connect to the server using a "
43 "secure CRAM-MD5 password, if the server supports it."),
49 static CamelSaslClass *parent_class = NULL;
51 /* Returns the class for a CamelSaslCramMd5 */
52 #define CSCM_CLASS(so) CAMEL_SASL_CRAM_MD5_CLASS (CAMEL_OBJECT_GET_CLASS (so))
54 static GByteArray *cram_md5_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
57 camel_sasl_cram_md5_class_init (CamelSaslCramMd5Class *camel_sasl_cram_md5_class)
59 CamelSaslClass *camel_sasl_class = CAMEL_SASL_CLASS (camel_sasl_cram_md5_class);
61 parent_class = CAMEL_SASL_CLASS (camel_type_get_global_classfuncs (camel_sasl_get_type ()));
63 /* virtual method overload */
64 camel_sasl_class->challenge = cram_md5_challenge;
68 camel_sasl_cram_md5_get_type (void)
70 static CamelType type = CAMEL_INVALID_TYPE;
72 if (type == CAMEL_INVALID_TYPE) {
73 type = camel_type_register (camel_sasl_get_type (),
75 sizeof (CamelSaslCramMd5),
76 sizeof (CamelSaslCramMd5Class),
77 (CamelObjectClassInitFunc) camel_sasl_cram_md5_class_init,
86 /* CRAM-MD5 algorithm:
87 * MD5 ((passwd XOR opad), MD5 ((passwd XOR ipad), timestamp))
91 cram_md5_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
94 guchar digest[16], md5asc[33], *s, *p;
95 GByteArray *ret = NULL;
101 /* Need to wait for the server */
105 g_return_val_if_fail (sasl->service->url->passwd != NULL, NULL);
107 memset (ipad, 0, sizeof (ipad));
108 memset (opad, 0, sizeof (opad));
110 passwd = sasl->service->url->passwd;
111 pw_len = strlen (passwd);
113 memcpy (ipad, passwd, pw_len);
114 memcpy (opad, passwd, pw_len);
116 md5_get_digest (passwd, pw_len, ipad);
117 memcpy (opad, ipad, 16);
120 for (i = 0; i < 64; i++) {
126 md5_update (&ctx, ipad, 64);
127 md5_update (&ctx, token->data, token->len);
128 md5_final (&ctx, digest);
131 md5_update (&ctx, opad, 64);
132 md5_update (&ctx, digest, 16);
133 md5_final (&ctx, digest);
135 /* lowercase hexify that bad-boy... */
136 for (s = digest, p = md5asc; p < md5asc + 32; s++, p += 2)
137 sprintf (p, "%.2x", *s);
139 ret = g_byte_array_new ();
140 g_byte_array_append (ret, sasl->service->url->user, strlen (sasl->service->url->user));
141 g_byte_array_append (ret, " ", 1);
142 g_byte_array_append (ret, md5asc, 32);
144 sasl->authenticated = TRUE;