digesthmac.c

Go to the documentation of this file.
00001 /* digesthmac.c --- Compute DIGEST-MD5 response value.
00002  * Copyright (C) 2002, 2003, 2004  Simon Josefsson
00003  *
00004  * This file is part of GNU SASL Library.
00005  *
00006  * GNU SASL Library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public License
00008  * as published by the Free Software Foundation; either version 2.1 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * GNU SASL Library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with GNU SASL Library; if not, write to the Free
00018  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #if HAVE_CONFIG_H
00024 # include "config.h"
00025 #endif
00026 
00027 /* Get specification. */
00028 #include "digesthmac.h"
00029 
00030 /* Get malloc, free. */
00031 #include <stdlib.h>
00032 
00033 /* Get memcpy, strlen. */
00034 #include <string.h>
00035 
00036 /* Get sprintf. */
00037 #include <stdio.h>
00038 
00039 /* Get gc_md5. */
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 /* Compute in 33 bytes large array OUTPUT the DIGEST-MD5 response
00068    value.  SECRET holds the 16 bytes MD5 hash SS, i.e.,
00069    H(username:realm:passwd).  NONCE is a zero terminated string with
00070    the server nonce.  NC is the nonce-count, typically 1 for initial
00071    authentication.  CNONCE is a zero terminated string with the client
00072    nonce.  QOP is the quality of protection to use.  AUTHZID is a zero
00073    terminated string with the authorization identity.  DIGESTURI is a
00074    zero terminated string with the server principal (e.g.,
00075    imap/mail.example.org).  RSPAUTH is a boolean which indicate
00076    whether to compute a value for the RSPAUTH response or the "real"
00077    authentication.  CIPHER is the cipher to use.  KIC, KIS, KCC, KCS
00078    are either NULL, or points to 16 byte arrays that will hold the
00079    computed keys on output.  Returns 0 on success. */
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   /* A1 */
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   /* A2 */
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   /* response_value */
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 }

Generated on Tue Aug 22 12:06:06 2006 for gsasl by  doxygen 1.4.7