159138Smsmith/* verify.c: The opieverify() library function.
259138Smsmith
359138Smsmith%%% copyright-cmetz-96
459138SmsmithThis software is Copyright 1996-2001 by Craig Metz, All Rights Reserved.
559138SmsmithThe Inner Net License Version 3 applies to this software.
659138SmsmithYou should have received a copy of the license with this software. If
759138Smsmithyou didn't get a copy, you may request one from <license@inner.net>.
859138Smsmith
959138Smsmith	History:
1059138Smsmith
1159138Smsmith	Modified by cmetz for OPIE 2.4. Use struct opie_otpkey for keys.
1259138Smsmith		Check that seed and sequence number are valid.
1359138Smsmith	Modified by cmetz for OPIE 2.32. Renamed _opieparsechallenge() to
1459138Smsmith		__opieparsechallenge() and handle new argument. Fixed init
1559138Smsmith		response parsing bug.
1659138Smsmith	Modified by cmetz for OPIE 2.31. Renamed "init" to "init-hex".
1759138Smsmith	Modified by cmetz for OPIE 2.31. Renamed "init" and "RESPONSE_INIT"
1859138Smsmith		to "init-hex" and "RESPONSE_INIT_HEX". Removed active attack
1959138Smsmith		protection support.
2059138Smsmith	Created by cmetz for OPIE 2.3 using the old verify.c as a guide.
2159138Smsmith*/
2259138Smsmith
2359138Smsmith#include "opie_cfg.h"
2459138Smsmith#ifdef HAVE_STRING_H
2559138Smsmith#include <string.h>
2659138Smsmith#endif /* HAVE_STRING_H */
2759138Smsmith#include "opie.h"
2859138Smsmith
2959138Smsmith#define RESPONSE_STANDARD  0
3059138Smsmith#define RESPONSE_WORD      1
3159138Smsmith#define RESPONSE_HEX       2
3259138Smsmith#define RESPONSE_INIT_HEX  3
3359138Smsmith#define RESPONSE_INIT_WORD 4
3459138Smsmith#define RESPONSE_UNKNOWN   5
3559138Smsmith
3659138Smsmithstruct _rtrans {
3759138Smsmith  int type;
3859138Smsmith  char *name;
3959138Smsmith};
4059138Smsmith
4159138Smsmithstatic struct _rtrans rtrans[] = {
4259138Smsmith  { RESPONSE_WORD, "word" },
4359138Smsmith  { RESPONSE_HEX, "hex" },
4459138Smsmith  { RESPONSE_INIT_HEX, "init-hex" },
4559138Smsmith  { RESPONSE_INIT_WORD, "init-word" },
4659138Smsmith  { RESPONSE_STANDARD, "" },
4759138Smsmith  { RESPONSE_UNKNOWN, NULL }
4859138Smsmith};
4959138Smsmith
5059138Smsmithstatic char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
5159138Smsmith
5259138Smsmithstatic int changed FUNCTION((opie), struct opie *opie)
5359138Smsmith{
5459138Smsmith  struct opie opie2;
5559138Smsmith
5659138Smsmith  memset(&opie2, 0, sizeof(struct opie));
5759138Smsmith  opie2.opie_principal = opie->opie_principal;
5859138Smsmith  if (__opiereadrec(&opie2))
5959138Smsmith    return 1;
6059138Smsmith
6159138Smsmith  if ((opie2.opie_n != opie->opie_n) || strcmp(opie2.opie_val, opie->opie_val) || strcmp(opie2.opie_seed, opie->opie_seed))
6259138Smsmith    return 1;
6359138Smsmith
6459138Smsmith  memset(&opie2, 0, sizeof(struct opie));
6559138Smsmith  return 0;
6659138Smsmith}
6759138Smsmith
6859138Smsmithint opieverify FUNCTION((opie, response), struct opie *opie AND char *response)
6959138Smsmith{
7059138Smsmith  int i, rval = -1;
7159138Smsmith  char *c;
7259138Smsmith  struct opie_otpkey key, fkey, lastkey;
7359138Smsmith  struct opie nopie;
7459138Smsmith
7559138Smsmith  if (!opie || !response)
7659138Smsmith    goto verret;
7759138Smsmith
7859138Smsmith  if (!opie->opie_principal)
7959138Smsmith#if DEBUG
8059138Smsmith    abort();
8159138Smsmith#else /* DEBUG */
8259138Smsmith    goto verret;
8359138Smsmith#endif /* DEBUG */
8459138Smsmith
8559138Smsmith  if (!opieatob8(&lastkey, opie->opie_val))
8659138Smsmith    goto verret;
8759138Smsmith
8859138Smsmith  for (c = opie->opie_seed; *c; c++)
8959138Smsmith    if (!isalnum(*c))
9059138Smsmith      goto verret;
9159138Smsmith
9259138Smsmith  if (opie->opie_n <= 0)
9359138Smsmith    goto verret;
9459138Smsmith
9559138Smsmith  if (c = strchr(response, ':')) {
9659138Smsmith    *(c++) = 0;
9759138Smsmith    {
9859138Smsmith      struct _rtrans *r;
9959138Smsmith      for (r = rtrans; r->name && strcmp(r->name, response); r++);
10059138Smsmith      i = r->type;
10159138Smsmith    }
10259138Smsmith  } else
10359138Smsmith    i = RESPONSE_STANDARD;
10459138Smsmith
10559138Smsmith  switch(i) {
10659138Smsmith  case RESPONSE_STANDARD:
10759138Smsmith    i = 1;
10859138Smsmith
10959138Smsmith    if (opieetob(&key, response) == 1) {
11059138Smsmith      memcpy(&fkey, &key, sizeof(struct opie_otpkey));
11159138Smsmith      opiehash(&fkey, MDX);
11259138Smsmith      i = memcmp(&fkey, &lastkey, sizeof(struct opie_otpkey));
11359138Smsmith    }
11459138Smsmith    if (i && opieatob8(&key, response)) {
11559138Smsmith      memcpy(&fkey, &key, sizeof(struct opie_otpkey));
11659138Smsmith      opiehash(&fkey, MDX);
11759138Smsmith      i = memcmp(&fkey, &lastkey, sizeof(struct opie_otpkey));
11859138Smsmith    }
11959138Smsmith    break;
12059138Smsmith  case RESPONSE_WORD:
12159138Smsmith    i = 1;
12259138Smsmith
12359138Smsmith    if (opieetob(&key, c) == 1) {
12459138Smsmith      memcpy(&fkey, &key, sizeof(struct opie_otpkey));
12559138Smsmith      opiehash(&fkey, MDX);
12659138Smsmith      i = memcmp(&fkey, &lastkey, sizeof(struct opie_otpkey));
12759138Smsmith    }
12859138Smsmith    break;
12959138Smsmith  case RESPONSE_HEX:
13059138Smsmith    i = 1;
13159138Smsmith
13259138Smsmith    if (opieatob8(&key, c)) {
13359138Smsmith      memcpy(&fkey, &key, sizeof(struct opie_otpkey));
13459138Smsmith      opiehash(&fkey, MDX);
13559138Smsmith      i = memcmp(&fkey, &lastkey, sizeof(struct opie_otpkey));
13659138Smsmith    }
13759138Smsmith    break;
13859138Smsmith  case RESPONSE_INIT_HEX:
13959138Smsmith  case RESPONSE_INIT_WORD:
14059138Smsmith    {
14159138Smsmith      char *c2;
14259138Smsmith
14359138Smsmith      if (!(c2 = strchr(c, ':')))
14459138Smsmith	goto verret;
14559138Smsmith
14659138Smsmith      *(c2++) = 0;
14759138Smsmith
14859138Smsmith      if (i == RESPONSE_INIT_HEX) {
14959138Smsmith	if (!opieatob8(&key, c))
15059138Smsmith	  goto verret;
15159138Smsmith      } else {
15259138Smsmith	if (opieetob(&key, c) != 1)
15359138Smsmith	  goto verret;
15459138Smsmith      }
15559138Smsmith
15659138Smsmith      memcpy(&fkey, &key, sizeof(struct opie_otpkey));
15759138Smsmith      opiehash(&fkey, MDX);
15859138Smsmith
15959138Smsmith      if (memcmp(&fkey, &lastkey, sizeof(struct opie_otpkey)))
16059138Smsmith	goto verret;
16159138Smsmith
16259138Smsmith      if (changed(opie))
16359138Smsmith	goto verret;
16459138Smsmith
16559138Smsmith      opie->opie_n--;
16659138Smsmith
16759138Smsmith      if (!opiebtoa8(opie->opie_val, &key))
16859138Smsmith	goto verret;
16959138Smsmith
17059138Smsmith      if (__opiewriterec(opie))
17159138Smsmith	goto verret;
17259138Smsmith
17359138Smsmith      if (!(c2 = strchr(c = c2, ':')))
17459138Smsmith	goto verret;
17559138Smsmith
17659138Smsmith      *(c2++) = 0;
17759138Smsmith
17859138Smsmith      {
17959138Smsmith	int j, k;
18059138Smsmith
18159138Smsmith	if (__opieparsechallenge(c, &j, &(opie->opie_n), &(opie->opie_seed), &k) || (j != MDX) || k)
18259138Smsmith	  goto verret;
18359138Smsmith      }
18459138Smsmith
18559138Smsmith      if (i == RESPONSE_INIT_HEX) {
18659138Smsmith	if (!opieatob8(&key, c2))
18759138Smsmith	  goto verret;
18859138Smsmith      } else {
18959138Smsmith	if (opieetob(&key, c2) != 1)
19059138Smsmith	  goto verret;
19159138Smsmith      }
19259138Smsmith    }
19359138Smsmith    goto verwrt;
19459138Smsmith  case RESPONSE_UNKNOWN:
19559138Smsmith    rval = 1;
19659138Smsmith    goto verret;
19759138Smsmith  default:
19859138Smsmith    rval = -1;
19959138Smsmith    goto verret;
20059138Smsmith  }
20159138Smsmith
20259138Smsmith  if (i) {
20359138Smsmith    rval = 1;
20459138Smsmith    goto verret;
20559138Smsmith  }
20659138Smsmith
20759138Smsmith  if (changed(opie))
20859138Smsmith    goto verret;
20959138Smsmith
21059138Smsmith  opie->opie_n--;
21159138Smsmith
21259138Smsmithverwrt:
21359138Smsmith  if (!opiebtoa8(opie->opie_val, &key))
21459138Smsmith    goto verret;
21559138Smsmith  rval = __opiewriterec(opie);
21659138Smsmith
21759138Smsmithverret:
21859138Smsmith  opieunlock();
21959138Smsmith  memset(opie, 0, sizeof(struct opie));
22059138Smsmith  return rval;
22159138Smsmith}
22259138Smsmith