1 | /* session.c --- Data integrity/privacy protection of DIGEST-MD5. |
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 "session.h" |
29 | |
30 | /* Get malloc, free. */ |
31 | #include <stdlib.h> |
32 | |
33 | /* Get memcpy, strdup, strlen. */ |
34 | #include <string.h> |
35 | |
36 | /* Get gc_hmac_md5. */ |
37 | #include <gc.h> |
38 | |
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 |
46 | |
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]) |
52 | { |
53 | int res; |
54 | |
55 | if (qop & DIGEST_MD5_QOP_AUTH_CONF) |
56 | { |
57 | return -1; |
58 | } |
59 | else if (qop & DIGEST_MD5_QOP_AUTH_INT) |
60 | { |
61 | char *seqnumin; |
62 | char hash[GC_MD5_DIGEST_SIZE]; |
63 | size_t len; |
64 | |
65 | seqnumin = malloc (MAC_SEQNUM_LEN + input_len); |
66 | if (seqnumin == NULL) |
67 | return -1; |
68 | |
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); |
74 | |
75 | res = gc_hmac_md5 (key, MD5LEN, |
76 | seqnumin, MAC_SEQNUM_LEN + input_len, hash); |
77 | free (seqnumin); |
78 | if (res) |
79 | return -1; |
80 | |
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; |
86 | |
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; |
103 | } |
104 | else |
105 | { |
106 | *output_len = input_len; |
107 | *output = malloc (input_len); |
108 | if (!*output) |
109 | return -1; |
110 | memcpy (*output, input, input_len); |
111 | } |
112 | |
113 | return 0; |
114 | } |
115 | |
116 | #define C2I(buf) ((buf[3] & 0xFF) | \ |
117 | ((buf[2] & 0xFF) << 8) | \ |
118 | ((buf[1] & 0xFF) << 16) | \ |
119 | ((buf[0] & 0xFF) << 24)) |
120 | |
121 | int |
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]) |
126 | { |
127 | if (qop & DIGEST_MD5_QOP_AUTH_CONF) |
128 | { |
129 | return -1; |
130 | } |
131 | else if (qop & DIGEST_MD5_QOP_AUTH_INT) |
132 | { |
133 | char *seqnumin; |
134 | char hash[GC_MD5_DIGEST_SIZE]; |
135 | unsigned long len; |
136 | char tmpbuf[SASL_INTEGRITY_PREFIX_LENGTH]; |
137 | int res; |
138 | |
139 | if (input_len < SASL_INTEGRITY_PREFIX_LENGTH) |
140 | return -2; |
141 | |
142 | len = C2I (input); |
143 | |
144 | if (input_len < SASL_INTEGRITY_PREFIX_LENGTH + len) |
145 | return -2; |
146 | |
147 | len -= MAC_HMAC_LEN + MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN; |
148 | |
149 | seqnumin = malloc (SASL_INTEGRITY_PREFIX_LENGTH + len); |
150 | if (seqnumin == NULL) |
151 | return -1; |
152 | |
153 | tmpbuf[0] = (readseqnum >> 24) & 0xFF; |
154 | tmpbuf[1] = (readseqnum >> 16) & 0xFF; |
155 | tmpbuf[2] = (readseqnum >> 8) & 0xFF; |
156 | tmpbuf[3] = readseqnum & 0xFF; |
157 | |
158 | memcpy (seqnumin, tmpbuf, SASL_INTEGRITY_PREFIX_LENGTH); |
159 | memcpy (seqnumin + SASL_INTEGRITY_PREFIX_LENGTH, |
160 | input + MAC_DATA_LEN, len); |
161 | |
162 | res = gc_hmac_md5 (key, MD5LEN, seqnumin, MAC_SEQNUM_LEN + len, hash); |
163 | free (seqnumin); |
164 | if (res) |
165 | return -1; |
166 | |
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) |
176 | { |
177 | *output_len = len; |
178 | *output = malloc (*output_len); |
179 | if (!*output) |
180 | return -1; |
181 | memcpy (*output, input + MAC_DATA_LEN, len); |
182 | } |
183 | else |
184 | return -1; |
185 | } |
186 | else |
187 | { |
188 | *output_len = input_len; |
189 | *output = malloc (input_len); |
190 | if (!*output) |
191 | return -1; |
192 | memcpy (*output, input, input_len); |
193 | } |
194 | |
195 | return 0; |
196 | } |
197 | |