예제 #1
0
파일: parser.c 프로젝트: cktan/toolchain
static int
parse_finish (char *finish, digest_md5_finish * out)
{
  char *value;

  memset (out, 0, sizeof (*out));

  /* The size of a response-auth MUST be less than 2048 bytes. */
  if (strlen (finish) >= 2048)
    return -1;

  while (*finish != '\0')
    switch (digest_md5_getsubopt (&finish, digest_responseauth_opts, &value))
      {
      case RESPONSEAUTH_RSPAUTH:
	if (*out->rspauth)
	  return -1;
	/* A string of 32 hex digits */
	if (strlen (value) != DIGEST_MD5_RESPONSE_LENGTH)
	  return -1;
	strcpy (out->rspauth, value);
	break;

      default:
	/* The client MUST ignore any unrecognized directives. */
	break;
      }

  /* Validate that we have the mandatory fields. */
  if (digest_md5_validate_finish (out) != 0)
    return -1;

  return 0;
}
예제 #2
0
파일: qop.c 프로젝트: dezelin/maily
int
digest_md5_qopstr2qops (const char *qopstr)
{
  int qops = 0;
  enum
  {
    /* the order must match the following struct */
    QOP_AUTH = 0,
    QOP_AUTH_INT,
    QOP_AUTH_CONF
  };
  const char *const qop_opts[] = {
    /* the order must match the previous enum */
    "qop-auth",
    "qop-int",
    "qop-conf",
    NULL
  };
  char *subsubopts;
  char *val;
  char *qopdup;

  if (!qopstr)
    return 0;

  qopdup = strdup (qopstr);
  if (!qopdup)
    return -1;

  subsubopts = qopdup;
  while (*subsubopts != '\0')
    switch (digest_md5_getsubopt (&subsubopts, qop_opts, &val))
      {
      case QOP_AUTH:
	qops |= DIGEST_MD5_QOP_AUTH;
	break;

      case QOP_AUTH_INT:
	qops |= DIGEST_MD5_QOP_AUTH_INT;
	break;

      case QOP_AUTH_CONF:
	qops |= DIGEST_MD5_QOP_AUTH_CONF;
	break;

      default:
	/* ignore unrecognized options */
	break;
      }

  free (qopdup);

  return qops;
}
예제 #3
0
파일: parser.c 프로젝트: cktan/toolchain
static int
parse_response (char *response, digest_md5_response * out)
{
  char *value;

  memset (out, 0, sizeof (*out));

  /* The size of a digest-response MUST be less than 4096 bytes. */
  if (strlen (response) >= 4096)
    return -1;

  while (*response != '\0')
    switch (digest_md5_getsubopt (&response, digest_response_opts, &value))
      {
      case RESPONSE_USERNAME:
	/* This directive is required and MUST be present exactly
	   once; otherwise, authentication fails. */
	if (out->username)
	  return -1;
	out->username = strdup (value);
	if (!out->username)
	  return -1;
	break;

      case RESPONSE_REALM:
	/* This directive is required if the server provided any
	   realms in the "digest-challenge", in which case it may
	   appear exactly once and its value SHOULD be one of those
	   realms. */
	if (out->realm)
	  return -1;
	out->realm = strdup (value);
	if (!out->realm)
	  return -1;
	break;

      case RESPONSE_NONCE:
	/* This directive is required and MUST be present exactly
	   once; otherwise, authentication fails. */
	if (out->nonce)
	  return -1;
	out->nonce = strdup (value);
	if (!out->nonce)
	  return -1;
	break;

      case RESPONSE_CNONCE:
	/* This directive is required and MUST be present exactly once;
	   otherwise, authentication fails. */
	if (out->cnonce)
	  return -1;
	out->cnonce = strdup (value);
	if (!out->cnonce)
	  return -1;
	break;

      case RESPONSE_NC:
	/* This directive is required and MUST be present exactly
	   once; otherwise, authentication fails. */
	if (out->nc)
	  return -1;
	/* nc-value = 8LHEX */
	if (strlen (value) != 8)
	  return -1;
	out->nc = strtoul (value, NULL, 16);
	/* FIXME: error handling. */
	break;

      case RESPONSE_QOP:
	/* If present, it may appear exactly once and its value MUST
	   be one of the alternatives in qop-options.  */
	if (out->qop)
	  return -1;
	if (strcmp (value, "auth") == 0)
	  out->qop = DIGEST_MD5_QOP_AUTH;
	else if (strcmp (value, "auth-int") == 0)
	  out->qop = DIGEST_MD5_QOP_AUTH_INT;
	else if (strcmp (value, "auth-conf") == 0)
	  out->qop = DIGEST_MD5_QOP_AUTH_CONF;
	else
	  return -1;
	break;

      case RESPONSE_DIGEST_URI:
	/* This directive is required and MUST be present exactly
	   once; if multiple instances are present, the client MUST
	   abort the authentication exchange. */
	if (out->digesturi)
	  return -1;
	/* FIXME: sub-parse. */
	out->digesturi = strdup (value);
	if (!out->digesturi)
	  return -1;
	break;

      case RESPONSE_RESPONSE:
	/* This directive is required and MUST be present exactly
	   once; otherwise, authentication fails. */
	if (*out->response)
	  return -1;
	/* A string of 32 hex digits */
	if (strlen (value) != DIGEST_MD5_RESPONSE_LENGTH)
	  return -1;
	strcpy (out->response, value);
	break;

      case RESPONSE_MAXBUF:
	/* This directive may appear at most once; if multiple
	   instances are present, the server MUST abort the
	   authentication exchange. */
	if (out->clientmaxbuf)
	  return -1;
	out->clientmaxbuf = strtoul (value, NULL, 10);
	/* FIXME: error handling. */
	/* If the value is less or equal to 16 (<<32 for aes-cbc>>) or
	   bigger than 16777215 (i.e. 2**24-1), the server MUST abort
	   the authentication exchange. */
	if (out->clientmaxbuf <= 16 || out->clientmaxbuf > 16777215)
	  return -1;
	break;

      case RESPONSE_CHARSET:
	if (strcmp (DEFAULT_CHARSET, value) != 0)
	  return -1;
	out->utf8 = 1;
	break;

      case RESPONSE_CIPHER:
	if (out->cipher)
	  return -1;
	if (strcmp (value, "3des") == 0)
	  out->cipher = DIGEST_MD5_CIPHER_3DES;
	else if (strcmp (value, "des") == 0)
	  out->cipher = DIGEST_MD5_CIPHER_DES;
	else if (strcmp (value, "rc4-40") == 0)
	  out->cipher = DIGEST_MD5_CIPHER_RC4_40;
	else if (strcmp (value, "rc4") == 0)
	  out->cipher = DIGEST_MD5_CIPHER_RC4;
	else if (strcmp (value, "rc4-56") == 0)
	  out->cipher = DIGEST_MD5_CIPHER_RC4_56;
	else if (strcmp (value, "aes-cbc") == 0)
	  out->cipher = DIGEST_MD5_CIPHER_AES_CBC;
	else
	  return -1;
	break;

      case RESPONSE_AUTHZID:
	/* This directive may appear at most once; if multiple
	   instances are present, the server MUST abort the
	   authentication exchange.  <<FIXME NOT IN DRAFT>> */
	if (out->authzid)
	  return -1;
	/*  The authzid MUST NOT be an empty string. */
	if (*value == '\0')
	  return -1;
	out->authzid = strdup (value);
	if (!out->authzid)
	  return -1;
	break;

      default:
	/* The client MUST ignore any unrecognized directives. */
	break;
      }

  /* Validate that we have the mandatory fields. */
  if (digest_md5_validate_response (out) != 0)
    return -1;

  return 0;
}
예제 #4
0
파일: parser.c 프로젝트: cktan/toolchain
static int
parse_challenge (char *challenge, digest_md5_challenge * out)
{
  int done_algorithm = 0;
  int disable_qop_auth_conf = 0;
  char *value;

  memset (out, 0, sizeof (*out));

  /* The size of a digest-challenge MUST be less than 2048 bytes. */
  if (strlen (challenge) >= 2048)
    return -1;

  while (*challenge != '\0')
    switch (digest_md5_getsubopt (&challenge, digest_challenge_opts, &value))
      {
      case CHALLENGE_REALM:
	{
	  char **tmp;
	  out->nrealms++;
	  tmp = realloc (out->realms, out->nrealms * sizeof (*out->realms));
	  if (!tmp)
	    return -1;
	  out->realms = tmp;
	  out->realms[out->nrealms - 1] = strdup (value);
	  if (!out->realms[out->nrealms - 1])
	    return -1;
	}
	break;

      case CHALLENGE_NONCE:
	/* This directive is required and MUST appear exactly once; if
	   not present, or if multiple instances are present, the
	   client should abort the authentication exchange. */
	if (out->nonce)
	  return -1;
	out->nonce = strdup (value);
	if (!out->nonce)
	  return -1;
	break;

      case CHALLENGE_QOP:
	/* <<What if this directive is present multiple times? Error,
	   or take the union of all values?>> */
	if (out->qops)
	  return -1;
	{
	  char *subsubopts;
	  char *val;

	  subsubopts = value;
	  while (*subsubopts != '\0')
	    switch (digest_md5_getsubopt (&subsubopts, qop_opts, &val))
	      {
	      case QOP_AUTH:
		out->qops |= DIGEST_MD5_QOP_AUTH;
		break;

	      case QOP_AUTH_INT:
		out->qops |= DIGEST_MD5_QOP_AUTH_INT;
		break;

	      case QOP_AUTH_CONF:
		out->qops |= DIGEST_MD5_QOP_AUTH_CONF;
		break;

	      default:
		/* The client MUST ignore unrecognized options */
		break;
	      }
	}
	/* if the client recognizes no cipher, it MUST behave as if
	   "auth-conf" qop option wasn't provided by the server. */
	if (disable_qop_auth_conf)
	  out->qops &= ~DIGEST_MD5_QOP_AUTH_CONF;
	/* if the client recognizes no option, it MUST abort the
	   authentication exchange. */
	if (!out->qops)
	  return -1;
	break;

      case CHALLENGE_STALE:
	/* This directive may appear at most once; if multiple
	   instances are present, the client MUST abort the
	   authentication exchange. */
	if (out->stale)
	  return -1;
	out->stale = 1;
	break;

      case CHALLENGE_MAXBUF:
	/* This directive may appear at most once; if multiple
	   instances are present, or the value is out of range the
	   client MUST abort the authentication exchange. */
	if (out->servermaxbuf)
	  return -1;
	out->servermaxbuf = strtoul (value, NULL, 10);
	/* FIXME: error handling. */
	/* The value MUST be bigger than 16 (32 for Confidentiality
	   protection with the "aes-cbc" cipher) and smaller or equal
	   to 16777215 (i.e. 2**24-1). */
	if (out->servermaxbuf <= 16 || out->servermaxbuf > 16777215)
	  return -1;
	break;

      case CHALLENGE_CHARSET:
	/* This directive may appear at most once; if multiple
	   instances are present, the client MUST abort the
	   authentication exchange. */
	if (out->utf8)
	  return -1;
	if (strcmp (DEFAULT_CHARSET, value) != 0)
	  return -1;
	out->utf8 = 1;
	break;

      case CHALLENGE_ALGORITHM:
	/* This directive is required and MUST appear exactly once; if
	   not present, or if multiple instances are present, the
	   client SHOULD abort the authentication exchange. */
	if (done_algorithm)
	  return -1;
	if (strcmp (DEFAULT_ALGORITHM, value) != 0)
	  return -1;
	done_algorithm = 1;
	break;


      case CHALLENGE_CIPHER:
	/* This directive must be present exactly once if "auth-conf"
	   is offered in the "qop-options" directive */
	if (out->ciphers)
	  return -1;
	{
	  char *subsubopts;
	  char *val;

	  subsubopts = value;
	  while (*subsubopts != '\0')
	    switch (digest_md5_getsubopt (&subsubopts, cipher_opts, &val))
	      {
	      case CIPHER_DES:
		out->ciphers |= DIGEST_MD5_CIPHER_DES;
		break;

	      case CIPHER_3DES:
		out->ciphers |= DIGEST_MD5_CIPHER_3DES;
		break;

	      case CIPHER_RC4:
		out->ciphers |= DIGEST_MD5_CIPHER_RC4;
		break;

	      case CIPHER_RC4_40:
		out->ciphers |= DIGEST_MD5_CIPHER_RC4_40;
		break;

	      case CIPHER_RC4_56:
		out->ciphers |= DIGEST_MD5_CIPHER_RC4_56;
		break;

	      case CIPHER_AES_CBC:
		out->ciphers |= DIGEST_MD5_CIPHER_AES_CBC;
		break;

	      default:
		/* The client MUST ignore unrecognized ciphers */
		break;
	      }
	}
	/* if the client recognizes no cipher, it MUST behave as if
	   "auth-conf" qop option wasn't provided by the server. */
	if (!out->ciphers)
	  {
	    disable_qop_auth_conf = 1;
	    if (out->qops)
	      {
		/* if the client recognizes no option, it MUST abort the
		   authentication exchange. */
		out->qops &= ~DIGEST_MD5_QOP_AUTH_CONF;
		if (!out->qops)
		  return -1;
	      }
	  }
	break;

      default:
	/* The client MUST ignore any unrecognized directives. */
	break;
      }

  /* This directive is required and MUST appear exactly once; if
     not present, or if multiple instances are present, the
     client SHOULD abort the authentication exchange. */
  if (!done_algorithm)
    return -1;

  /* Validate that we have the mandatory fields. */
  if (digest_md5_validate_challenge (out) != 0)
    return -1;

  return 0;
}