gsasl  1.8.0
session.c
Go to the documentation of this file.
00001 /* session.c --- Data integrity/privacy protection of DIGEST-MD5.
00002  * Copyright (C) 2002-2012 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 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 /* Get specification. */
00028 #include "session.h"
00029 
00030 /* Get malloc, free. */
00031 #include <stdlib.h>
00032 
00033 /* Get memcpy, strdup, strlen. */
00034 #include <string.h>
00035 
00036 /* Get gc_hmac_md5. */
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[3] & 0xFF) |             \
00117                   ((buf[2] & 0xFF) << 8) |      \
00118                   ((buf[1] & 0xFF) << 16) |     \
00119                   ((buf[0] & 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 }