Update gnulib.
[gsasl.git] / lib / digest-md5 / session.c
blob91643334309db84f03eba4c7882cca219ea38981
1 /* session.c --- Data integrity/privacy protection of DIGEST-MD5.
2 * Copyright (C) 2002, 2003, 2004, 2005 Simon Josefsson
4 * This file is part of GNU SASL Library.
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.
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.
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.
23 #if HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 /* Get specification. */
28 #include "session.h"
30 /* Get malloc, free. */
31 #include <stdlib.h>
33 /* Get memcpy, strdup, strlen. */
34 #include <string.h>
36 /* Get gc_hmac_md5. */
37 #include <gc.h>
39 #define MD5LEN 16
40 #define SASL_INTEGRITY_PREFIX_LENGTH 4
41 #define MAC_DATA_LEN 4
42 #define MAC_HMAC_LEN 10
43 #define MAC_MSG_TYPE "\x00\x01"
44 #define MAC_MSG_TYPE_LEN 2
45 #define MAC_SEQNUM_LEN 4
47 int
48 digest_md5_encode (const char *input, size_t input_len,
49 char **output, size_t * output_len,
50 digest_md5_qop qop,
51 unsigned long sendseqnum, char key[DIGEST_MD5_LENGTH])
53 int res;
55 if (qop & DIGEST_MD5_QOP_AUTH_CONF)
57 return -1;
59 else if (qop & DIGEST_MD5_QOP_AUTH_INT)
61 char *seqnumin;
62 char hash[GC_MD5_DIGEST_SIZE];
63 size_t len;
65 seqnumin = malloc (MAC_SEQNUM_LEN + input_len);
66 if (seqnumin == NULL)
67 return -1;
69 seqnumin[0] = (sendseqnum >> 24) & 0xFF;
70 seqnumin[1] = (sendseqnum >> 16) & 0xFF;
71 seqnumin[2] = (sendseqnum >> 8) & 0xFF;
72 seqnumin[3] = sendseqnum & 0xFF;
73 memcpy (seqnumin + MAC_SEQNUM_LEN, input, input_len);
75 res = gc_hmac_md5 (key, MD5LEN,
76 seqnumin, MAC_SEQNUM_LEN + input_len, hash);
77 free (seqnumin);
78 if (res)
79 return -1;
81 *output_len = MAC_DATA_LEN + input_len + MAC_HMAC_LEN +
82 MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN;
83 *output = malloc (*output_len);
84 if (!*output)
85 return -1;
87 len = MAC_DATA_LEN;
88 memcpy (*output + len, input, input_len);
89 len += input_len;
90 memcpy (*output + len, hash, MAC_HMAC_LEN);
91 len += MAC_HMAC_LEN;
92 memcpy (*output + len, MAC_MSG_TYPE, MAC_MSG_TYPE_LEN);
93 len += MAC_MSG_TYPE_LEN;
94 (*output + len)[0] = (sendseqnum >> 24) & 0xFF;
95 (*output + len)[1] = (sendseqnum >> 16) & 0xFF;
96 (*output + len)[2] = (sendseqnum >> 8) & 0xFF;
97 (*output + len)[3] = sendseqnum & 0xFF;
98 len += MAC_SEQNUM_LEN;
99 (*output)[0] = ((len - MAC_DATA_LEN) >> 24) & 0xFF;
100 (*output)[1] = ((len - MAC_DATA_LEN) >> 16) & 0xFF;
101 (*output)[2] = ((len - MAC_DATA_LEN) >> 8) & 0xFF;
102 (*output)[3] = (len - MAC_DATA_LEN) & 0xFF;
104 else
106 *output_len = input_len;
107 *output = malloc (input_len);
108 if (!*output)
109 return -1;
110 memcpy (*output, input, input_len);
113 return 0;
116 #define C2I(buf) ((buf[0] & 0xFF) | \
117 ((buf[1] & 0xFF) << 8) | \
118 ((buf[2] & 0xFF) << 16) | \
119 ((buf[3] & 0xFF) << 24))
122 digest_md5_decode (const char *input, size_t input_len,
123 char **output, size_t * output_len,
124 digest_md5_qop qop,
125 unsigned long readseqnum, char key[DIGEST_MD5_LENGTH])
127 if (qop & DIGEST_MD5_QOP_AUTH_CONF)
129 return -1;
131 else if (qop & DIGEST_MD5_QOP_AUTH_INT)
133 char *seqnumin;
134 char hash[GC_MD5_DIGEST_SIZE];
135 unsigned long len;
136 char tmpbuf[SASL_INTEGRITY_PREFIX_LENGTH];
137 int res;
139 if (input_len < SASL_INTEGRITY_PREFIX_LENGTH)
140 return -2;
142 len = C2I (input);
144 if (input_len < SASL_INTEGRITY_PREFIX_LENGTH + len)
145 return -2;
147 len -= MAC_HMAC_LEN + MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN;
149 seqnumin = malloc (SASL_INTEGRITY_PREFIX_LENGTH + len);
150 if (seqnumin == NULL)
151 return -1;
153 tmpbuf[0] = (readseqnum >> 24) & 0xFF;
154 tmpbuf[1] = (readseqnum >> 16) & 0xFF;
155 tmpbuf[2] = (readseqnum >> 8) & 0xFF;
156 tmpbuf[3] = readseqnum & 0xFF;
158 memcpy (seqnumin, tmpbuf, SASL_INTEGRITY_PREFIX_LENGTH);
159 memcpy (seqnumin + SASL_INTEGRITY_PREFIX_LENGTH,
160 input + MAC_DATA_LEN, len);
162 res = gc_hmac_md5 (key, MD5LEN, seqnumin, MAC_SEQNUM_LEN + len, hash);
163 free (seqnumin);
164 if (res)
165 return -1;
167 if (memcmp
168 (hash,
169 input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN -
170 MAC_HMAC_LEN, MAC_HMAC_LEN) == 0
171 && memcmp (MAC_MSG_TYPE,
172 input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN,
173 MAC_MSG_TYPE_LEN) == 0
174 && memcmp (tmpbuf, input + input_len - MAC_SEQNUM_LEN,
175 MAC_SEQNUM_LEN) == 0)
177 *output_len = len;
178 *output = malloc (*output_len);
179 if (!*output)
180 return -1;
181 memcpy (*output, input + MAC_DATA_LEN, len);
183 else
184 return -1;
186 else
188 *output_len = input_len;
189 *output = malloc (input_len);
190 if (!*output)
191 return -1;
192 memcpy (*output, input, input_len);
195 return 0;