00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 # include "config.h"
00025 #endif
00026
00027
00028 #include "digesthmac.h"
00029
00030
00031 #include <stdlib.h>
00032
00033
00034 #include <string.h>
00035
00036
00037 #include <stdio.h>
00038
00039
00040 #include <gc.h>
00041
00042 #define HEXCHAR(c) ((c & 0x0F) > 9 ? 'a' + (c & 0x0F) - 10 : '0' + (c & 0x0F))
00043
00044 #define QOP_AUTH "auth"
00045 #define QOP_AUTH_INT "auth-int"
00046 #define QOP_AUTH_CONF "auth-conf"
00047
00048 #define A2_PRE "AUTHENTICATE:"
00049 #define A2_POST ":00000000000000000000000000000000"
00050 #define COLON ":"
00051 #define MD5LEN 16
00052 #define DERIVE_CLIENT_INTEGRITY_KEY_STRING \
00053 "Digest session key to client-to-server signing key magic constant"
00054 #define DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN 65
00055 #define DERIVE_SERVER_INTEGRITY_KEY_STRING \
00056 "Digest session key to server-to-client signing key magic constant"
00057 #define DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN 65
00058 #define DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING \
00059 "Digest H(A1) to client-to-server sealing key magic constant"
00060 #define DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN 59
00061 #define DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING \
00062 "Digest H(A1) to server-to-client sealing key magic constant"
00063 #define DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN 59
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 int
00079 digest_md5_hmac (char *output, char secret[MD5LEN], const char *nonce,
00080 unsigned long nc, const char *cnonce, digest_md5_qop qop,
00081 const char *authzid, const char *digesturi, int rspauth,
00082 digest_md5_cipher cipher,
00083 char *kic, char *kis, char *kcc, char *kcs)
00084 {
00085 const char *a2string = rspauth ? COLON : A2_PRE;
00086 char nchex[9];
00087 char a1hexhash[2 * MD5LEN];
00088 char a2hexhash[2 * MD5LEN];
00089 char hash[MD5LEN];
00090 char *tmp, *p;
00091 size_t tmplen;
00092 int rc;
00093 int i;
00094
00095
00096
00097 tmplen = MD5LEN + strlen (COLON) + strlen (nonce) +
00098 strlen (COLON) + strlen (cnonce);
00099 if (authzid && strlen (authzid) > 0)
00100 tmplen += strlen (COLON) + strlen (authzid);
00101
00102 p = tmp = malloc (tmplen);
00103 if (tmp == NULL)
00104 return -1;
00105
00106 memcpy (p, secret, MD5LEN);
00107 p += MD5LEN;
00108 memcpy (p, COLON, strlen (COLON));
00109 p += strlen (COLON);
00110 memcpy (p, nonce, strlen (nonce));
00111 p += strlen (nonce);
00112 memcpy (p, COLON, strlen (COLON));
00113 p += strlen (COLON);
00114 memcpy (p, cnonce, strlen (cnonce));
00115 p += strlen (cnonce);
00116 if (authzid && strlen (authzid) > 0)
00117 {
00118 memcpy (p, COLON, strlen (COLON));
00119 p += strlen (COLON);
00120 memcpy (p, authzid, strlen (authzid));
00121 p += strlen (authzid);
00122 }
00123
00124 rc = gc_md5 (tmp, tmplen, hash);
00125 free (tmp);
00126 if (rc)
00127 return rc;
00128
00129 if (kic)
00130 {
00131 char hash2[MD5LEN];
00132 char q[MD5LEN + DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN];
00133 size_t qlen = MD5LEN + DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN;
00134
00135 memcpy (q, hash, MD5LEN);
00136 memcpy (q + MD5LEN, DERIVE_CLIENT_INTEGRITY_KEY_STRING,
00137 DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN);
00138
00139 rc = gc_md5 (q, qlen, hash2);
00140 if (rc)
00141 return rc;
00142
00143 memcpy (kic, hash2, MD5LEN);
00144 }
00145
00146 if (kis)
00147 {
00148 char hash2[MD5LEN];
00149 char q[MD5LEN + DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN];
00150 size_t qlen = MD5LEN + DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN;
00151
00152 memcpy (q, hash, MD5LEN);
00153 memcpy (q + MD5LEN, DERIVE_SERVER_INTEGRITY_KEY_STRING,
00154 DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN);
00155
00156 rc = gc_md5 (q, qlen, hash2);
00157 if (rc)
00158 return rc;
00159
00160 memcpy (kis, hash2, MD5LEN);
00161 }
00162
00163 if (kcc)
00164 {
00165 char hash2[MD5LEN];
00166 int n;
00167 char q[MD5LEN + DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN];
00168
00169 if (cipher == DIGEST_MD5_CIPHER_RC4_40)
00170 n = 5;
00171 else if (cipher == DIGEST_MD5_CIPHER_RC4_56)
00172 n = 7;
00173 else
00174 n = MD5LEN;
00175
00176 memcpy (q, hash, n);
00177 memcpy (q + n, DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING,
00178 DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN);
00179
00180 rc = gc_md5 (q, n + DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN,
00181 hash2);
00182 if (rc)
00183 return rc;
00184
00185 memcpy (kcc, hash2, MD5LEN);
00186 }
00187
00188 if (kcs)
00189 {
00190 char hash2[MD5LEN];
00191 int n;
00192 char q[MD5LEN + DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN];
00193
00194 if (cipher == DIGEST_MD5_CIPHER_RC4_40)
00195 n = 5;
00196 else if (cipher == DIGEST_MD5_CIPHER_RC4_56)
00197 n = 7;
00198 else
00199 n = MD5LEN;
00200
00201 memcpy (q, hash, n);
00202 memcpy (q + n, DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING,
00203 DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN);
00204
00205 rc = gc_md5 (q, n + DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN,
00206 hash2);
00207 if (rc)
00208 return rc;
00209
00210 memcpy (kcs, hash2, MD5LEN);
00211 }
00212
00213 for (i = 0; i < MD5LEN; i++)
00214 {
00215 a1hexhash[2 * i + 1] = HEXCHAR (hash[i]);
00216 a1hexhash[2 * i + 0] = HEXCHAR (hash[i] >> 4);
00217 }
00218
00219
00220
00221 tmplen = strlen (a2string) + strlen (digesturi);
00222 if (qop & DIGEST_MD5_QOP_AUTH_INT || qop & DIGEST_MD5_QOP_AUTH_CONF)
00223 tmplen += strlen (A2_POST);
00224
00225 p = tmp = malloc (tmplen);
00226 if (tmp == NULL)
00227 return -1;
00228
00229 memcpy (p, a2string, strlen (a2string));
00230 p += strlen (a2string);
00231 memcpy (p, digesturi, strlen (digesturi));
00232 p += strlen (digesturi);
00233 if (qop & DIGEST_MD5_QOP_AUTH_INT || qop & DIGEST_MD5_QOP_AUTH_CONF)
00234 memcpy (p, A2_POST, strlen (A2_POST));
00235
00236 rc = gc_md5 (tmp, tmplen, hash);
00237 free (tmp);
00238 if (rc)
00239 return rc;
00240
00241 for (i = 0; i < MD5LEN; i++)
00242 {
00243 a2hexhash[2 * i + 1] = HEXCHAR (hash[i]);
00244 a2hexhash[2 * i + 0] = HEXCHAR (hash[i] >> 4);
00245 }
00246
00247
00248
00249 sprintf (nchex, "%08lx", nc);
00250
00251 tmplen = 2 * MD5LEN + strlen (COLON) + strlen (nonce) + strlen (COLON) +
00252 strlen (nchex) + strlen (COLON) + strlen (cnonce) + strlen (COLON);
00253 if (qop & DIGEST_MD5_QOP_AUTH_CONF)
00254 tmplen += strlen (QOP_AUTH_CONF);
00255 else if (qop & DIGEST_MD5_QOP_AUTH_INT)
00256 tmplen += strlen (QOP_AUTH_INT);
00257 else if (qop & DIGEST_MD5_QOP_AUTH)
00258 tmplen += strlen (QOP_AUTH);
00259 tmplen += strlen (COLON) + 2 * MD5LEN;
00260
00261 p = tmp = malloc (tmplen);
00262 if (tmp == NULL)
00263 return -1;
00264
00265 memcpy (p, a1hexhash, 2 * MD5LEN);
00266 p += 2 * MD5LEN;
00267 memcpy (p, COLON, strlen (COLON));
00268 p += strlen (COLON);
00269 memcpy (p, nonce, strlen (nonce));
00270 p += strlen (nonce);
00271 memcpy (p, COLON, strlen (COLON));
00272 p += strlen (COLON);
00273 memcpy (p, nchex, strlen (nchex));
00274 p += strlen (nchex);
00275 memcpy (p, COLON, strlen (COLON));
00276 p += strlen (COLON);
00277 memcpy (p, cnonce, strlen (cnonce));
00278 p += strlen (cnonce);
00279 memcpy (p, COLON, strlen (COLON));
00280 p += strlen (COLON);
00281 if (qop & DIGEST_MD5_QOP_AUTH_CONF)
00282 {
00283 memcpy (p, QOP_AUTH_CONF, strlen (QOP_AUTH_CONF));
00284 p += strlen (QOP_AUTH_CONF);
00285 }
00286 else if (qop & DIGEST_MD5_QOP_AUTH_INT)
00287 {
00288 memcpy (p, QOP_AUTH_INT, strlen (QOP_AUTH_INT));
00289 p += strlen (QOP_AUTH_INT);
00290 }
00291 else if (qop & DIGEST_MD5_QOP_AUTH)
00292 {
00293 memcpy (p, QOP_AUTH, strlen (QOP_AUTH));
00294 p += strlen (QOP_AUTH);
00295 }
00296 memcpy (p, COLON, strlen (COLON));
00297 p += strlen (COLON);
00298 memcpy (p, a2hexhash, 2 * MD5LEN);
00299
00300 rc = gc_md5 (tmp, tmplen, hash);
00301 free (tmp);
00302 if (rc)
00303 return rc;
00304
00305 for (i = 0; i < MD5LEN; i++)
00306 {
00307 output[2 * i + 1] = HEXCHAR (hash[i]);
00308 output[2 * i + 0] = HEXCHAR (hash[i] >> 4);
00309 }
00310 output[32] = '\0';
00311
00312 return 0;
00313 }