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