Report generated at: Tue Mar 30 23:45:56 CEST 2010
| Total number of functions | 170 |
| Number of low risk functions | 141 |
| Number of moderate risk functions | 15 |
| Number of high risk functions | 14 |
| Number of untestable functions | 0 |
Used ranges:
| Cyclomatic Complexity | Risk Evaluation | |
| 0 - 10 | Simple module, without much risk | |
| 11 - 20 | More complex module, moderate risk | |
| 21 - 50 | Complex module, high risk | |
| greater than 50 | Untestable module, very high risk |
| Function Name |
Cyclomatic
Complexity |
Number of
Statements |
Number of
Lines |
Source File | |
| ↓ | _gsasl_scram_sha1_server_step | 39 | 139 | 268 | lib/scram/server.c |
int
_gsasl_scram_sha1_server_step (Gsasl_session * sctx,
void *mech_data,
const char *input,
size_t input_len,
char **output, size_t * output_len)
{
struct scram_server_state *state = mech_data;
int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
int rc;
*output = NULL;
*output_len = 0;
switch (state->step)
{
case 0:
{
if (input_len == 0)
return GSASL_NEEDS_MORE;
if (scram_parse_client_first (input, input_len, &state->cf) < 0)
return GSASL_MECHANISM_PARSE_ERROR;
/* We don't support channel bindings. */
if (state->cf.cbflag != 'n')
return GSASL_AUTHENTICATION_ERROR;
/* Check that username doesn't fail SASLprep. */
{
char *tmp;
rc = gsasl_saslprep (state->cf.username, GSASL_ALLOW_UNASSIGNED,
&tmp, NULL);
if (rc != GSASL_OK || *tmp == '\0')
return GSASL_AUTHENTICATION_ERROR;
gsasl_free (tmp);
}
{
const char *p;
/* Save "bare" for next step. */
p = memchr (input, ',', input_len);
if (!p)
return GSASL_AUTHENTICATION_ERROR;
p++;
p = memchr (p, ',', input_len - (p - input));
if (!p)
return GSASL_AUTHENTICATION_ERROR;
p++;
state->cfmb_str = malloc (input_len - (p - input) + 1);
if (!state->cfmb_str)
return GSASL_MALLOC_ERROR;
memcpy (state->cfmb_str, p, input_len - (p - input));
state->cfmb_str[input_len - (p - input)] = '\0';
}
/* Create new nonce. */
{
size_t cnlen = strlen (state->cf.client_nonce);
state->sf.nonce = malloc (cnlen + SNONCE_ENTROPY_BYTES + 1);
if (!state->sf.nonce)
return GSASL_MALLOC_ERROR;
memcpy (state->sf.nonce, state->cf.client_nonce, cnlen);
memcpy (state->sf.nonce + cnlen, state->snonce,
SNONCE_ENTROPY_BYTES);
state->sf.nonce[cnlen + SNONCE_ENTROPY_BYTES] = '\0';
}
gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username);
gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid);
{
const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER);
if (p)
state->sf.iter = strtoul (p, NULL, 10);
if (!p || state->sf.iter == 0 || state->sf.iter == ULONG_MAX)
state->sf.iter = 4096;
}
{
const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT);
if (p)
{
free (state->sf.salt);
state->sf.salt = strdup (p);
}
}
rc = scram_print_server_first (&state->sf, &state->sf_str);
if (rc != 0)
return GSASL_MALLOC_ERROR;
*output = strdup (state->sf_str);
if (!*output)
return GSASL_MALLOC_ERROR;
*output_len = strlen (*output);
state->step++;
return GSASL_NEEDS_MORE;
break;
}
case 1:
{
if (scram_parse_client_final (input, input_len, &state->cl) < 0)
return GSASL_MECHANISM_PARSE_ERROR;
if (strcmp (state->cl.nonce, state->sf.nonce) != 0)
return GSASL_AUTHENTICATION_ERROR;
/* Base64 decode client proof and check that length matches
SHA-1 size. */
{
size_t len;
rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof),
&state->clientproof, &len);
if (rc != 0)
return rc;
if (len != 20)
return GSASL_MECHANISM_PARSE_ERROR;
}
{
const char *p;
/* Get StoredKey and ServerKey */
if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)))
{
Gc_rc err;
char *salt;
size_t saltlen;
char saltedpassword[20];
char *clientkey;
char *preppasswd;
rc = gsasl_saslprep (p, 0, &preppasswd, NULL);
if (rc != GSASL_OK)
return rc;
rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
&salt, &saltlen);
if (rc != 0)
{
gsasl_free (preppasswd);
return rc;
}
/* SaltedPassword := Hi(password, salt) */
err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd),
salt, saltlen,
state->sf.iter, saltedpassword, 20);
gsasl_free (preppasswd);
gsasl_free (salt);
if (err != GC_OK)
return GSASL_MALLOC_ERROR;
/* ClientKey := HMAC(SaltedPassword, "Client Key") */
#define CLIENT_KEY "Client Key"
rc = gsasl_hmac_sha1 (saltedpassword, 20,
CLIENT_KEY, strlen (CLIENT_KEY),
&clientkey);
if (rc != 0)
return rc;
/* StoredKey := H(ClientKey) */
rc = gsasl_sha1 (clientkey, 20, &state->storedkey);
free (clientkey);
if (rc != 0)
return rc;
/* ServerKey := HMAC(SaltedPassword, "Server Key") */
#define SERVER_KEY "Server Key"
rc = gsasl_hmac_sha1 (saltedpassword, 20,
SERVER_KEY, strlen (SERVER_KEY),
&state->serverkey);
if (rc != 0)
return rc;
}
else
return GSASL_NO_PASSWORD;
/* Compute AuthMessage */
{
size_t len;
int n;
/* Get client-final-message-without-proof. */
p = memmem (input, input_len, ",p=", 3);
if (!p)
return GSASL_MECHANISM_PARSE_ERROR;
len = p - input;
n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
state->cfmb_str,
strlen (state->sf_str), state->sf_str,
len, input);
if (n <= 0 || !state->authmessage)
return GSASL_MALLOC_ERROR;
}
/* Check client proof. */
{
char *clientsignature;
char *maybe_storedkey;
/* ClientSignature := HMAC(StoredKey, AuthMessage) */
rc = gsasl_hmac_sha1 (state->storedkey, 20,
state->authmessage,
strlen (state->authmessage),
&clientsignature);
if (rc != 0)
return rc;
/* ClientKey := ClientProof XOR ClientSignature */
memxor (clientsignature, state->clientproof, 20);
rc = gsasl_sha1 (clientsignature, 20, &maybe_storedkey);
free (clientsignature);
if (rc != 0)
return rc;
rc = memcmp (state->storedkey, maybe_storedkey, 20);
free (maybe_storedkey);
if (rc != 0)
return GSASL_AUTHENTICATION_ERROR;
}
/* Generate server verifier. */
{
char *serversignature;
/* ServerSignature := HMAC(ServerKey, AuthMessage) */
rc = gsasl_hmac_sha1 (state->serverkey, 20,
state->authmessage,
strlen (state->authmessage),
&serversignature);
if (rc != 0)
return rc;
rc = gsasl_base64_to (serversignature, 20,
&state->sl.verifier, NULL);
free (serversignature);
if (rc != 0)
return rc;
}
}
rc = scram_print_server_final (&state->sl, output);
if (rc != 0)
return GSASL_MALLOC_ERROR;
*output_len = strlen (*output);
state->step++;
return GSASL_OK;
break;
}
default:
break;
}
return res;
}
|
|||||
| ↓ | digest_md5_print_response | 38 | 86 | 146 | lib/digest-md5/printer.c |
char *
digest_md5_print_response (digest_md5_response * r)
{
char *out = NULL;
const char *qop = NULL;
const char *cipher = NULL;
/* Below we assume the mandatory fields are present, verify that
first to avoid crashes. */
if (digest_md5_validate_response (r) != 0)
return NULL;
if (r->qop & DIGEST_MD5_QOP_AUTH_CONF)
qop = "qop=auth-conf";
else if (r->qop & DIGEST_MD5_QOP_AUTH_INT)
qop = "qop=auth-int";
else if (r->qop & DIGEST_MD5_QOP_AUTH)
qop = "qop=auth";
if (r->cipher & DIGEST_MD5_CIPHER_3DES)
cipher = "cipher=3des";
else if (r->cipher & DIGEST_MD5_CIPHER_DES)
cipher = "cipher=des";
else if (r->cipher & DIGEST_MD5_CIPHER_RC4_40)
cipher = "cipher=rc4-40";
else if (r->cipher & DIGEST_MD5_CIPHER_RC4)
cipher = "cipher=rc4";
else if (r->cipher & DIGEST_MD5_CIPHER_RC4_56)
cipher = "cipher=rc4-56";
else if (r->cipher & DIGEST_MD5_CIPHER_AES_CBC)
cipher = "cipher=aes-cbc";
else if (r->cipher & DIGEST_MD5_CIPHER_3DES)
cipher = "cipher=3des";
if (r->username)
if (comma_append (&out, "username", r->username, 1) < 0)
{
free (out);
return NULL;
}
if (r->realm)
if (comma_append (&out, "realm", r->realm, 1) < 0)
{
free (out);
return NULL;
}
if (r->nonce)
if (comma_append (&out, "nonce", r->nonce, 1) < 0)
{
free (out);
return NULL;
}
if (r->cnonce)
if (comma_append (&out, "cnonce", r->cnonce, 1) < 0)
{
free (out);
return NULL;
}
if (r->nc)
{
char *tmp;
if (asprintf (&tmp, "%08lx", r->nc) < 0)
{
free (out);
return NULL;
}
if (comma_append (&out, "nc", tmp, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
free (tmp);
}
if (qop)
if (comma_append (&out, qop, NULL, 0) < 0)
{
free (out);
return NULL;
}
if (r->digesturi)
if (comma_append (&out, "digest-uri", r->digesturi, 1) < 0)
{
free (out);
return NULL;
}
if (r->response)
if (comma_append (&out, "response", r->response, 0) < 0)
{
free (out);
return NULL;
}
if (r->clientmaxbuf)
{
char *tmp;
if (asprintf (&tmp, "%lu", r->clientmaxbuf) < 0)
{
free (out);
return NULL;
}
if (comma_append (&out, "maxbuf", tmp, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
free (tmp);
}
if (r->utf8)
if (comma_append (&out, "charset", "utf-8", 0) < 0)
{
free (out);
return NULL;
}
if (cipher)
if (comma_append (&out, cipher, NULL, 0) < 0)
{
free (out);
return NULL;
}
if (r->authzid)
if (comma_append (&out, "authzid", r->authzid, 1) < 0)
{
free (out);
return NULL;
}
return out;
}
|
|||||
| ↓ | parse_response | 48 | 95 | 171 | lib/digest-md5/parser.c |
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. <
|
|||||
| ↓ | _gsasl_scram_sha1_client_step | 39 | 140 | 260 | lib/scram/client.c |
int
_gsasl_scram_sha1_client_step (Gsasl_session * sctx,
void *mech_data,
const char *input, size_t input_len,
char **output, size_t * output_len)
{
struct scram_client_state *state = mech_data;
int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
int rc;
*output = NULL;
*output_len = 0;
switch (state->step)
{
case 0:
{
const char *p;
/* We don't support channel bindings. */
state->cf.cbflag = 'n';
p = gsasl_property_get (sctx, GSASL_AUTHID);
if (!p)
return GSASL_NO_AUTHID;
/* FIXME check that final document uses query strings. */
rc = gsasl_saslprep (p, GSASL_ALLOW_UNASSIGNED,
&state->cf.username, NULL);
if (rc != GSASL_OK)
return rc;
p = gsasl_property_get (sctx, GSASL_AUTHZID);
if (p)
state->cf.authzid = strdup (p);
rc = scram_print_client_first (&state->cf, output);
if (rc == -2)
return GSASL_MALLOC_ERROR;
else if (rc != 0)
return GSASL_AUTHENTICATION_ERROR;
*output_len = strlen (*output);
/* Save "cbind" and "bare" for next step. */
p = strchr (*output, ',');
if (!p)
return GSASL_AUTHENTICATION_ERROR;
p++;
p = strchr (p, ',');
if (!p)
return GSASL_AUTHENTICATION_ERROR;
p++;
rc = gsasl_base64_to (*output, p - *output, &state->cl.cbind, NULL);
if (rc != 0)
return rc;
state->cfmb = strdup (p);
if (!state->cfmb)
return GSASL_MALLOC_ERROR;
/* We are done. */
state->step++;
return GSASL_NEEDS_MORE;
break;
}
case 1:
{
if (scram_parse_server_first (input, input_len, &state->sf) < 0)
return GSASL_MECHANISM_PARSE_ERROR;
if (strlen (state->sf.nonce) < strlen (state->cf.client_nonce) ||
memcmp (state->cf.client_nonce, state->sf.nonce,
strlen (state->cf.client_nonce)) != 0)
return GSASL_AUTHENTICATION_ERROR;
state->cl.nonce = strdup (state->sf.nonce);
if (!state->cl.nonce)
return GSASL_MALLOC_ERROR;
/* Save salt/iter as properties, so that client callback can
access them. */
{
char *str = NULL;
int n;
n = asprintf (&str, "%d", state->sf.iter);
if (n < 0 || str == NULL)
return GSASL_MALLOC_ERROR;
gsasl_property_set (sctx, GSASL_SCRAM_ITER, str);
free (str);
}
gsasl_property_set (sctx, GSASL_SCRAM_SALT, state->sf.salt);
/* Generate ClientProof. */
{
char saltedpassword[20];
char *clientkey;
char *storedkey;
char *clientsignature;
char clientproof[20];
const char *p;
/* Get SaltedPassword. */
p = gsasl_property_get (sctx, GSASL_SCRAM_SALTED_PASSWORD);
if (p && strlen (p) == 40 && hex_p (p))
sha1_hex_to_byte (saltedpassword, p);
else if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)) != NULL)
{
Gc_rc err;
char *salt;
size_t saltlen;
char *preppasswd;
rc = gsasl_saslprep (p, 0, &preppasswd, NULL);
if (rc != GSASL_OK)
return rc;
rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
&salt, &saltlen);
if (rc != 0)
{
gsasl_free (preppasswd);
return rc;
}
/* SaltedPassword := Hi(password, salt) */
err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd),
salt, saltlen,
state->sf.iter, saltedpassword, 20);
gsasl_free (preppasswd);
gsasl_free (salt);
if (err != GC_OK)
return GSASL_MALLOC_ERROR;
}
else
return GSASL_NO_PASSWORD;
/* Get client-final-message-without-proof. */
{
char *cfmwp;
int n;
state->cl.proof = strdup ("p");
rc = scram_print_client_final (&state->cl, &cfmwp);
if (rc != 0)
return GSASL_MALLOC_ERROR;
free (state->cl.proof);
/* Compute AuthMessage */
n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
state->cfmb,
input_len, input,
strlen (cfmwp) - 4,
cfmwp);
free (cfmwp);
if (n <= 0 || !state->authmessage)
return GSASL_MALLOC_ERROR;
}
/* ClientKey := HMAC(SaltedPassword, "Client Key") */
#define CLIENT_KEY "Client Key"
rc = gsasl_hmac_sha1 (saltedpassword, 20,
CLIENT_KEY, strlen (CLIENT_KEY),
&clientkey);
if (rc != 0)
return rc;
/* StoredKey := H(ClientKey) */
rc = gsasl_sha1 (clientkey, 20, &storedkey);
if (rc != 0)
{
free (clientkey);
return rc;
}
/* ClientSignature := HMAC(StoredKey, AuthMessage) */
rc = gsasl_hmac_sha1 (storedkey, 20,
state->authmessage,
strlen (state->authmessage),
&clientsignature);
free (storedkey);
if (rc != 0)
{
free (clientkey);
return rc;
}
/* ClientProof := ClientKey XOR ClientSignature */
memcpy (clientproof, clientkey, 20);
memxor (clientproof, clientsignature, 20);
free (clientkey);
free (clientsignature);
rc = gsasl_base64_to (clientproof, 20, &state->cl.proof, NULL);
if (rc != 0)
return rc;
/* Generate ServerSignature, for comparison in next step. */
{
char *serverkey;
char *serversignature;
/* ServerKey := HMAC(SaltedPassword, "Server Key") */
#define SERVER_KEY "Server Key"
rc = gsasl_hmac_sha1 (saltedpassword, 20,
SERVER_KEY, strlen (SERVER_KEY),
&serverkey);
if (rc != 0)
return rc;
/* ServerSignature := HMAC(ServerKey, AuthMessage) */
rc = gsasl_hmac_sha1 (serverkey, 20,
state->authmessage,
strlen (state->authmessage),
&serversignature);
gsasl_free (serverkey);
if (rc != 0)
return rc;
rc = gsasl_base64_to (serversignature, 20,
&state->serversignature, NULL);
gsasl_free (serversignature);
if (rc != 0)
return rc;
}
}
rc = scram_print_client_final (&state->cl, output);
if (rc != 0)
return GSASL_MALLOC_ERROR;
*output_len = strlen (*output);
state->step++;
return GSASL_NEEDS_MORE;
break;
}
case 2:
{
if (scram_parse_server_final (input, input_len, &state->sl) < 0)
return GSASL_MECHANISM_PARSE_ERROR;
if (strcmp (state->sl.verifier, state->serversignature) != 0)
return GSASL_AUTHENTICATION_ERROR;
state->step++;
return GSASL_OK;
break;
}
default:
break;
}
return res;
}
|
|||||
| ↓ | digest_md5_hmac | 37 | 162 | 236 | lib/digest-md5/digesthmac.c |
int
digest_md5_hmac (char *output, char secret[MD5LEN], const char *nonce,
unsigned long nc, const char *cnonce, digest_md5_qop qop,
const char *authzid, const char *digesturi, int rspauth,
digest_md5_cipher cipher,
char *kic, char *kis, char *kcc, char *kcs)
{
const char *a2string = rspauth ? COLON : A2_PRE;
char nchex[9];
char a1hexhash[2 * MD5LEN];
char a2hexhash[2 * MD5LEN];
char hash[MD5LEN];
char *tmp, *p;
size_t tmplen;
int rc;
int i;
/* A1 */
tmplen = MD5LEN + strlen (COLON) + strlen (nonce) +
strlen (COLON) + strlen (cnonce);
if (authzid && strlen (authzid) > 0)
tmplen += strlen (COLON) + strlen (authzid);
p = tmp = malloc (tmplen);
if (tmp == NULL)
return -1;
memcpy (p, secret, MD5LEN);
p += MD5LEN;
memcpy (p, COLON, strlen (COLON));
p += strlen (COLON);
memcpy (p, nonce, strlen (nonce));
p += strlen (nonce);
memcpy (p, COLON, strlen (COLON));
p += strlen (COLON);
memcpy (p, cnonce, strlen (cnonce));
p += strlen (cnonce);
if (authzid && strlen (authzid) > 0)
{
memcpy (p, COLON, strlen (COLON));
p += strlen (COLON);
memcpy (p, authzid, strlen (authzid));
p += strlen (authzid);
}
rc = gc_md5 (tmp, tmplen, hash);
free (tmp);
if (rc)
return rc;
if (kic)
{
char hash2[MD5LEN];
char q[MD5LEN + DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN];
size_t qlen = MD5LEN + DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN;
memcpy (q, hash, MD5LEN);
memcpy (q + MD5LEN, DERIVE_CLIENT_INTEGRITY_KEY_STRING,
DERIVE_CLIENT_INTEGRITY_KEY_STRING_LEN);
rc = gc_md5 (q, qlen, hash2);
if (rc)
return rc;
memcpy (kic, hash2, MD5LEN);
}
if (kis)
{
char hash2[MD5LEN];
char q[MD5LEN + DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN];
size_t qlen = MD5LEN + DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN;
memcpy (q, hash, MD5LEN);
memcpy (q + MD5LEN, DERIVE_SERVER_INTEGRITY_KEY_STRING,
DERIVE_SERVER_INTEGRITY_KEY_STRING_LEN);
rc = gc_md5 (q, qlen, hash2);
if (rc)
return rc;
memcpy (kis, hash2, MD5LEN);
}
if (kcc)
{
char hash2[MD5LEN];
int n;
char q[MD5LEN + DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN];
if (cipher == DIGEST_MD5_CIPHER_RC4_40)
n = 5;
else if (cipher == DIGEST_MD5_CIPHER_RC4_56)
n = 7;
else
n = MD5LEN;
memcpy (q, hash, n);
memcpy (q + n, DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING,
DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN);
rc = gc_md5 (q, n + DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING_LEN,
hash2);
if (rc)
return rc;
memcpy (kcc, hash2, MD5LEN);
}
if (kcs)
{
char hash2[MD5LEN];
int n;
char q[MD5LEN + DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN];
if (cipher == DIGEST_MD5_CIPHER_RC4_40)
n = 5;
else if (cipher == DIGEST_MD5_CIPHER_RC4_56)
n = 7;
else
n = MD5LEN;
memcpy (q, hash, n);
memcpy (q + n, DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING,
DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN);
rc = gc_md5 (q, n + DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING_LEN,
hash2);
if (rc)
return rc;
memcpy (kcs, hash2, MD5LEN);
}
for (i = 0; i < MD5LEN; i++)
{
a1hexhash[2 * i + 1] = HEXCHAR (hash[i]);
a1hexhash[2 * i + 0] = HEXCHAR (hash[i] >> 4);
}
/* A2 */
tmplen = strlen (a2string) + strlen (digesturi);
if (qop & DIGEST_MD5_QOP_AUTH_INT || qop & DIGEST_MD5_QOP_AUTH_CONF)
tmplen += strlen (A2_POST);
p = tmp = malloc (tmplen);
if (tmp == NULL)
return -1;
memcpy (p, a2string, strlen (a2string));
p += strlen (a2string);
memcpy (p, digesturi, strlen (digesturi));
p += strlen (digesturi);
if (qop & DIGEST_MD5_QOP_AUTH_INT || qop & DIGEST_MD5_QOP_AUTH_CONF)
memcpy (p, A2_POST, strlen (A2_POST));
rc = gc_md5 (tmp, tmplen, hash);
free (tmp);
if (rc)
return rc;
for (i = 0; i < MD5LEN; i++)
{
a2hexhash[2 * i + 1] = HEXCHAR (hash[i]);
a2hexhash[2 * i + 0] = HEXCHAR (hash[i] >> 4);
}
/* response_value */
sprintf (nchex, "%08lx", nc);
tmplen = 2 * MD5LEN + strlen (COLON) + strlen (nonce) + strlen (COLON) +
strlen (nchex) + strlen (COLON) + strlen (cnonce) + strlen (COLON);
if (qop & DIGEST_MD5_QOP_AUTH_CONF)
tmplen += strlen (QOP_AUTH_CONF);
else if (qop & DIGEST_MD5_QOP_AUTH_INT)
tmplen += strlen (QOP_AUTH_INT);
else if (qop & DIGEST_MD5_QOP_AUTH)
tmplen += strlen (QOP_AUTH);
tmplen += strlen (COLON) + 2 * MD5LEN;
p = tmp = malloc (tmplen);
if (tmp == NULL)
return -1;
memcpy (p, a1hexhash, 2 * MD5LEN);
p += 2 * MD5LEN;
memcpy (p, COLON, strlen (COLON));
p += strlen (COLON);
memcpy (p, nonce, strlen (nonce));
p += strlen (nonce);
memcpy (p, COLON, strlen (COLON));
p += strlen (COLON);
memcpy (p, nchex, strlen (nchex));
p += strlen (nchex);
memcpy (p, COLON, strlen (COLON));
p += strlen (COLON);
memcpy (p, cnonce, strlen (cnonce));
p += strlen (cnonce);
memcpy (p, COLON, strlen (COLON));
p += strlen (COLON);
if (qop & DIGEST_MD5_QOP_AUTH_CONF)
{
memcpy (p, QOP_AUTH_CONF, strlen (QOP_AUTH_CONF));
p += strlen (QOP_AUTH_CONF);
}
else if (qop & DIGEST_MD5_QOP_AUTH_INT)
{
memcpy (p, QOP_AUTH_INT, strlen (QOP_AUTH_INT));
p += strlen (QOP_AUTH_INT);
}
else if (qop & DIGEST_MD5_QOP_AUTH)
{
memcpy (p, QOP_AUTH, strlen (QOP_AUTH));
p += strlen (QOP_AUTH);
}
memcpy (p, COLON, strlen (COLON));
p += strlen (COLON);
memcpy (p, a2hexhash, 2 * MD5LEN);
rc = gc_md5 (tmp, tmplen, hash);
free (tmp);
if (rc)
return rc;
for (i = 0; i < MD5LEN; i++)
{
output[2 * i + 1] = HEXCHAR (hash[i]);
output[2 * i + 0] = HEXCHAR (hash[i] >> 4);
}
output[32] = '\0';
return 0;
}
|
|||||
| ↓ | digest_md5_print_challenge | 36 | 94 | 168 | lib/digest-md5/printer.c |
char *
digest_md5_print_challenge (digest_md5_challenge * c)
{
char *out = NULL;
size_t i;
/* Below we assume the mandatory fields are present, verify that
first to avoid crashes. */
if (digest_md5_validate_challenge (c) != 0)
return NULL;
for (i = 0; i < c->nrealms; i++)
{
if (comma_append (&out, "realm", c->realms[i], 1) < 0)
{
free (out);
return NULL;
}
}
if (c->nonce)
if (comma_append (&out, "nonce", c->nonce, 1) < 0)
{
free (out);
return NULL;
}
if (c->qops)
{
char *tmp = NULL;
if (c->qops & DIGEST_MD5_QOP_AUTH)
if (comma_append (&tmp, "auth", NULL, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
if (c->qops & DIGEST_MD5_QOP_AUTH_INT)
if (comma_append (&tmp, "auth-int", NULL, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
if (c->qops & DIGEST_MD5_QOP_AUTH_CONF)
if (comma_append (&tmp, "auth-conf", NULL, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
if (comma_append (&out, "qop", tmp, 1) < 0)
{
free (tmp);
free (out);
return NULL;
}
free (tmp);
}
if (c->stale)
if (comma_append (&out, "stale", "true", 0) < 0)
{
free (out);
return NULL;
}
if (c->servermaxbuf)
{
char *tmp;
if (asprintf (&tmp, "%lu", c->servermaxbuf) < 0)
{
free (out);
return NULL;
}
if (comma_append (&out, "maxbuf", tmp, 0) < 0)
{
free (out);
return NULL;
}
free (tmp);
}
if (c->utf8)
if (comma_append (&out, "charset", "utf-8", 0) < 0)
{
free (out);
return NULL;
}
if (comma_append (&out, "algorithm", "md5-sess", 0) < 0)
{
free (out);
return NULL;
}
if (c->ciphers)
{
char *tmp = NULL;
if (c->ciphers & DIGEST_MD5_CIPHER_3DES)
if (comma_append (&tmp, "3des", NULL, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
if (c->ciphers & DIGEST_MD5_CIPHER_DES)
if (comma_append (&tmp, "des", NULL, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
if (c->ciphers & DIGEST_MD5_CIPHER_RC4_40)
if (comma_append (&tmp, "rc4-40", NULL, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
if (c->ciphers & DIGEST_MD5_CIPHER_RC4)
if (comma_append (&tmp, "rc4", NULL, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
if (c->ciphers & DIGEST_MD5_CIPHER_RC4_56)
if (comma_append (&tmp, "rc4-56", NULL, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
if (c->ciphers & DIGEST_MD5_CIPHER_AES_CBC)
if (comma_append (&tmp, "aes-cbc", NULL, 0) < 0)
{
free (tmp);
free (out);
return NULL;
}
if (comma_append (&out, "cipher", tmp, 1) < 0)
{
free (tmp);
free (out);
return NULL;
}
free (tmp);
}
return out;
}
|
|||||
| ↓ | scram_parse_client_first | 33 | 80 | 122 | lib/scram/parser.c |
int
scram_parse_client_first (const char *str, size_t len,
struct scram_client_first *cf)
{
/* Minimum client first string is 'n,,n=a,r=b'. */
if (strnlen (str, len) < 10)
return -1;
if (len == 0 || *str != 'n')
/* FIXME parse non-'n' cbflags */
return -1;
cf->cbflag = *str;
str++, len--;
if (len == 0 || *str != ',')
return -1;
str++, len--;
if (len == 0)
return -1;
if (*str == 'a')
{
const char *p;
size_t l;
str++, len--;
if (len == 0 || *str != '=')
return -1;
str++, len--;
p = memchr (str, ',', len);
if (!p)
return -1;
l = p - str;
if (len < l)
return -1;
cf->authzid = unescape (str, l);
if (!cf->authzid)
return -1;
str = p;
len -= l;
}
if (len == 0 || *str != ',')
return -1;
str++, len--;
if (len == 0 || *str != 'n')
return -1;
str++, len--;
if (len == 0 || *str != '=')
return -1;
str++, len--;
{
const char *p;
size_t l;
p = memchr (str, ',', len);
if (!p)
return -1;
l = p - str;
if (len < l)
return -1;
cf->username = unescape (str, l);
if (!cf->username)
return -1;
str = p;
len -= l;
}
if (len == 0 || *str != ',')
return -1;
str++, len--;
if (len == 0 || *str != 'r')
return -1;
str++, len--;
if (len == 0 || *str != '=')
return -1;
str++, len--;
{
const char *p;
size_t l;
p = memchr (str, ',', len);
if (!p)
p = str + len;
if (!p)
return -1;
l = p - str;
if (len < l)
return -1;
cf->client_nonce = malloc (l + 1);
if (!cf->client_nonce)
return -1;
memcpy (cf->client_nonce, str, l);
cf->client_nonce[l] = '\0';
str = p;
len -= l;
}
/* FIXME check that any extension fields follow valid syntax. */
if (scram_valid_client_first (cf) < 0)
return -1;
return 0;
}
|
|||||
| ↓ | digest_md5_getsubopt | 33 | 38 | 71 | lib/digest-md5/getsubopt.c |
int
digest_md5_getsubopt (char **optionp,
const char *const *tokens, char **valuep)
{
char *endp, *vstart;
int cnt;
int inside_quote = 0;
if (**optionp == '\0')
return -1;
/* Find end of next token. */
endp = *optionp;
while (*endp != '\0' && (inside_quote || (!inside_quote && *endp != ',')))
{
if (*endp == '"')
inside_quote = !inside_quote;
endp++;
}
/* Find start of value. */
vstart = memchr (*optionp, '=', endp - *optionp);
if (vstart == NULL)
vstart = endp;
/* Try to match the characters between *OPTIONP and VSTART against
one of the TOKENS. */
for (cnt = 0; tokens[cnt] != NULL; ++cnt)
if (memcmp (*optionp, tokens[cnt], vstart - *optionp) == 0
&& tokens[cnt][vstart - *optionp] == '\0')
{
/* We found the current option in TOKENS. */
*valuep = vstart != endp ? vstart + 1 : NULL;
while (*valuep && (**valuep == ' ' ||
**valuep == '\t' ||
**valuep == '\r' ||
**valuep == '\n' || **valuep == '"'))
(*valuep)++;
if (*endp != '\0')
{
*endp = '\0';
*optionp = endp + 1;
}
else
*optionp = endp;
endp--;
while (*endp == ' ' ||
*endp == '\t' ||
*endp == '\r' || *endp == '\n' || *endp == '"')
*endp-- = '\0';
while (**optionp == ' ' ||
**optionp == '\t' || **optionp == '\r' || **optionp == '\n')
(*optionp)++;
return cnt;
}
/* The current suboption does not match any option. */
*valuep = *optionp;
if (*endp != '\0')
*endp++ = '\0';
*optionp = endp;
while (**optionp == ' ' ||
**optionp == '\t' || **optionp == '\r' || **optionp == '\n')
(*optionp)++;
return -1;
}
|
|||||
| ↓ | scram_parse_server_first | 31 | 69 | 108 | lib/scram/parser.c |
int
scram_parse_server_first (const char *str, size_t len,
struct scram_server_first *sf)
{
/* Minimum server first string is 'r=ab,s=biws,i=1'. */
if (strnlen (str, len) < 15)
return -1;
if (len == 0 || *str != 'r')
return -1;
str++, len--;
if (len == 0 || *str != '=')
return -1;
str++, len--;
{
const char *p;
size_t l;
p = memchr (str, ',', len);
if (!p)
return -1;
l = p - str;
if (len < l)
return -1;
sf->nonce = malloc (l + 1);
if (!sf->nonce)
return -1;
memcpy (sf->nonce, str, l);
sf->nonce[l] = '\0';
str = p;
len -= l;
}
if (len == 0 || *str != ',')
return -1;
str++, len--;
if (len == 0 || *str != 's')
return -1;
str++, len--;
if (len == 0 || *str != '=')
return -1;
str++, len--;
{
const char *p;
size_t l;
p = memchr (str, ',', len);
if (!p)
return -1;
l = p - str;
if (len < l)
return -1;
sf->salt = malloc (l + 1);
if (!sf->salt)
return -1;
memcpy (sf->salt, str, l);
sf->salt[l] = '\0';
str = p;
len -= l;
}
if (len == 0 || *str != ',')
return -1;
str++, len--;
if (len == 0 || *str != 'i')
return -1;
str++, len--;
if (len == 0 || *str != '=')
return -1;
str++, len--;
sf->iter = 0;
for (; len > 0 && *str >= '0' && *str <= '9'; str++, len--)
{
size_t last_iter = sf->iter;
sf->iter = sf->iter * 10 + (*str - '0');
/* Protect against wrap arounds. */
if (sf->iter < last_iter)
return -1;
}
if (len > 0 && *str != ',')
return -1;
/* FIXME check that any extension fields follow valid syntax. */
if (scram_valid_server_first (sf) < 0)
return -1;
return 0;
}
|
|||||
| ↓ | parse_challenge | 43 | 95 | 203 | lib/digest-md5/parser.c |
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:
/* <
|
|||||
| ↓ | _gsasl_digest_md5_client_step | 29 | 91 | 185 | lib/digest-md5/client.c |
int
_gsasl_digest_md5_client_step (Gsasl_session * sctx,
void *mech_data,
const char *input,
size_t input_len,
char **output, size_t * output_len)
{
_Gsasl_digest_md5_client_state *state = mech_data;
int rc, res;
*output = NULL;
*output_len = 0;
switch (state->step)
{
case 0:
state->step++;
if (input_len == 0)
return GSASL_NEEDS_MORE;
/* fall through */
case 1:
{
if (digest_md5_parse_challenge (input, input_len,
&state->challenge) < 0)
return GSASL_MECHANISM_PARSE_ERROR;
/* FIXME: How to let application know of remaining realms?
One idea, add a GSASL_REALM_COUNT property, and have the
GSASL_REALM be that many concatenated zero terminated realm
strings. Slightly hackish, though. Another cleaner
approach would be to add gsasl_property_set_array and
gsasl_property_get_array APIs, for those properties that
may be used multiple times. */
if (state->challenge.nrealms > 0)
gsasl_property_set (sctx, GSASL_REALM, state->challenge.realms[0]);
else
gsasl_property_set (sctx, GSASL_REALM, NULL);
/* FIXME: cipher, maxbuf. */
/* Create response token. */
state->response.utf8 = 1;
gsasl_property_set (sctx, GSASL_QOPS,
digest_md5_qops2qopstr (state->challenge.qops));
{
const char *qop = gsasl_property_get (sctx, GSASL_QOP);
if (!qop)
state->response.qop = GSASL_QOP_AUTH;
else if (strcmp (qop, "qop-int") == 0)
state->response.qop = GSASL_QOP_AUTH_INT;
else if (strcmp (qop, "qop-auth") == 0)
state->response.qop = GSASL_QOP_AUTH;
else
/* We don't support confidentiality or unknown
keywords. */
return GSASL_AUTHENTICATION_ERROR;
}
state->response.nonce = strdup (state->challenge.nonce);
if (!state->response.nonce)
return GSASL_MALLOC_ERROR;
{
const char *service = gsasl_property_get (sctx, GSASL_SERVICE);
const char *hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
if (!service)
return GSASL_NO_SERVICE;
if (!hostname)
return GSASL_NO_HOSTNAME;
if (asprintf (&state->response.digesturi, "%s/%s",
service, hostname) < 0)
return GSASL_MALLOC_ERROR;
}
{
const char *c;
char *tmp, *tmp2;
c = gsasl_property_get (sctx, GSASL_AUTHID);
if (!c)
return GSASL_NO_AUTHID;
state->response.username = strdup (c);
if (!state->response.username)
return GSASL_MALLOC_ERROR;
c = gsasl_property_get (sctx, GSASL_AUTHZID);
if (c)
{
state->response.authzid = strdup (c);
if (!state->response.authzid)
return GSASL_MALLOC_ERROR;
}
gsasl_callback (NULL, sctx, GSASL_REALM);
c = gsasl_property_fast (sctx, GSASL_REALM);
if (c)
{
state->response.realm = strdup (c);
if (!state->response.realm)
return GSASL_MALLOC_ERROR;
}
c = gsasl_property_get (sctx, GSASL_PASSWORD);
if (!c)
return GSASL_NO_PASSWORD;
tmp2 = utf8tolatin1ifpossible (c);
rc = asprintf (&tmp, "%s:%s:%s", state->response.username,
state->response.realm ?
state->response.realm : "", tmp2);
free (tmp2);
if (rc < 0)
return GSASL_MALLOC_ERROR;
rc = gsasl_md5 (tmp, strlen (tmp), &tmp2);
free (tmp);
if (rc != GSASL_OK)
return rc;
memcpy (state->secret, tmp2, DIGEST_MD5_LENGTH);
free (tmp2);
}
rc = digest_md5_hmac (state->response.response,
state->secret,
state->response.nonce,
state->response.nc,
state->response.cnonce,
state->response.qop,
state->response.authzid,
state->response.digesturi,
0,
state->response.cipher,
state->kic, state->kis, state->kcc, state->kcs);
if (rc)
return GSASL_CRYPTO_ERROR;
*output = digest_md5_print_response (&state->response);
if (!*output)
return GSASL_AUTHENTICATION_ERROR;
*output_len = strlen (*output);
state->step++;
res = GSASL_NEEDS_MORE;
}
break;
case 2:
{
char check[DIGEST_MD5_RESPONSE_LENGTH + 1];
if (digest_md5_parse_finish (input, input_len, &state->finish) < 0)
return GSASL_MECHANISM_PARSE_ERROR;
res = digest_md5_hmac (check, state->secret,
state->response.nonce, state->response.nc,
state->response.cnonce, state->response.qop,
state->response.authzid,
state->response.digesturi, 1,
state->response.cipher, NULL, NULL, NULL,
NULL);
if (res != GSASL_OK)
break;
if (strcmp (state->finish.rspauth, check) == 0)
res = GSASL_OK;
else
res = GSASL_AUTHENTICATION_ERROR;
state->step++;
}
break;
default:
res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
break;
}
return res;
}
|
|||||
| ↓ | scram_parse_client_final | 27 | 66 | 104 | lib/scram/parser.c |
int
scram_parse_client_final (const char *str, size_t len,
struct scram_client_final *cl)
{
/* Minimum client final string is 'c=biws,r=ab,p=ab=='. */
if (strnlen (str, len) < 18)
return -1;
if (len == 0 || *str != 'c')
return -1;
str++, len--;
if (len == 0 || *str != '=')
return -1;
str++, len--;
{
const char *p;
size_t l;
p = memchr (str, ',', len);
if (!p)
return -1;
l = p - str;
if (len < l)
return -1;
cl->cbind = malloc (l + 1);
if (!cl->cbind)
return -1;
memcpy (cl->cbind, str, l);
cl->cbind[l] = '\0';
str = p;
len -= l;
}
if (len == 0 || *str != ',')
return -1;
str++, len--;
if (len == 0 || *str != 'r')
return -1;
str++, len--;
if (len == 0 || *str != '=')
return -1;
str++, len--;
{
const char *p;
size_t l;
p = memchr (str, ',', len);
if (!p)
return -1;
l = p - str;
if (len < l)
return -1;
cl->nonce = malloc (l + 1);
if (!cl->nonce)
return -1;
memcpy (cl->nonce, str, l);
cl->nonce[l] = '\0';
str = p;
len -= l;
}
/* FIXME check that any extension fields follow valid syntax. */
if (len == 0 || *str != ',')
return -1;
str++, len--;
if (len == 0 || *str != 'p')
return -1;
str++, len--;
if (len == 0 || *str != '=')
return -1;
str++, len--;
/* Sanity check proof. */
if (memchr (str, '\0', len))
return -1;
cl->proof = malloc (len + 1);
if (!cl->proof)
return -1;
memcpy (cl->proof, str, len);
cl->proof[len] = '\0';
if (scram_valid_client_final (cl) < 0)
return -1;
return 0;
}
|
|||||
| ↓ | _gsasl_digest_md5_server_step | 27 | 92 | 192 | lib/digest-md5/server.c |
int
_gsasl_digest_md5_server_step (Gsasl_session * sctx,
void *mech_data,
const char *input,
size_t input_len,
char **output, size_t * output_len)
{
_Gsasl_digest_md5_server_state *state = mech_data;
int rc, res;
*output = NULL;
*output_len = 0;
switch (state->step)
{
case 0:
/* Set realm. */
{
const char *c;
c = gsasl_property_get (sctx, GSASL_REALM);
if (c)
{
state->challenge.nrealms = 1;
state->challenge.realms =
malloc (sizeof (*state->challenge.realms));
if (!state->challenge.realms)
return GSASL_MALLOC_ERROR;
state->challenge.realms[0] = strdup (c);
if (!state->challenge.realms[0])
return GSASL_MALLOC_ERROR;
}
}
/* Set QOP */
{
const char *qopstr = gsasl_property_get (sctx, GSASL_QOPS);
if (qopstr)
{
int qops = digest_md5_qopstr2qops (qopstr);
if (qops == -1)
return GSASL_MALLOC_ERROR;
/* We don't support confidentiality right now. */
if (qops & DIGEST_MD5_QOP_AUTH_CONF)
return GSASL_AUTHENTICATION_ERROR;
if (qops)
state->challenge.qops = qops;
}
}
/* FIXME: cipher, maxbuf, more realms. */
/* Create challenge. */
*output = digest_md5_print_challenge (&state->challenge);
if (!*output)
return GSASL_AUTHENTICATION_ERROR;
*output_len = strlen (*output);
state->step++;
res = GSASL_NEEDS_MORE;
break;
case 1:
if (digest_md5_parse_response (input, input_len, &state->response) < 0)
return GSASL_MECHANISM_PARSE_ERROR;
/* Make sure response is consistent with challenge. */
if (digest_md5_validate (&state->challenge, &state->response) < 0)
return GSASL_MECHANISM_PARSE_ERROR;
/* Store properties, from the client response. */
if (state->response.utf8)
{
gsasl_property_set (sctx, GSASL_AUTHID, state->response.username);
gsasl_property_set (sctx, GSASL_REALM, state->response.realm);
}
else
{
/* Client provided username/realm in ISO-8859-1 form,
convert it to UTF-8 since the library is all-UTF-8. */
char *tmp;
tmp = latin1toutf8 (state->response.username);
if (!tmp)
return GSASL_MALLOC_ERROR;
gsasl_property_set (sctx, GSASL_AUTHID, tmp);
free (tmp);
tmp = latin1toutf8 (state->response.realm);
if (!tmp)
return GSASL_MALLOC_ERROR;
gsasl_property_set (sctx, GSASL_REALM, tmp);
free (tmp);
}
gsasl_property_set (sctx, GSASL_AUTHZID, state->response.authzid);
/* FIXME: cipher, maxbuf. */
/* Compute secret. */
{
const char *passwd;
const char *hashed_passwd;
hashed_passwd =
gsasl_property_get (sctx, GSASL_DIGEST_MD5_HASHED_PASSWORD);
if (hashed_passwd)
{
if (strlen (hashed_passwd) != (DIGEST_MD5_LENGTH * 2))
return GSASL_AUTHENTICATION_ERROR;
rc = _gsasl_digest_md5_set_hashed_secret (state->secret,
hashed_passwd);
if (rc != GSASL_OK)
return rc;
}
else if ((passwd = gsasl_property_get (sctx, GSASL_PASSWORD)) != NULL)
{
char *tmp, *tmp2;
tmp2 = utf8tolatin1ifpossible (passwd);
rc = asprintf (&tmp, "%s:%s:%s", state->response.username,
state->response.realm ?
state->response.realm : "", tmp2);
free (tmp2);
if (rc < 0)
return GSASL_MALLOC_ERROR;
rc = gsasl_md5 (tmp, strlen (tmp), &tmp2);
free (tmp);
if (rc != GSASL_OK)
return rc;
memcpy (state->secret, tmp2, DIGEST_MD5_LENGTH);
free (tmp2);
}
else
{
return GSASL_NO_PASSWORD;
}
}
/* Check client response. */
{
char check[DIGEST_MD5_RESPONSE_LENGTH + 1];
rc = digest_md5_hmac (check, state->secret,
state->response.nonce, state->response.nc,
state->response.cnonce, state->response.qop,
state->response.authzid,
state->response.digesturi, 0,
state->response.cipher,
state->kic, state->kis, state->kcc, state->kcs);
if (rc)
return GSASL_AUTHENTICATION_ERROR;
if (strcmp (state->response.response, check) != 0)
return GSASL_AUTHENTICATION_ERROR;
}
/* Create finish token. */
rc = digest_md5_hmac (state->finish.rspauth, state->secret,
state->response.nonce, state->response.nc,
state->response.cnonce, state->response.qop,
state->response.authzid,
state->response.digesturi, 1,
state->response.cipher, NULL, NULL, NULL, NULL);
if (rc)
return GSASL_AUTHENTICATION_ERROR;
*output = digest_md5_print_finish (&state->finish);
if (!*output)
return GSASL_MALLOC_ERROR;
*output_len = strlen (*output);
state->step++;
res = GSASL_OK;
break;
default:
res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
break;
}
return res;
}
|
|||||
| ↓ | _gsasl_gssapi_client_step | 24 | 91 | 178 | lib/gssapi/client.c |
int
_gsasl_gssapi_client_step (Gsasl_session * sctx,
void *mech_data,
const char *input, size_t input_len,
char **output, size_t * output_len)
{
_Gsasl_gssapi_client_state *state = mech_data;
char clientwrap[4];
gss_qop_t serverqop;
gss_buffer_desc bufdesc, bufdesc2;
gss_buffer_t buf = GSS_C_NO_BUFFER;
OM_uint32 maj_stat, min_stat;
int conf_state;
int res;
const char *p;
if (state->service == NULL)
{
const char *service, *hostname;
service = gsasl_property_get (sctx, GSASL_SERVICE);
if (!service)
return GSASL_NO_SERVICE;
hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
if (!hostname)
return GSASL_NO_HOSTNAME;
/* FIXME: Use asprintf. */
bufdesc.length = strlen (service) + 1 + strlen (hostname) + 1;
bufdesc.value = malloc (bufdesc.length);
if (bufdesc.value == NULL)
return GSASL_MALLOC_ERROR;
sprintf (bufdesc.value, "%s@%s", service, hostname);
maj_stat = gss_import_name (&min_stat, &bufdesc,
GSS_C_NT_HOSTBASED_SERVICE,
&state->service);
free (bufdesc.value);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_IMPORT_NAME_ERROR;
}
switch (state->step)
{
case 1:
bufdesc.length = input_len;
bufdesc.value = (void *) input;
buf = &bufdesc;
/* fall through */
case 0:
bufdesc2.length = 0;
bufdesc2.value = NULL;
maj_stat = gss_init_sec_context (&min_stat,
GSS_C_NO_CREDENTIAL,
&state->context,
state->service,
GSS_C_NO_OID,
GSS_C_MUTUAL_FLAG |
GSS_C_REPLAY_FLAG |
GSS_C_SEQUENCE_FLAG |
GSS_C_INTEG_FLAG |
GSS_C_CONF_FLAG,
0,
GSS_C_NO_CHANNEL_BINDINGS,
buf, NULL, &bufdesc2, NULL, NULL);
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR;
*output_len = bufdesc2.length;
*output = malloc (*output_len);
if (!*output)
return GSASL_MALLOC_ERROR;
memcpy (*output, bufdesc2.value, bufdesc2.length);
if (maj_stat == GSS_S_COMPLETE)
state->step = 2;
else
state->step = 1;
maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
if (maj_stat != GSS_S_COMPLETE)
return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
res = GSASL_NEEDS_MORE;
break;
case 2:
/* [RFC 2222 section 7.2.1]:
The client passes this token to GSS_Unwrap and interprets the
first octet of resulting cleartext as a bit-mask specifying
the security layers supported by the server and the second
through fourth octets as the maximum size output_message to
send to the server. The client then constructs data, with
the first octet containing the bit-mask specifying the
selected security layer, the second through fourth octets
containing in network byte order the maximum size
output_message the client is able to receive, and the
remaining octets containing the authorization identity. The
client passes the data to GSS_Wrap with conf_flag set to
FALSE, and responds with the generated output_message. The
client can then consider the server authenticated. */
bufdesc.length = input_len;
bufdesc.value = (void *) input;
maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc,
&bufdesc2, &conf_state, &serverqop);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_UNWRAP_ERROR;
if (bufdesc2.length != 4)
return GSASL_MECHANISM_PARSE_ERROR;
memcpy (clientwrap, bufdesc2.value, 4);
maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
#if 0
/* FIXME: Fix qop. */
if (cb_qop)
state->qop = cb_qop (sctx, serverqop);
if ((state->qop & serverqop) == 0)
/* Server does not support what user wanted. */
return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
#endif
/* FIXME: Fix maxbuf. */
p = gsasl_property_get (sctx, GSASL_AUTHID);
if (!p)
return GSASL_NO_AUTHID;
bufdesc.length = 4 + strlen (p);
bufdesc.value = malloc (bufdesc.length);
if (!bufdesc.value)
return GSASL_MALLOC_ERROR;
{
char *q = bufdesc.value;
q[0] = state->qop;
memcpy (q + 1, clientwrap + 1, 3);
memcpy (q + 4, p, strlen (p));
}
maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
&bufdesc, &conf_state, &bufdesc2);
free (bufdesc.value);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_WRAP_ERROR;
*output_len = bufdesc2.length;
*output = malloc (bufdesc2.length);
if (!*output)
return GSASL_MALLOC_ERROR;
memcpy (*output, bufdesc2.value, bufdesc2.length);
maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
state->step++;
res = GSASL_OK;
break;
default:
res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
break;
}
return res;
}
|
|||||
| ↓ | _gsasl_gssapi_server_step | 19 | 73 | 146 | lib/gssapi/server.c |
int
_gsasl_gssapi_server_step (Gsasl_session * sctx,
void *mech_data,
const char *input, size_t input_len,
char **output, size_t * output_len)
{
_Gsasl_gssapi_server_state *state = mech_data;
gss_buffer_desc bufdesc1, bufdesc2;
OM_uint32 maj_stat, min_stat;
gss_buffer_desc client_name;
gss_OID mech_type;
char tmp[4];
int res;
*output = NULL;
*output_len = 0;
switch (state->step)
{
case 0:
if (input_len == 0)
{
res = GSASL_NEEDS_MORE;
break;
}
state->step++;
/* fall through */
case 1:
bufdesc1.value = (void *) input;
bufdesc1.length = input_len;
if (state->client)
{
gss_release_name (&min_stat, &state->client);
state->client = GSS_C_NO_NAME;
}
maj_stat = gss_accept_sec_context (&min_stat,
&state->context,
state->cred,
&bufdesc1,
GSS_C_NO_CHANNEL_BINDINGS,
&state->client,
&mech_type,
&bufdesc2, NULL, NULL, NULL);
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR;
*output = malloc (bufdesc2.length);
if (!*output)
return GSASL_MALLOC_ERROR;
memcpy (*output, bufdesc2.value, bufdesc2.length);
*output_len = bufdesc2.length;
maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
if (maj_stat == GSS_S_COMPLETE)
state->step++;
res = GSASL_NEEDS_MORE;
break;
case 2:
memset (tmp, 0xFF, 4);
tmp[0] = GSASL_QOP_AUTH;
bufdesc1.length = 4;
bufdesc1.value = tmp;
maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
&bufdesc1, NULL, &bufdesc2);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_WRAP_ERROR;
*output = malloc (bufdesc2.length);
if (!*output)
return GSASL_MALLOC_ERROR;
memcpy (*output, bufdesc2.value, bufdesc2.length);
*output_len = bufdesc2.length;
maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
state->step++;
res = GSASL_NEEDS_MORE;
break;
case 3:
bufdesc1.value = (void *) input;
bufdesc1.length = input_len;
maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc1,
&bufdesc2, NULL, NULL);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_UNWRAP_ERROR;
/* [RFC 2222 section 7.2.1]:
The client passes this token to GSS_Unwrap and interprets the
first octet of resulting cleartext as a bit-mask specifying
the security layers supported by the server and the second
through fourth octets as the maximum size output_message to
send to the server. The client then constructs data, with
the first octet containing the bit-mask specifying the
selected security layer, the second through fourth octets
containing in network byte order the maximum size
output_message the client is able to receive, and the
remaining octets containing the authorization identity. The
client passes the data to GSS_Wrap with conf_flag set to
FALSE, and responds with the generated output_message. The
client can then consider the server authenticated. */
if ((((char *) bufdesc2.value)[0] & GSASL_QOP_AUTH) == 0)
{
/* Integrity or privacy unsupported */
maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
}
gsasl_property_set_raw (sctx, GSASL_AUTHZID,
(char *) bufdesc2.value + 4,
bufdesc2.length - 4);
maj_stat = gss_display_name (&min_stat, state->client,
&client_name, &mech_type);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_DISPLAY_NAME_ERROR;
gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME,
client_name.value, client_name.length);
maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);
state->step++;
break;
default:
res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
break;
}
return res;
}
|
|||||
| ↓ | _gsasl_gs2_server_step | 18 | 65 | 128 | lib/gs2/server.c |
int
_gsasl_gs2_server_step (Gsasl_session * sctx,
void *mech_data,
const char *input, size_t input_len,
char **output, size_t * output_len)
{
_Gsasl_gs2_server_state *state = mech_data;
gss_buffer_desc bufdesc1, bufdesc2;
OM_uint32 maj_stat, min_stat;
gss_buffer_desc client_name;
gss_OID mech_type;
int res;
OM_uint32 ret_flags;
int free_bufdesc1 = 0;
*output = NULL;
*output_len = 0;
bufdesc1.value = input;
bufdesc1.length = input_len;
switch (state->step)
{
case 0:
if (input_len == 0)
{
res = GSASL_NEEDS_MORE;
break;
}
state->step++;
/* fall through */
case 1:
{
char *authzid;
size_t headerlen;
res = parse_gs2_header (input, input_len, &authzid, &headerlen);
if (res != GSASL_OK)
return res;
if (authzid)
{
gsasl_property_set (sctx, GSASL_AUTHZID, authzid);
free (authzid);
}
state->cb.application_data.value = input;
state->cb.application_data.length = headerlen;
bufdesc2.value = input + headerlen;
bufdesc2.length = input_len - headerlen;
maj_stat = gss_encapsulate_token (&bufdesc2, state->mech_oid,
&bufdesc1);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_ENCAPSULATE_TOKEN_ERROR;
free_bufdesc1 = 1;
}
state->step++;
/* fall through */
case 2:
if (state->client)
{
gss_release_name (&min_stat, &state->client);
state->client = GSS_C_NO_NAME;
}
maj_stat = gss_accept_sec_context (&min_stat,
&state->context,
state->cred,
&bufdesc1,
&state->cb,
&state->client,
&mech_type,
&bufdesc2,
&ret_flags,
NULL,
NULL);
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR;
if (maj_stat == GSS_S_COMPLETE)
{
state->step++;
if (!(ret_flags & GSS_C_MUTUAL_FLAG))
return GSASL_MECHANISM_PARSE_ERROR;
maj_stat = gss_display_name (&min_stat, state->client,
&client_name, &mech_type);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_DISPLAY_NAME_ERROR;
gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME,
client_name.value, client_name.length);
res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);
}
else
res = GSASL_NEEDS_MORE;
if (free_bufdesc1)
{
maj_stat = gss_release_buffer (&min_stat, &bufdesc1);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
}
*output = malloc (bufdesc2.length);
if (!*output)
return GSASL_MALLOC_ERROR;
memcpy (*output, bufdesc2.value, bufdesc2.length);
*output_len = bufdesc2.length;
maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
break;
default:
res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
break;
}
return res;
}
|
|||||
| ↓ | _gsasl_securid_client_step | 18 | 59 | 106 | lib/securid/client.c |
int
_gsasl_securid_client_step (Gsasl_session * sctx,
void *mech_data,
const char *input,
size_t input_len,
char **output, size_t * output_len)
{
int *step = mech_data;
const char *authzid = NULL, *authid = NULL, *passcode = NULL, *pin = NULL;
size_t authzidlen, authidlen, passcodelen, pinlen = 0;
int do_pin = 0;
int res;
switch (*step)
{
case 1:
if (input_len == strlen (PASSCODE) &&
memcmp (input, PASSCODE, strlen (PASSCODE)) == 0)
{
*step = 0;
}
else if (input_len >= strlen (PIN) &&
memcmp (input, PIN, strlen (PIN)) == 0)
{
do_pin = 1;
*step = 0;
}
else
{
*output_len = 0;
res = GSASL_OK;
break;
}
/* fall through */
case 0:
authzid = gsasl_property_get (sctx, GSASL_AUTHZID);
if (authzid)
authzidlen = strlen (authzid);
else
authzidlen = 0;
authid = gsasl_property_get (sctx, GSASL_AUTHID);
if (!authid)
return GSASL_NO_AUTHID;
authidlen = strlen (authid);
passcode = gsasl_property_get (sctx, GSASL_PASSCODE);
if (!passcode)
return GSASL_NO_PASSCODE;
passcodelen = strlen (passcode);
if (do_pin)
{
if (input_len > strlen (PIN))
gsasl_property_set_raw (sctx, GSASL_SUGGESTED_PIN,
&input[strlen (PIN)],
input_len - strlen (PIN));
pin = gsasl_property_get (sctx, GSASL_PIN);
if (!pin)
return GSASL_NO_PIN;
pinlen = strlen (pin);
}
*output_len = authzidlen + 1 + authidlen + 1 + passcodelen + 1;
if (do_pin)
*output_len += pinlen + 1;
*output = malloc (*output_len);
if (*output == NULL)
return GSASL_MALLOC_ERROR;
if (authzid)
memcpy (*output, authzid, authzidlen);
(*output)[authzidlen] = '\0';
memcpy (*output + authzidlen + 1, authid, authidlen);
(*output)[authzidlen + 1 + authidlen] = '\0';
memcpy (*output + authzidlen + 1 + authidlen + 1, passcode,
passcodelen);
(*output)[authzidlen + 1 + authidlen + 1 + passcodelen] = '\0';
if (do_pin)
{
memcpy (*output + authzidlen + 1 + authidlen + 1 + passcodelen + 1,
pin, pinlen);
(*output)[authzidlen + 1 + authidlen + 1 + passcodelen + 1 +
pinlen] = '\0';
}
(*step)++;
res = GSASL_OK;
break;
case 2:
*output_len = 0;
*output = NULL;
(*step)++;
res = GSASL_OK;
break;
default:
res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
break;
}
return res;
}
|
|||||
| ↓ | _gsasl_securid_server_step | 15 | 55 | 89 | lib/securid/server.c |
int
_gsasl_securid_server_step (Gsasl_session * sctx,
void *mech_data,
const char *input, size_t input_len,
char **output, size_t * output_len)
{
const char *authorization_id = NULL;
const char *authentication_id = NULL;
const char *passcode = NULL;
const char *suggestedpin;
char *pin = NULL;
int res;
size_t len;
if (input_len == 0)
{
*output_len = 0;
*output = NULL;
return GSASL_NEEDS_MORE;
}
authorization_id = input;
authentication_id = memchr (input, '\0', input_len - 1);
if (authentication_id)
{
authentication_id++;
passcode = memchr (authentication_id, '\0',
input_len - strlen (authorization_id) - 1 - 1);
if (passcode)
{
passcode++;
pin = memchr (passcode, '\0', input_len -
strlen (authorization_id) - 1 -
strlen (authentication_id) - 1 - 1);
if (pin)
{
pin++;
if (pin && !*pin)
pin = NULL;
}
}
}
if (passcode == NULL)
return GSASL_MECHANISM_PARSE_ERROR;
gsasl_property_set (sctx, GSASL_AUTHID, authentication_id);
gsasl_property_set (sctx, GSASL_AUTHZID, authorization_id);
gsasl_property_set (sctx, GSASL_PASSCODE, passcode);
if (pin)
gsasl_property_set (sctx, GSASL_PIN, pin);
else
gsasl_property_set (sctx, GSASL_PIN, NULL);
res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_SECURID);
switch (res)
{
case GSASL_SECURID_SERVER_NEED_ADDITIONAL_PASSCODE:
*output = strdup (PASSCODE);
if (!*output)
return GSASL_MALLOC_ERROR;
*output_len = strlen (PASSCODE);
res = GSASL_NEEDS_MORE;
break;
case GSASL_SECURID_SERVER_NEED_NEW_PIN:
suggestedpin = gsasl_property_get (sctx, GSASL_SUGGESTED_PIN);
if (suggestedpin)
len = strlen (suggestedpin);
else
len = 0;
*output_len = strlen (PIN) + len;
*output = malloc (*output_len);
if (!*output)
return GSASL_MALLOC_ERROR;
memcpy (*output, PIN, strlen (PIN));
if (suggestedpin)
memcpy (*output + strlen (PIN), suggestedpin, len);
res = GSASL_NEEDS_MORE;
break;
default:
*output_len = 0;
*output = NULL;
break;
}
return res;
}
|
|||||
| ↓ | _gsasl_login_server_step | 15 | 50 | 87 | lib/login/server.c |
int
_gsasl_login_server_step (Gsasl_session * sctx,
void *mech_data,
const char *input, size_t input_len,
char **output, size_t * output_len)
{
struct _Gsasl_login_server_state *state = mech_data;
int res;
switch (state->step)
{
case 0:
*output = strdup (CHALLENGE_USERNAME);
if (!*output)
return GSASL_MALLOC_ERROR;
*output_len = strlen (CHALLENGE_USERNAME);
state->step++;
res = GSASL_NEEDS_MORE;
break;
case 1:
if (input_len == 0)
return GSASL_MECHANISM_PARSE_ERROR;
state->username = malloc (input_len + 1);
if (state->username == NULL)
return GSASL_MALLOC_ERROR;
memcpy (state->username, input, input_len);
state->username[input_len] = '\0';
*output = strdup (CHALLENGE_PASSWORD);
if (!*output)
return GSASL_MALLOC_ERROR;
*output_len = strlen (CHALLENGE_PASSWORD);
state->step++;
res = GSASL_NEEDS_MORE;
break;
case 2:
if (input_len == 0)
return GSASL_MECHANISM_PARSE_ERROR;
state->password = malloc (input_len + 1);
if (state->password == NULL)
return GSASL_MALLOC_ERROR;
memcpy (state->password, input, input_len);
state->password[input_len] = '\0';
if (input_len != strlen (state->password))
return GSASL_MECHANISM_PARSE_ERROR;
gsasl_property_set (sctx, GSASL_AUTHID, state->username);
gsasl_property_set (sctx, GSASL_PASSWORD, state->password);
res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_SIMPLE);
if (res == GSASL_NO_CALLBACK)
{
const char *key;
gsasl_property_set (sctx, GSASL_AUTHZID, NULL);
gsasl_property_set (sctx, GSASL_PASSWORD, NULL);
key = gsasl_property_get (sctx, GSASL_PASSWORD);
if (key && strlen (state->password) == strlen (key) &&
strcmp (state->password, key) == 0)
res = GSASL_OK;
else
res = GSASL_AUTHENTICATION_ERROR;
}
*output_len = 0;
*output = NULL;
state->step++;
break;
default:
res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
break;
}
return res;
}
|
|||||
| ↓ | _gsasl_plain_server_step | 13 | 59 | 114 | lib/plain/server.c |
int
_gsasl_plain_server_step (Gsasl_session * sctx,
void *mech_data,
const char *input, size_t input_len,
char **output, size_t * output_len)
{
const char *authzidptr = input;
char *authidptr = NULL;
char *passwordptr = NULL;
char *passwdz = NULL, *passprep = NULL, *authidprep = NULL;
int res;
*output_len = 0;
*output = NULL;
if (input_len == 0)
return GSASL_NEEDS_MORE;
/* Parse input. */
{
size_t tmplen;
authidptr = memchr (input, 0, input_len - 1);
if (authidptr)
{
authidptr++;
passwordptr = memchr (authidptr, 0, input_len - strlen (input) - 1);
if (passwordptr)
passwordptr++;
else
return GSASL_MECHANISM_PARSE_ERROR;
}
else
return GSASL_MECHANISM_PARSE_ERROR;
/* As the NUL (U+0000) character is used as a deliminator, the NUL
(U+0000) character MUST NOT appear in authzid, authcid, or passwd
productions. */
tmplen = input_len - (size_t) (passwordptr - input);
if (memchr (passwordptr, 0, tmplen))
return GSASL_MECHANISM_PARSE_ERROR;
}
/* Store authid, after preparing it... */
{
res = gsasl_saslprep (authidptr, GSASL_ALLOW_UNASSIGNED,
&authidprep, NULL);
if (res != GSASL_OK)
return res;
gsasl_property_set (sctx, GSASL_AUTHID, authidprep);
/* Store authzid, if absent, use SASLprep(authcid). */
if (*authzidptr == '\0')
gsasl_property_set (sctx, GSASL_AUTHZID, authidprep);
else
gsasl_property_set (sctx, GSASL_AUTHZID, authzidptr);
free (authidprep);
}
/* Store passwd, after preparing it... */
{
size_t passwdzlen = input_len - (size_t) (passwordptr - input);
/* Need to zero terminate password... */
passwdz = malloc (passwdzlen + 1);
if (passwdz == NULL)
return GSASL_MALLOC_ERROR;
memcpy (passwdz, passwordptr, passwdzlen);
passwdz[passwdzlen] = '\0';
res = gsasl_saslprep (passwdz, GSASL_ALLOW_UNASSIGNED, &passprep, NULL);
free (passwdz);
if (res != GSASL_OK)
return res;
gsasl_property_set (sctx, GSASL_PASSWORD, passprep);
}
/* Authorization. Let application verify credentials internally,
but fall back to deal with it locally... */
res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_SIMPLE);
if (res == GSASL_NO_CALLBACK)
{
const char *key;
char *normkey;
gsasl_property_set (sctx, GSASL_PASSWORD, NULL);
key = gsasl_property_get (sctx, GSASL_PASSWORD);
if (!key)
{
free (passprep);
return GSASL_NO_PASSWORD;
}
/* Unassigned code points are not permitted. */
res = gsasl_saslprep (key, 0, &normkey, NULL);
if (res != GSASL_OK)
{
free (passprep);
return res;
}
if (strcmp (normkey, passprep) == 0)
res = GSASL_OK;
else
res = GSASL_AUTHENTICATION_ERROR;
free (normkey);
}
free (passprep);
return res;
}
|
|||||
| ↓ | _gsasl_gs2_client_step | 13 | 37 | 74 | lib/gs2/client.c |
int
_gsasl_gs2_client_step (Gsasl_session * sctx,
void *mech_data,
const char *input, size_t input_len,
char **output, size_t * output_len)
{
_gsasl_gs2_client_state *state = mech_data;
gss_buffer_desc bufdesc;
gss_buffer_t buf = GSS_C_NO_BUFFER;
OM_uint32 maj_stat, min_stat, ret_flags;
gss_OID actual_mech_type;
int res;
if (state->step > 2)
return GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
if (state->step == 0)
{
res = prepare (sctx, state);
if (res != GSASL_OK)
return res;
state->step++;
}
if (state->step == 2)
{
bufdesc.length = input_len;
bufdesc.value = (void *) input;
buf = &bufdesc;
}
/* Release memory for token from last round-trip, if any. */
if (state->token.value != NULL)
{
maj_stat = gss_release_buffer (&min_stat, &state->token);
if (GSS_ERROR (maj_stat))
return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
state->token.value = NULL;
state->token.length = 0;
}
maj_stat = gss_init_sec_context (&min_stat,
GSS_C_NO_CREDENTIAL,
&state->context,
state->service,
state->mech_oid,
GSS_C_MUTUAL_FLAG,
0,
&state->cb,
buf,
&actual_mech_type,
&state->token,
&ret_flags,
NULL);
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR;
res = token2output (sctx, state, &state->token, output, output_len);
if (res != GSASL_OK)
return res;
if (maj_stat == GSS_S_CONTINUE_NEEDED)
return GSASL_NEEDS_MORE;
if (!(ret_flags & GSS_C_MUTUAL_FLAG))
return GSASL_AUTHENTICATION_ERROR;
if (!gss_oid_equal (state->mech_oid, actual_mech_type))
return GSASL_AUTHENTICATION_ERROR;
state->step++;
return GSASL_OK;
}
|
|||||
| ↓ | digest_md5_decode | 12 | 40 | 76 | lib/digest-md5/session.c |
int
digest_md5_decode (const char *input, size_t input_len,
char **output, size_t * output_len,
digest_md5_qop qop,
unsigned long readseqnum, char key[DIGEST_MD5_LENGTH])
{
if (qop & DIGEST_MD5_QOP_AUTH_CONF)
{
return -1;
}
else if (qop & DIGEST_MD5_QOP_AUTH_INT)
{
char *seqnumin;
char hash[GC_MD5_DIGEST_SIZE];
unsigned long len;
char tmpbuf[SASL_INTEGRITY_PREFIX_LENGTH];
int res;
if (input_len < SASL_INTEGRITY_PREFIX_LENGTH)
return -2;
len = C2I (input);
if (input_len < SASL_INTEGRITY_PREFIX_LENGTH + len)
return -2;
len -= MAC_HMAC_LEN + MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN;
seqnumin = malloc (SASL_INTEGRITY_PREFIX_LENGTH + len);
if (seqnumin == NULL)
return -1;
tmpbuf[0] = (readseqnum >> 24) & 0xFF;
tmpbuf[1] = (readseqnum >> 16) & 0xFF;
tmpbuf[2] = (readseqnum >> 8) & 0xFF;
tmpbuf[3] = readseqnum & 0xFF;
memcpy (seqnumin, tmpbuf, SASL_INTEGRITY_PREFIX_LENGTH);
memcpy (seqnumin + SASL_INTEGRITY_PREFIX_LENGTH,
input + MAC_DATA_LEN, len);
res = gc_hmac_md5 (key, MD5LEN, seqnumin, MAC_SEQNUM_LEN + len, hash);
free (seqnumin);
if (res)
return -1;
if (memcmp
(hash,
input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN -
MAC_HMAC_LEN, MAC_HMAC_LEN) == 0
&& memcmp (MAC_MSG_TYPE,
input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN,
MAC_MSG_TYPE_LEN) == 0
&& memcmp (tmpbuf, input + input_len - MAC_SEQNUM_LEN,
MAC_SEQNUM_LEN) == 0)
{
*output_len = len;
*output = malloc (*output_len);
if (!*output)
return -1;
memcpy (*output, input + MAC_DATA_LEN, len);
}
else
return -1;
}
else
{
*output_len = input_len;
*output = malloc (input_len);
if (!*output)
return -1;
memcpy (*output, input, input_len);
}
return 0;
}
|
|||||
| ↓ | register_builtin_mechs | 12 | 35 | 73 | lib/src/init.c |
static int
register_builtin_mechs (Gsasl * ctx)
{
int rc = GSASL_OK;
#ifdef USE_ANONYMOUS
rc = gsasl_register (ctx, &gsasl_anonymous_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_ANONYMOUS */
#ifdef USE_EXTERNAL
rc = gsasl_register (ctx, &gsasl_external_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_EXTERNAL */
#ifdef USE_LOGIN
rc = gsasl_register (ctx, &gsasl_login_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_LOGIN */
#ifdef USE_PLAIN
rc = gsasl_register (ctx, &gsasl_plain_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_PLAIN */
#ifdef USE_SECURID
rc = gsasl_register (ctx, &gsasl_securid_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_SECURID */
#ifdef USE_NTLM
rc = gsasl_register (ctx, &gsasl_ntlm_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_NTLM */
#ifdef USE_DIGEST_MD5
rc = gsasl_register (ctx, &gsasl_digest_md5_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_DIGEST_MD5 */
#ifdef USE_CRAM_MD5
rc = gsasl_register (ctx, &gsasl_cram_md5_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_CRAM_MD5 */
#ifdef USE_SCRAM_SHA1
rc = gsasl_register (ctx, &gsasl_scram_sha1_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_SCRAM_SHA1 */
#ifdef USE_GSSAPI
rc = gsasl_register (ctx, &gsasl_gssapi_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_GSSAPI */
#ifdef USE_GS2
rc = gsasl_register (ctx, &gsasl_gs2_krb5_mechanism);
if (rc != GSASL_OK)
return rc;
#endif /* USE_GSSAPI */
return GSASL_OK;
}
|
|||||
| ↓ | digest_md5_validate_response | 12 | 19 | 49 | lib/digest-md5/validate.c |
int
digest_md5_validate_response (digest_md5_response * r)
{
/* This directive is required and MUST be present exactly
once; otherwise, authentication fails. */
if (!r->username)
return -1;
/* This directive is required and MUST be present exactly
once; otherwise, authentication fails. */
if (!r->nonce)
return -1;
/* This directive is required and MUST be present exactly once;
otherwise, authentication fails. */
if (!r->cnonce)
return -1;
/* This directive is required and MUST be present exactly once;
otherwise, or if the value is 0, authentication fails. */
if (!r->nc)
return -1;
/* This directive is required and MUST be present exactly
once; if multiple instances are present, the client MUST
abort the authentication exchange. */
if (!r->digesturi)
return -1;
/* This directive is required and MUST be present exactly
once; otherwise, authentication fails. */
if (!*r->response)
return -1;
if (strlen (r->response) != DIGEST_MD5_RESPONSE_LENGTH)
return -1;
/* This directive MUST appear exactly once if "auth-conf" is
negotiated; if required and not present, authentication fails.
If the client recognizes no cipher and the server only advertised
"auth-conf" in the qop option, the client MUST abort the
authentication exchange. */
if (r->qop == DIGEST_MD5_QOP_AUTH_CONF && !r->cipher)
return -1;
if (r->qop != DIGEST_MD5_QOP_AUTH_CONF && r->cipher)
return -1;
return 0;
}
|
|||||
| ↓ | unescape | 12 | 18 | 34 | lib/scram/parser.c |
static char *
unescape (const char *str, size_t len)
{
char *out = malloc (len + 1);
char *p = out;
if (!out)
return NULL;
while (len > 0 && *str)
{
if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
{
*p++ = ',';
str += 3;
len -= 3;
}
else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
{
*p++ = '=';
str += 3;
len -= 3;
}
else
{
*p++ = *str;
str++;
len--;
}
}
*p = '\0';
return out;
}
|
|||||
| ↓ | unescape_authzid | 12 | 18 | 34 | lib/gs2/server.c |
static char *
unescape_authzid (const char *str, size_t len)
{
char *out = malloc (len + 1);
char *p = out;
if (!out)
return NULL;
while (len > 0 && *str)
{
if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
{
*p++ = ',';
str += 3;
len -= 3;
}
else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
{
*p++ = '=';
str += 3;
len -= 3;
}
else
{
*p++ = *str;
str++;
len--;
}
}
*p = '\0';
return out;
}
|
|||||
| ↓ | digest_md5_validate | 12 | 15 | 26 | lib/digest-md5/validate.c |
int
digest_md5_validate (digest_md5_challenge * c, digest_md5_response * r)
{
if (!c->nonce || !r->nonce)
return -1;
if (strcmp (c->nonce, r->nonce) != 0)
return -1;
if (r->nc != 1)
return -1;
if (!c->utf8 && r->utf8)
return -1;
if (!((c->qops ? c->qops : DIGEST_MD5_QOP_AUTH) &
(r->qop ? r->qop : DIGEST_MD5_QOP_AUTH)))
return -1;
if ((r->qop & DIGEST_MD5_QOP_AUTH_CONF) && !(c->ciphers & r->cipher))
return -1;
/* FIXME: Check more? */
return 0;
}
|
|||||
| ↓ | scram_valid_client_first | 13 | 13 | 37 | lib/scram/validate.c |
bool
scram_valid_client_first (struct scram_client_first *cf)
{
/* Check that cbflag is one of permitted values. */
switch (cf->cbflag)
{
case 'p':
case 'n':
case 'y':
break;
default:
return false;
}
/* Check that cbname is only set when cbflag is p. */
if (cf->cbflag == 'p' && cf->cbname == NULL)
return false;
else if (cf->cbflag != 'p' && cf->cbname != NULL)
return false;
/* FIXME check that cbname matches [A-Za-z0-9.-]. */
/* We require a non-zero username string. */
if (cf->username == NULL || *cf->username == '\0')
return false;
/* We require a non-zero client nonce. */
if (cf->client_nonce == NULL || *cf->client_nonce == '\0')
return false;
/* Nonce cannot contain ','. */
if (strchr (cf->client_nonce, ','))
return false;
return true;
}
|
|||||
| ↓ | scram_print_client_first | 11 | 22 | 42 | lib/scram/printer.c |
int
scram_print_client_first (struct scram_client_first *cf, char **out)
{
char *username = NULL;
char *authzid = NULL;
int n;
/* Below we assume fields are sensible, so first verify that to
avoid crashes. */
if (!scram_valid_client_first (cf))
return -1;
/* Escape username and authzid. */
username = scram_escape (cf->username);
if (!username)
return -2;
if (cf->authzid)
{
authzid = scram_escape (cf->authzid);
if (!authzid)
return -2;
}
n = asprintf (out, "%c%s%s,%s%s,n=%s,r=%s",
cf->cbflag,
cf->cbflag == 'p' ? "=" : "",
cf->cbflag == 'p' ? cf->cbname : "",
authzid ? "a=" : "",
authzid ? authzid : "",
username,
cf->client_nonce);
free (username);
free (authzid);
if (n <= 0 || *out == NULL)
return -1;
return 0;
}
|
|||||
| _gsasl_ntlm_client_step | 11 | 53 | 105 | lib/ntlm/ntlm.c | |
| prepare | 10 | 28 | 50 | lib/gs2/client.c | |
| gsasl_simple_getpass | 10 | 27 | 50 | lib/src/md5pwd.c | |
| utf8tolatin1ifpossible | 10 | 23 | 39 | lib/digest-md5/nonascii.c | |
| scram_valid_client_final | 10 | 13 | 29 | lib/scram/validate.c | |
| gs2_get_cred | 9 | 35 | 56 | lib/gs2/server.c | |
| _gss_decapsulate_token | 9 | 33 | 51 | lib/gs2/gs2helper.c | |
| _gsasl_gssapi_client_encode | 9 | 28 | 54 | lib/gssapi/client.c | |
| gsasl_saslprep | 9 | 26 | 50 | lib/src/saslprep.c | |
| gsasl_client_suggest_mechanism | 9 | 25 | 45 | lib/src/suggest.c | |
| scram_parse_server_final | 9 | 18 | 32 | lib/scram/parser.c | |
| _gsasl_cram_md5_server_step | 8 | 34 | 62 | lib/cram-md5/server.c | |
| _gsasl_gssapi_client_decode | 8 | 27 | 52 | lib/gssapi/client.c | |
| setup | 8 | 22 | 40 | lib/src/xstart.c | |
| scram_valid_server_first | 8 | 11 | 24 | lib/scram/validate.c | |
| digest_md5_encode | 7 | 45 | 68 | lib/digest-md5/session.c | |
| _gsasl_cram_md5_client_step | 7 | 37 | 66 | lib/cram-md5/client.c | |
| _gsasl_gssapi_server_start | 7 | 36 | 61 | lib/gssapi/server.c | |
| gsasl_finish | 7 | 25 | 37 | lib/src/xfinish.c | |
| gss_decapsulate_token | 7 | 21 | 37 | lib/gs2/gs2helper.c | |
| _gss_asn1_get_length_der | 7 | 20 | 43 | lib/gs2/gs2helper.c | |
| comma_append | 7 | 18 | 31 | lib/digest-md5/printer.c | |
| gsasl_register | 7 | 16 | 37 | lib/src/register.c | |
| parse_finish | 7 | 15 | 34 | lib/digest-md5/parser.c | |
| gss_inquire_mech_for_saslname | 6 | 8 | 23 | lib/gs2/gs2helper.c | |
| digest_md5_validate_challenge | 6 | 7 | 18 | lib/digest-md5/validate.c | |
| _gsasl_plain_client_step | 6 | 26 | 47 | lib/plain/client.c | |
| _gsasl_scram_sha1_server_start | 6 | 24 | 39 | lib/scram/server.c | |
| token2output | 6 | 23 | 46 | lib/gs2/client.c | |
| _gsasl_listmech | 6 | 20 | 35 | lib/src/listmech.c | |
| gsasl_done | 6 | 17 | 28 | lib/src/done.c | |
| gsasl_step64 | 6 | 15 | 31 | lib/src/xstep.c | |
| _gss_asn1_length_der | 6 | 15 | 32 | lib/gs2/gs2helper.c | |
| parse_gs2_header | 6 | 13 | 27 | lib/gs2/server.c | |
| digest_md5_qopstr2qops | 7 | 22 | 54 | lib/digest-md5/qop.c | |
| gsasl_callback | 5 | 8 | 18 | lib/src/callback.c | |
| _gsasl_digest_md5_hexdigit_to_char | 5 | 5 | 13 | lib/digest-md5/server.c | |
| hexdigit_to_char | 5 | 5 | 9 | lib/scram/client.c | |
| escape_authzid | 5 | 16 | 32 | lib/gs2/client.c | |
| scram_escape | 5 | 16 | 32 | lib/scram/printer.c | |
| latin1toutf8 | 5 | 15 | 27 | lib/digest-md5/nonascii.c | |
| _gsasl_gs2_client_finish | 5 | 12 | 20 | lib/gs2/client.c | |
| _gsasl_gs2_server_finish | 5 | 11 | 20 | lib/gs2/server.c | |
| _gsasl_gssapi_server_finish | 5 | 11 | 20 | lib/gssapi/server.c | |
| gss_encapsulate_token | 5 | 11 | 26 | lib/gs2/gs2helper.c | |
| _gsasl_login_client_step | 5 | 22 | 43 | lib/login/client.c | |
| _gsasl_gssapi_client_finish | 4 | 9 | 17 | lib/gssapi/client.c | |
| find_mechanism | 4 | 9 | 14 | lib/src/xstart.c | |
| gsasl_strerror | 4 | 9 | 17 | lib/src/error.c | |
| gsasl_property_set_raw | 4 | 9 | 22 | lib/src/property.c | |
| _gsasl_anonymous_server_step | 4 | 8 | 25 | lib/anonymous/server.c | |
| _gsasl_support_p | 4 | 7 | 11 | lib/src/supportp.c | |
| scram_print_server_final | 4 | 7 | 16 | lib/scram/printer.c | |
| scram_print_client_final | 4 | 7 | 17 | lib/scram/printer.c | |
| scram_print_server_first | 4 | 7 | 17 | lib/scram/printer.c | |
| scram_valid_server_final | 4 | 5 | 13 | lib/scram/validate.c | |
| _gsasl_gs2_server_start | 4 | 26 | 45 | lib/gs2/server.c | |
| _gss_encapsulate_token_prefix | 4 | 25 | 39 | lib/gs2/gs2helper.c | |
| _gsasl_digest_md5_server_start | 4 | 20 | 33 | lib/digest-md5/server.c | |
| _gsasl_digest_md5_client_start | 4 | 18 | 30 | lib/digest-md5/client.c | |
| _gsasl_scram_sha1_client_start | 4 | 16 | 30 | lib/scram/client.c | |
| gsasl_init | 4 | 11 | 21 | lib/src/init.c | |
| cram_md5_digest | 4 | 10 | 19 | lib/cram-md5/digest.c | |
| _gsasl_digest_md5_server_decode | 4 | 10 | 23 | lib/digest-md5/server.c | |
| _gsasl_digest_md5_server_encode | 4 | 10 | 23 | lib/digest-md5/server.c | |
| _gsasl_external_server_step | 4 | 10 | 28 | lib/external/server.c | |
| _gsasl_digest_md5_client_decode | 4 | 10 | 23 | lib/digest-md5/client.c | |
| _gsasl_digest_md5_client_encode | 4 | 10 | 23 | lib/digest-md5/client.c | |
| gss_oid_equal | 4 | 1 | 8 | lib/gs2/gs2helper.c | |
| _gsasl_external_client_step | 3 | 9 | 19 | lib/external/client.c | |
| _gsasl_anonymous_client_step | 3 | 9 | 19 | lib/anonymous/client.c | |
| main | 3 | 8 | 14 | lib/tests/test-error.c | |
| _gsasl_code | 3 | 8 | 20 | lib/src/xcode.c | |
| gsasl_property_get | 3 | 7 | 18 | lib/src/property.c | |
| hex_p | 3 | 7 | 11 | lib/scram/client.c | |
| gsasl_base64_from | 3 | 6 | 13 | lib/src/base64.c | |
| gsasl_base64_to | 3 | 6 | 13 | lib/src/base64.c | |
| digest_md5_print_finish | 3 | 6 | 15 | lib/digest-md5/printer.c | |
| digest_md5_validate_finish | 3 | 5 | 12 | lib/digest-md5/validate.c | |
| gsasl_check_version | 3 | 3 | 8 | lib/src/version.c | |
| gsasl_mechanism_name | 3 | 3 | 7 | lib/src/mechname.c | |
| gsasl_strerror_name | 3 | 3 | 8 | lib/src/error.c | |
| _gsasl_gs2_client_start | 3 | 24 | 41 | lib/gs2/client.c | |
| cram_md5_challenge | 3 | 14 | 23 | lib/cram-md5/challenge.c | |
| start | 3 | 11 | 24 | lib/src/xstart.c | |
| digest_md5_parse_finish | 3 | 11 | 20 | lib/digest-md5/parser.c | |
| digest_md5_parse_response | 3 | 11 | 20 | lib/digest-md5/parser.c | |
| digest_md5_parse_challenge | 3 | 11 | 20 | lib/digest-md5/parser.c | |
| _gsasl_digest_md5_set_hashed_secret | 3 | 11 | 22 | lib/digest-md5/server.c | |
| _gsasl_cram_md5_server_start | 3 | 10 | 18 | lib/cram-md5/server.c | |
| gs2_get_oid | 3 | 10 | 18 | lib/gs2/gs2helper.c | |
| map | 19 | 39 | 84 | lib/src/property.c | |
| digest_md5_free_challenge | 2 | 8 | 12 | lib/digest-md5/free.c | |
| _gsasl_ntlm_client_start | 2 | 7 | 15 | lib/ntlm/ntlm.c | |
| _gsasl_login_client_start | 2 | 7 | 15 | lib/login/client.c | |
| _gsasl_securid_client_start | 2 | 7 | 15 | lib/securid/client.c | |
| _gsasl_digest_md5_server_finish | 2 | 7 | 14 | lib/digest-md5/server.c | |
| _gsasl_digest_md5_client_finish | 2 | 7 | 14 | lib/digest-md5/client.c | |
| _gsasl_login_server_start | 2 | 6 | 13 | lib/login/server.c | |
| _gsasl_login_server_finish | 2 | 6 | 12 | lib/login/server.c | |
| gsasl_decode | 2 | 5 | 14 | lib/src/xcode.c | |
| gsasl_encode | 2 | 5 | 14 | lib/src/xcode.c | |
| gsasl_step | 2 | 5 | 14 | lib/src/xstep.c | |
| gsasl_hmac_md5 | 2 | 4 | 9 | lib/src/crypto.c | |
| gsasl_md5 | 2 | 4 | 8 | lib/src/crypto.c | |
| gsasl_property_fast | 2 | 4 | 10 | lib/src/property.c | |
| gsasl_hmac_sha1 | 2 | 4 | 9 | lib/src/crypto.c | |
| gsasl_sha1 | 2 | 4 | 8 | lib/src/crypto.c | |
| sha1_hex_to_byte | 2 | 4 | 10 | lib/scram/client.c | |
| _gsasl_login_client_finish | 2 | 4 | 10 | lib/login/client.c | |
| gsasl_property_set | 2 | 2 | 6 | lib/src/property.c | |
| _gsasl_scram_sha1_server_finish | 2 | 15 | 22 | lib/scram/server.c | |
| _gsasl_scram_sha1_client_finish | 2 | 11 | 18 | lib/scram/client.c | |
| _gsasl_gssapi_client_start | 2 | 10 | 18 | lib/gssapi/client.c | |
| digest_md5_free_response | 1 | 7 | 12 | lib/digest-md5/free.c | |
| scram_free_client_first | 1 | 5 | 10 | lib/scram/tokens.c | |
| scram_free_client_final | 1 | 4 | 9 | lib/scram/tokens.c | |
| scram_free_server_first | 1 | 3 | 8 | lib/scram/tokens.c | |
| digest_md5_qops2qopstr | 1 | 2 | 16 | lib/digest-md5/qop.c | |
| scram_free_server_final | 1 | 2 | 7 | lib/scram/tokens.c | |
| _gsasl_ntlm_client_finish | 1 | 2 | 7 | lib/ntlm/ntlm.c | |
| _gsasl_securid_client_finish | 1 | 2 | 7 | lib/securid/client.c | |
| _gsasl_cram_md5_server_finish | 1 | 2 | 7 | lib/cram-md5/server.c | |
| gsasl_server_mechlist | 1 | 1 | 6 | lib/src/listmech.c | |
| gsasl_client_mechlist | 1 | 1 | 6 | lib/src/listmech.c | |
| gsasl_server_support_p | 1 | 1 | 5 | lib/src/supportp.c | |
| digest_md5_free_finish | 1 | 1 | 5 | lib/digest-md5/free.c | |
| gsasl_random | 1 | 1 | 5 | lib/src/crypto.c | |
| gsasl_client_support_p | 1 | 1 | 5 | lib/src/supportp.c | |
| gsasl_callback_set | 1 | 1 | 5 | lib/src/callback.c | |
| gsasl_free | 1 | 1 | 5 | lib/src/free.c | |
| gsasl_nonce | 1 | 1 | 5 | lib/src/crypto.c | |
| to_uchar | 1 | 1 | 5 | lib/digest-md5/nonascii.c | |
| gsasl_session_hook_get | 1 | 1 | 5 | lib/src/callback.c | |
| gsasl_session_hook_set | 1 | 1 | 5 | lib/src/callback.c | |
| gsasl_server_start | 1 | 1 | 5 | lib/src/xstart.c | |
| gsasl_callback_hook_get | 1 | 1 | 5 | lib/src/callback.c | |
| gsasl_client_start | 1 | 1 | 5 | lib/src/xstart.c | |
| _gsasl_digest_md5_hex_to_char | 1 | 1 | 6 | lib/digest-md5/server.c | |
| gsasl_callback_hook_set | 1 | 1 | 5 | lib/src/callback.c | |