challenge.c

Go to the documentation of this file.
00001 /* challenge.c --- Generate a CRAM-MD5 challenge string.
00002  * Copyright (C) 2002, 2003, 2004, 2008, 2009  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 #include <stddef.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026 #include <assert.h>
00027 
00028 /* Get prototype. */
00029 #include "challenge.h"
00030 
00031 /* Get gc_nonce. */
00032 #include <gc.h>
00033 
00034 /*
00035  * From draft-ietf-sasl-crammd5-02.txt:
00036  *
00037  *   The data encoded in the challenge contains a presumptively
00038  *   arbitrary string of random digits, a time-stamp, and the
00039  *   fully-qualified primary host name of the server.
00040  * ...
00041  *   challenge  = "<" 1*DIGIT "." 1*DIGIT "@" hostname ">"
00042  *   hostname   = 1*(ALPHA / DIGIT) *("." / "-" / ALPHA / DIGIT)
00043  *
00044  * This implementation avoid the information leakage by always using 0
00045  * as the time stamp and a fixed host name.  This should be
00046  * unproblematic, as any client that try to validate the challenge
00047  * string somehow, would violate the same specification:
00048  *
00049  *   The client MUST NOT interpret or attempt to validate the
00050  *   contents of the challenge in any way.
00051  *
00052  */
00053 
00054 /* The sequence of X in TEMPLATE must be twice as long as NONCELEN. */
00055 #define NONCELEN 10
00056 #define TEMPLATE "<XXXXXXXXXXXXXXXXXXXX.0@localhost>"
00057 
00058 /* The probabilities for each digit are skewed (0-5 is more likely to
00059    occur than 6-9), but it is just used as a nonce anyway. */
00060 #define DIGIT(c) (((c) & 0x0F) > 9 ?            \
00061                     '0' + ((c) & 0x0F) - 10 :   \
00062                     '0' + ((c) & 0x0F))
00063 
00064 int
00065 cram_md5_challenge (char challenge[CRAM_MD5_CHALLENGE_LEN])
00066 {
00067   char nonce[NONCELEN];
00068   size_t i;
00069   int rc;
00070 
00071   assert (strlen (TEMPLATE) == CRAM_MD5_CHALLENGE_LEN - 1);
00072 
00073   memcpy (challenge, TEMPLATE, CRAM_MD5_CHALLENGE_LEN);
00074 
00075   rc = gc_nonce (nonce, sizeof (nonce));
00076   if (rc != GC_OK)
00077     return -1;
00078 
00079   for (i = 0; i < sizeof (nonce); i++)
00080     {
00081       challenge[1 + i] = DIGIT (nonce[i]);
00082       challenge[11 + i] = DIGIT (nonce[i] >> 4);
00083     }
00084 
00085   return 0;
00086 }