1/* server.c --- SASL CRAM-MD5 server side functions.
2 * Copyright (C) 2002-2012 Simon Josefsson
3 *
4 * This file is part of GNU SASL Library.
5 *
6 * GNU SASL Library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * GNU SASL Library 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 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with GNU SASL Library; if not, write to the Free
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27/* Get specification. */
28#include "cram-md5.h"
29
30/* Get malloc, free. */
31#include <stdlib.h>
32
33/* Get memcpy, strdup, strlen. */
34#include <string.h>
35
36/* Get cram_md5_challenge. */
37#include "challenge.h"
38
39/* Get cram_md5_digest. */
40#include "digest.h"
41
42#define MD5LEN 16
43
44int
45_gsasl_cram_md5_server_start (Gsasl_session * sctx, void **mech_data)
46{
47 char *challenge;
48 int rc;
49
50 challenge = malloc (CRAM_MD5_CHALLENGE_LEN);
51 if (challenge == NULL)
52 return GSASL_MALLOC_ERROR;
53
54 rc = cram_md5_challenge (challenge);
55 if (rc)
56 return GSASL_CRYPTO_ERROR;
57
58 *mech_data = challenge;
59
60 return GSASL_OK;
61}
62
63int
64_gsasl_cram_md5_server_step (Gsasl_session * sctx,
65 void *mech_data,
66 const char *input, size_t input_len,
67 char **output, size_t * output_len)
68{
69 char *challenge = mech_data;
70 char hash[CRAM_MD5_DIGEST_LEN];
71 const char *password;
72 char *username = NULL;
73 int res = GSASL_OK;
74 char *normkey;
75
76 if (input_len == 0)
77 {
78 *output_len = strlen (challenge);
79 *output = strdup (challenge);
80
81 return GSASL_NEEDS_MORE;
82 }
83
84 if (input_len <= MD5LEN * 2)
85 return GSASL_MECHANISM_PARSE_ERROR;
86
87 if (input[input_len - MD5LEN * 2 - 1] != ' ')
88 return GSASL_MECHANISM_PARSE_ERROR;
89
90 username = calloc (1, input_len - MD5LEN * 2);
91 if (username == NULL)
92 return GSASL_MALLOC_ERROR;
93
94 memcpy (username, input, input_len - MD5LEN * 2 - 1);
95
96 gsasl_property_set (sctx, GSASL_AUTHID, username);
97
98 free (username);
99
100 password = gsasl_property_get (sctx, GSASL_PASSWORD);
101 if (!password)
102 return GSASL_NO_PASSWORD;
103
104 /* FIXME: Use SASLprep here? Treat string as storage string?
105 Specification is unclear. */
106 res = gsasl_saslprep (password, 0, &normkey, NULL);
107 if (res != GSASL_OK)
108 return res;
109
110 cram_md5_digest (challenge, strlen (challenge),
111 normkey, strlen (normkey), hash);
112
113 free (normkey);
114
115 if (memcmp (&input[input_len - MD5LEN * 2], hash, 2 * MD5LEN) == 0)
116 res = GSASL_OK;
117 else
118 res = GSASL_AUTHENTICATION_ERROR;
119
120 *output_len = 0;
121 *output = NULL;
122
123 return res;
124}
125
126void
127_gsasl_cram_md5_server_finish (Gsasl_session * sctx, void *mech_data)
128{
129 char *challenge = mech_data;
130
131 free (challenge);
132}
133