LCOV - code coverage report
Current view: top level - lib/digest-md5 - digesthmac.c (source / functions) Hit Total Coverage
Test: GNU SASL Lines: 123 140 87.9 %
Date: 2012-05-28 Functions: 1 1 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 62 84 73.8 %

           Branch data     Line data    Source code
       1                 :            : /* digesthmac.c --- Compute DIGEST-MD5 response value.
       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 "digesthmac.h"
      29                 :            : 
      30                 :            : /* Get malloc, free. */
      31                 :            : #include <stdlib.h>
      32                 :            : 
      33                 :            : /* Get memcpy, strlen. */
      34                 :            : #include <string.h>
      35                 :            : 
      36                 :            : /* Get sprintf. */
      37                 :            : #include <stdio.h>
      38                 :            : 
      39                 :            : /* Get gc_md5. */
      40                 :            : #include <gc.h>
      41                 :            : 
      42                 :            : #define HEXCHAR(c) ((c & 0x0F) > 9 ? 'a' + (c & 0x0F) - 10 : '0' + (c & 0x0F))
      43                 :            : 
      44                 :            : #define QOP_AUTH "auth"
      45                 :            : #define QOP_AUTH_INT "auth-int"
      46                 :            : #define QOP_AUTH_CONF "auth-conf"
      47                 :            : 
      48                 :            : #define A2_PRE "AUTHENTICATE:"
      49                 :            : #define A2_POST ":00000000000000000000000000000000"
      50                 :            : #define COLON ":"
      51                 :            : #define MD5LEN 16
      52                 :            : #define DERIVE_CLIENT_INTEGRITY_KEY_STRING \
      53                 :            :   "Digest session key to client-to-server signing key magic constant"
      54                 :            : #define DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN 65
      55                 :            : #define DERIVE_SERVER_INTEGRITY_KEY_STRING \
      56                 :            :   "Digest session key to server-to-client signing key magic constant"
      57                 :            : #define DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN 65
      58                 :            : #define DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING \
      59                 :            :   "Digest H(A1) to client-to-server sealing key magic constant"
      60                 :            : #define DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN 59
      61                 :            : #define DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING \
      62                 :            :   "Digest H(A1) to server-to-client sealing key magic constant"
      63                 :            : #define DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN 59
      64                 :            : 
      65                 :            : /* Compute in 33 bytes large array OUTPUT the DIGEST-MD5 response
      66                 :            :    value.  SECRET holds the 16 bytes MD5 hash SS, i.e.,
      67                 :            :    H(username:realm:passwd).  NONCE is a zero terminated string with
      68                 :            :    the server nonce.  NC is the nonce-count, typically 1 for initial
      69                 :            :    authentication.  CNONCE is a zero terminated string with the client
      70                 :            :    nonce.  QOP is the quality of protection to use.  AUTHZID is a zero
      71                 :            :    terminated string with the authorization identity.  DIGESTURI is a
      72                 :            :    zero terminated string with the server principal (e.g.,
      73                 :            :    imap/mail.example.org).  RSPAUTH is a boolean which indicate
      74                 :            :    whether to compute a value for the RSPAUTH response or the "real"
      75                 :            :    authentication.  CIPHER is the cipher to use.  KIC, KIS, KCC, KCS
      76                 :            :    are either NULL, or points to 16 byte arrays that will hold the
      77                 :            :    computed keys on output.  Returns 0 on success. */
      78                 :            : int
      79                 :         62 : digest_md5_hmac (char *output, char secret[MD5LEN], const char *nonce,
      80                 :            :                  unsigned long nc, const char *cnonce, digest_md5_qop qop,
      81                 :            :                  const char *authzid, const char *digesturi, int rspauth,
      82                 :            :                  digest_md5_cipher cipher,
      83                 :            :                  char *kic, char *kis, char *kcc, char *kcs)
      84                 :            : {
      85         [ +  + ]:         62 :   const char *a2string = rspauth ? COLON : A2_PRE;
      86                 :            :   char nchex[9];
      87                 :            :   char a1hexhash[2 * MD5LEN];
      88                 :            :   char a2hexhash[2 * MD5LEN];
      89                 :            :   char hash[MD5LEN];
      90                 :            :   char *tmp, *p;
      91                 :            :   size_t tmplen;
      92                 :            :   int rc;
      93                 :            :   int i;
      94                 :            : 
      95                 :            :   /* A1 */
      96                 :            : 
      97                 :        124 :   tmplen = MD5LEN + strlen (COLON) + strlen (nonce) +
      98                 :         62 :     strlen (COLON) + strlen (cnonce);
      99 [ +  + ][ +  - ]:         62 :   if (authzid && strlen (authzid) > 0)
     100                 :         22 :     tmplen += strlen (COLON) + strlen (authzid);
     101                 :            : 
     102                 :         62 :   p = tmp = malloc (tmplen);
     103         [ -  + ]:         62 :   if (tmp == NULL)
     104                 :          0 :     return -1;
     105                 :            : 
     106                 :         62 :   memcpy (p, secret, MD5LEN);
     107                 :         62 :   p += MD5LEN;
     108                 :         62 :   memcpy (p, COLON, strlen (COLON));
     109                 :         62 :   p += strlen (COLON);
     110                 :         62 :   memcpy (p, nonce, strlen (nonce));
     111                 :         62 :   p += strlen (nonce);
     112                 :         62 :   memcpy (p, COLON, strlen (COLON));
     113                 :         62 :   p += strlen (COLON);
     114                 :         62 :   memcpy (p, cnonce, strlen (cnonce));
     115                 :         62 :   p += strlen (cnonce);
     116 [ +  + ][ +  - ]:         62 :   if (authzid && strlen (authzid) > 0)
     117                 :            :     {
     118                 :         22 :       memcpy (p, COLON, strlen (COLON));
     119                 :         22 :       p += strlen (COLON);
     120                 :         22 :       memcpy (p, authzid, strlen (authzid));
     121                 :         22 :       p += strlen (authzid);
     122                 :            :     }
     123                 :            : 
     124                 :         62 :   rc = gc_md5 (tmp, tmplen, hash);
     125                 :         62 :   free (tmp);
     126         [ -  + ]:         62 :   if (rc)
     127                 :          0 :     return rc;
     128                 :            : 
     129         [ +  + ]:         62 :   if (kic)
     130                 :            :     {
     131                 :            :       char hash2[MD5LEN];
     132                 :            :       char q[MD5LEN + DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN];
     133                 :         30 :       size_t qlen = MD5LEN + DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN;
     134                 :            : 
     135                 :         30 :       memcpy (q, hash, MD5LEN);
     136                 :         30 :       memcpy (q + MD5LEN, DERIVE_CLIENT_INTEGRITY_KEY_STRING,
     137                 :            :               DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN);
     138                 :            : 
     139                 :         30 :       rc = gc_md5 (q, qlen, hash2);
     140         [ -  + ]:         30 :       if (rc)
     141                 :          0 :         return rc;
     142                 :            : 
     143                 :         30 :       memcpy (kic, hash2, MD5LEN);
     144                 :            :     }
     145                 :            : 
     146         [ +  + ]:         62 :   if (kis)
     147                 :            :     {
     148                 :            :       char hash2[MD5LEN];
     149                 :            :       char q[MD5LEN + DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN];
     150                 :         30 :       size_t qlen = MD5LEN + DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN;
     151                 :            : 
     152                 :         30 :       memcpy (q, hash, MD5LEN);
     153                 :         30 :       memcpy (q + MD5LEN, DERIVE_SERVER_INTEGRITY_KEY_STRING,
     154                 :            :               DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN);
     155                 :            : 
     156                 :         30 :       rc = gc_md5 (q, qlen, hash2);
     157         [ -  + ]:         30 :       if (rc)
     158                 :          0 :         return rc;
     159                 :            : 
     160                 :         30 :       memcpy (kis, hash2, MD5LEN);
     161                 :            :     }
     162                 :            : 
     163         [ +  + ]:         62 :   if (kcc)
     164                 :            :     {
     165                 :            :       char hash2[MD5LEN];
     166                 :            :       int n;
     167                 :            :       char q[MD5LEN + DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN];
     168                 :            : 
     169         [ -  + ]:         30 :       if (cipher == DIGEST_MD5_CIPHER_RC4_40)
     170                 :          0 :         n = 5;
     171         [ -  + ]:         30 :       else if (cipher == DIGEST_MD5_CIPHER_RC4_56)
     172                 :          0 :         n = 7;
     173                 :            :       else
     174                 :         30 :         n = MD5LEN;
     175                 :            : 
     176                 :         30 :       memcpy (q, hash, n);
     177                 :         30 :       memcpy (q + n, DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING,
     178                 :            :               DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN);
     179                 :            : 
     180                 :         30 :       rc = gc_md5 (q, n + DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN,
     181                 :            :                    hash2);
     182         [ -  + ]:         30 :       if (rc)
     183                 :          0 :         return rc;
     184                 :            : 
     185                 :         30 :       memcpy (kcc, hash2, MD5LEN);
     186                 :            :     }
     187                 :            : 
     188         [ +  + ]:         62 :   if (kcs)
     189                 :            :     {
     190                 :            :       char hash2[MD5LEN];
     191                 :            :       int n;
     192                 :            :       char q[MD5LEN + DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN];
     193                 :            : 
     194         [ -  + ]:         30 :       if (cipher == DIGEST_MD5_CIPHER_RC4_40)
     195                 :          0 :         n = 5;
     196         [ -  + ]:         30 :       else if (cipher == DIGEST_MD5_CIPHER_RC4_56)
     197                 :          0 :         n = 7;
     198                 :            :       else
     199                 :         30 :         n = MD5LEN;
     200                 :            : 
     201                 :         30 :       memcpy (q, hash, n);
     202                 :         30 :       memcpy (q + n, DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING,
     203                 :            :               DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN);
     204                 :            : 
     205                 :         30 :       rc = gc_md5 (q, n + DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN,
     206                 :            :                    hash2);
     207         [ -  + ]:         30 :       if (rc)
     208                 :          0 :         return rc;
     209                 :            : 
     210                 :         30 :       memcpy (kcs, hash2, MD5LEN);
     211                 :            :     }
     212                 :            : 
     213         [ +  + ]:       1054 :   for (i = 0; i < MD5LEN; i++)
     214                 :            :     {
     215         [ +  + ]:        992 :       a1hexhash[2 * i + 1] = HEXCHAR (hash[i]);
     216         [ +  + ]:        992 :       a1hexhash[2 * i + 0] = HEXCHAR (hash[i] >> 4);
     217                 :            :     }
     218                 :            : 
     219                 :            :   /* A2 */
     220                 :            : 
     221                 :         62 :   tmplen = strlen (a2string) + strlen (digesturi);
     222 [ +  + ][ -  + ]:         62 :   if (qop & DIGEST_MD5_QOP_AUTH_INT || qop & DIGEST_MD5_QOP_AUTH_CONF)
     223                 :          8 :     tmplen += strlen (A2_POST);
     224                 :            : 
     225                 :         62 :   p = tmp = malloc (tmplen);
     226         [ -  + ]:         62 :   if (tmp == NULL)
     227                 :          0 :     return -1;
     228                 :            : 
     229                 :         62 :   memcpy (p, a2string, strlen (a2string));
     230                 :         62 :   p += strlen (a2string);
     231                 :         62 :   memcpy (p, digesturi, strlen (digesturi));
     232                 :         62 :   p += strlen (digesturi);
     233 [ +  + ][ -  + ]:         62 :   if (qop & DIGEST_MD5_QOP_AUTH_INT || qop & DIGEST_MD5_QOP_AUTH_CONF)
     234                 :          8 :     memcpy (p, A2_POST, strlen (A2_POST));
     235                 :            : 
     236                 :         62 :   rc = gc_md5 (tmp, tmplen, hash);
     237                 :         62 :   free (tmp);
     238         [ -  + ]:         62 :   if (rc)
     239                 :          0 :     return rc;
     240                 :            : 
     241         [ +  + ]:       1054 :   for (i = 0; i < MD5LEN; i++)
     242                 :            :     {
     243         [ +  + ]:        992 :       a2hexhash[2 * i + 1] = HEXCHAR (hash[i]);
     244         [ +  + ]:        992 :       a2hexhash[2 * i + 0] = HEXCHAR (hash[i] >> 4);
     245                 :            :     }
     246                 :            : 
     247                 :            :   /* response_value */
     248                 :            : 
     249                 :         62 :   sprintf (nchex, "%08lx", nc);
     250                 :            : 
     251                 :        186 :   tmplen = 2 * MD5LEN + strlen (COLON) + strlen (nonce) + strlen (COLON) +
     252                 :        124 :     strlen (nchex) + strlen (COLON) + strlen (cnonce) + strlen (COLON);
     253         [ -  + ]:         62 :   if (qop & DIGEST_MD5_QOP_AUTH_CONF)
     254                 :          0 :     tmplen += strlen (QOP_AUTH_CONF);
     255         [ +  + ]:         62 :   else if (qop & DIGEST_MD5_QOP_AUTH_INT)
     256                 :          8 :     tmplen += strlen (QOP_AUTH_INT);
     257         [ +  - ]:         54 :   else if (qop & DIGEST_MD5_QOP_AUTH)
     258                 :         54 :     tmplen += strlen (QOP_AUTH);
     259                 :         62 :   tmplen += strlen (COLON) + 2 * MD5LEN;
     260                 :            : 
     261                 :         62 :   p = tmp = malloc (tmplen);
     262         [ -  + ]:         62 :   if (tmp == NULL)
     263                 :          0 :     return -1;
     264                 :            : 
     265                 :         62 :   memcpy (p, a1hexhash, 2 * MD5LEN);
     266                 :         62 :   p += 2 * MD5LEN;
     267                 :         62 :   memcpy (p, COLON, strlen (COLON));
     268                 :         62 :   p += strlen (COLON);
     269                 :         62 :   memcpy (p, nonce, strlen (nonce));
     270                 :         62 :   p += strlen (nonce);
     271                 :         62 :   memcpy (p, COLON, strlen (COLON));
     272                 :         62 :   p += strlen (COLON);
     273                 :         62 :   memcpy (p, nchex, strlen (nchex));
     274                 :         62 :   p += strlen (nchex);
     275                 :         62 :   memcpy (p, COLON, strlen (COLON));
     276                 :         62 :   p += strlen (COLON);
     277                 :         62 :   memcpy (p, cnonce, strlen (cnonce));
     278                 :         62 :   p += strlen (cnonce);
     279                 :         62 :   memcpy (p, COLON, strlen (COLON));
     280                 :         62 :   p += strlen (COLON);
     281         [ -  + ]:         62 :   if (qop & DIGEST_MD5_QOP_AUTH_CONF)
     282                 :            :     {
     283                 :          0 :       memcpy (p, QOP_AUTH_CONF, strlen (QOP_AUTH_CONF));
     284                 :          0 :       p += strlen (QOP_AUTH_CONF);
     285                 :            :     }
     286         [ +  + ]:         62 :   else if (qop & DIGEST_MD5_QOP_AUTH_INT)
     287                 :            :     {
     288                 :          8 :       memcpy (p, QOP_AUTH_INT, strlen (QOP_AUTH_INT));
     289                 :          8 :       p += strlen (QOP_AUTH_INT);
     290                 :            :     }
     291         [ +  - ]:         54 :   else if (qop & DIGEST_MD5_QOP_AUTH)
     292                 :            :     {
     293                 :         54 :       memcpy (p, QOP_AUTH, strlen (QOP_AUTH));
     294                 :         54 :       p += strlen (QOP_AUTH);
     295                 :            :     }
     296                 :         62 :   memcpy (p, COLON, strlen (COLON));
     297                 :         62 :   p += strlen (COLON);
     298                 :         62 :   memcpy (p, a2hexhash, 2 * MD5LEN);
     299                 :            : 
     300                 :         62 :   rc = gc_md5 (tmp, tmplen, hash);
     301                 :         62 :   free (tmp);
     302         [ -  + ]:         62 :   if (rc)
     303                 :          0 :     return rc;
     304                 :            : 
     305         [ +  + ]:       1054 :   for (i = 0; i < MD5LEN; i++)
     306                 :            :     {
     307         [ +  + ]:        992 :       output[2 * i + 1] = HEXCHAR (hash[i]);
     308         [ +  + ]:        992 :       output[2 * i + 0] = HEXCHAR (hash[i] >> 4);
     309                 :            :     }
     310                 :         62 :   output[32] = '\0';
     311                 :            : 
     312                 :         62 :   return 0;
     313                 :            : }

Generated by: LCOV version 1.9