00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #if HAVE_CONFIG_H
00024 # include "config.h"
00025 #endif
00026
00027
00028 #include "session.h"
00029
00030
00031 #include <stdlib.h>
00032
00033
00034 #include <string.h>
00035
00036
00037 #include <gc.h>
00038
00039 #define MD5LEN 16
00040 #define SASL_INTEGRITY_PREFIX_LENGTH 4
00041 #define MAC_DATA_LEN 4
00042 #define MAC_HMAC_LEN 10
00043 #define MAC_MSG_TYPE "\x00\x01"
00044 #define MAC_MSG_TYPE_LEN 2
00045 #define MAC_SEQNUM_LEN 4
00046
00047 int
00048 digest_md5_encode (const char *input, size_t input_len,
00049 char **output, size_t * output_len,
00050 digest_md5_qop qop,
00051 unsigned long sendseqnum, char key[DIGEST_MD5_LENGTH])
00052 {
00053 int res;
00054
00055 if (qop & DIGEST_MD5_QOP_AUTH_CONF)
00056 {
00057 return -1;
00058 }
00059 else if (qop & DIGEST_MD5_QOP_AUTH_INT)
00060 {
00061 char *seqnumin;
00062 char hash[GC_MD5_DIGEST_SIZE];
00063 size_t len;
00064
00065 seqnumin = malloc (MAC_SEQNUM_LEN + input_len);
00066 if (seqnumin == NULL)
00067 return -1;
00068
00069 seqnumin[0] = (sendseqnum >> 24) & 0xFF;
00070 seqnumin[1] = (sendseqnum >> 16) & 0xFF;
00071 seqnumin[2] = (sendseqnum >> 8) & 0xFF;
00072 seqnumin[3] = sendseqnum & 0xFF;
00073 memcpy (seqnumin + MAC_SEQNUM_LEN, input, input_len);
00074
00075 res = gc_hmac_md5 (key, MD5LEN,
00076 seqnumin, MAC_SEQNUM_LEN + input_len, hash);
00077 free (seqnumin);
00078 if (res)
00079 return -1;
00080
00081 *output_len = MAC_DATA_LEN + input_len + MAC_HMAC_LEN +
00082 MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN;
00083 *output = malloc (*output_len);
00084 if (!*output)
00085 return -1;
00086
00087 len = MAC_DATA_LEN;
00088 memcpy (*output + len, input, input_len);
00089 len += input_len;
00090 memcpy (*output + len, hash, MAC_HMAC_LEN);
00091 len += MAC_HMAC_LEN;
00092 memcpy (*output + len, MAC_MSG_TYPE, MAC_MSG_TYPE_LEN);
00093 len += MAC_MSG_TYPE_LEN;
00094 (*output + len)[0] = (sendseqnum >> 24) & 0xFF;
00095 (*output + len)[1] = (sendseqnum >> 16) & 0xFF;
00096 (*output + len)[2] = (sendseqnum >> 8) & 0xFF;
00097 (*output + len)[3] = sendseqnum & 0xFF;
00098 len += MAC_SEQNUM_LEN;
00099 (*output)[0] = ((len - MAC_DATA_LEN) >> 24) & 0xFF;
00100 (*output)[1] = ((len - MAC_DATA_LEN) >> 16) & 0xFF;
00101 (*output)[2] = ((len - MAC_DATA_LEN) >> 8) & 0xFF;
00102 (*output)[3] = (len - MAC_DATA_LEN) & 0xFF;
00103 }
00104 else
00105 {
00106 *output_len = input_len;
00107 *output = malloc (input_len);
00108 if (!*output)
00109 return -1;
00110 memcpy (*output, input, input_len);
00111 }
00112
00113 return 0;
00114 }
00115
00116 #define C2I(buf) ((buf[0] & 0xFF) | \
00117 ((buf[1] & 0xFF) << 8) | \
00118 ((buf[2] & 0xFF) << 16) | \
00119 ((buf[3] & 0xFF) << 24))
00120
00121 int
00122 digest_md5_decode (const char *input, size_t input_len,
00123 char **output, size_t * output_len,
00124 digest_md5_qop qop,
00125 unsigned long readseqnum, char key[DIGEST_MD5_LENGTH])
00126 {
00127 if (qop & DIGEST_MD5_QOP_AUTH_CONF)
00128 {
00129 return -1;
00130 }
00131 else if (qop & DIGEST_MD5_QOP_AUTH_INT)
00132 {
00133 char *seqnumin;
00134 char hash[GC_MD5_DIGEST_SIZE];
00135 unsigned long len;
00136 char tmpbuf[SASL_INTEGRITY_PREFIX_LENGTH];
00137 int res;
00138
00139 if (input_len < SASL_INTEGRITY_PREFIX_LENGTH)
00140 return -2;
00141
00142 len = C2I (input);
00143
00144 if (input_len < SASL_INTEGRITY_PREFIX_LENGTH + len)
00145 return -2;
00146
00147 len -= MAC_HMAC_LEN + MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN;
00148
00149 seqnumin = malloc (SASL_INTEGRITY_PREFIX_LENGTH + len);
00150 if (seqnumin == NULL)
00151 return -1;
00152
00153 tmpbuf[0] = (readseqnum >> 24) & 0xFF;
00154 tmpbuf[1] = (readseqnum >> 16) & 0xFF;
00155 tmpbuf[2] = (readseqnum >> 8) & 0xFF;
00156 tmpbuf[3] = readseqnum & 0xFF;
00157
00158 memcpy (seqnumin, tmpbuf, SASL_INTEGRITY_PREFIX_LENGTH);
00159 memcpy (seqnumin + SASL_INTEGRITY_PREFIX_LENGTH,
00160 input + MAC_DATA_LEN, len);
00161
00162 res = gc_hmac_md5 (key, MD5LEN, seqnumin, MAC_SEQNUM_LEN + len, hash);
00163 free (seqnumin);
00164 if (res)
00165 return -1;
00166
00167 if (memcmp
00168 (hash,
00169 input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN -
00170 MAC_HMAC_LEN, MAC_HMAC_LEN) == 0
00171 && memcmp (MAC_MSG_TYPE,
00172 input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN,
00173 MAC_MSG_TYPE_LEN) == 0
00174 && memcmp (tmpbuf, input + input_len - MAC_SEQNUM_LEN,
00175 MAC_SEQNUM_LEN) == 0)
00176 {
00177 *output_len = len;
00178 *output = malloc (*output_len);
00179 if (!*output)
00180 return -1;
00181 memcpy (*output, input + MAC_DATA_LEN, len);
00182 }
00183 else
00184 return -1;
00185 }
00186 else
00187 {
00188 *output_len = input_len;
00189 *output = malloc (input_len);
00190 if (!*output)
00191 return -1;
00192 memcpy (*output, input, input_len);
00193 }
00194
00195 return 0;
00196 }