↓
|
gss_krb5_unwrap
|
41
|
132
|
227
|
lib/krb5/msg.c
|
OM_uint32
gss_krb5_unwrap (OM_uint32 * minor_status,
const gss_ctx_id_t context_handle,
const gss_buffer_t input_message_buffer,
gss_buffer_t output_message_buffer,
int *conf_state, gss_qop_t * qop_state)
{
_gss_krb5_ctx_t k5 = context_handle->krb5;
gss_buffer_desc tok;
char *data;
OM_uint32 sgn_alg, seal_alg;
size_t tmplen;
int rc;
rc = gss_decapsulate_token (input_message_buffer, GSS_KRB5, &tok);
if (rc != GSS_S_COMPLETE)
return GSS_S_BAD_MIC;
if (tok.length < 8)
return GSS_S_BAD_MIC;
if (memcmp (tok.value, TOK_WRAP, TOK_LEN) != 0)
return GSS_S_BAD_MIC;
data = tok.value;
sgn_alg = data[2] & 0xFF;
sgn_alg |= data[3] << 8 & 0xFF00;
seal_alg = data[4] & 0xFF;
seal_alg |= data[5] << 8 & 0xFF00;
if (conf_state != NULL)
*conf_state = seal_alg == 0xFFFF;
if (memcmp (data + 6, "\xFF\xFF", 2) != 0)
return GSS_S_BAD_MIC;
switch (sgn_alg)
{
/* XXX implement other checksums */
case 0: /* DES-MD5 */
{
size_t padlen;
char *pt;
char header[8];
char encseqno[8];
char seqno[8];
char cksum[8];
char confounder[8];
char *tmp;
uint32_t seqnr;
size_t outlen, i;
/* Typical data:
;; 02 01 00 00 ff ff ff ff 0c 22 1f 79 59 3d 00 cb
;; d5 78 2f fb 50 d2 b8 59 fb b4 e0 9b d0 a2 fa dc
;; 01 00 20 00 04 04 04 04
Translates into:
;; HEADER ENCRYPTED SEQ.NUMBER
;; DES-MAC-MD5 CKSUM CONFOUNDER
;; PADDED DATA
*/
if (tok.length < 5 * 8)
return GSS_S_BAD_MIC;
memcpy (header, data, 8);
memcpy (encseqno, data + 8, 8);
memcpy (cksum, data + 16, 8);
memcpy (confounder, data + 24, 8);
pt = data + 32;
/* XXX decrypt data iff confidential option chosen */
rc = shishi_decrypt_iv_etype (k5->sh,
k5->key,
0, SHISHI_DES_CBC_NONE,
cksum, 8, encseqno, 8, &tmp, &outlen);
if (rc != SHISHI_OK)
return GSS_S_FAILURE;
if (outlen != 8)
return GSS_S_BAD_MIC;
memcpy (seqno, tmp, 8);
free (tmp);
if (memcmp (seqno + 4, k5->acceptor ? "\x00\x00\x00\x00" :
"\xFF\xFF\xFF\xFF", 4) != 0)
return GSS_S_BAD_MIC;
seqnr = C2I (seqno);
if (seqnr != (k5->acceptor ? k5->initseqnr : k5->acceptseqnr))
return GSS_S_BAD_MIC;
if (k5->acceptor)
k5->initseqnr++;
else
k5->acceptseqnr++;
/* Check pad */
padlen = data[tok.length - 1];
if (padlen > 8)
return GSS_S_BAD_MIC;
for (i = 1; i <= padlen; i++)
if (data[tok.length - i] != (int) padlen)
return GSS_S_BAD_MIC;
/* Write header and confounder next to data */
memcpy (data + 16, header, 8);
memcpy (data + 24, confounder, 8);
/* Checksum header + confounder + data + pad */
rc = shishi_checksum (k5->sh,
k5->key,
0, SHISHI_RSA_MD5_DES_GSS,
data + 16, tok.length - 16, &tmp, &tmplen);
if (rc != SHISHI_OK || tmplen != 8)
return GSS_S_FAILURE;
memcpy (data + 8, tmp, tmplen);
/* Compare checksum */
if (tmplen != 8 || memcmp (cksum, data + 8, 8) != 0)
return GSS_S_BAD_MIC;
/* Copy output data */
output_message_buffer->length = tok.length - 8 - 8 - 8 - 8 - padlen;
output_message_buffer->value = malloc (output_message_buffer->length);
if (!output_message_buffer->value)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
memcpy (output_message_buffer->value, pt,
tok.length - 4 * 8 - padlen);
}
break;
case 4: /* 3DES */
{
size_t padlen;
char *p;
char *t;
char cksum[20];
size_t outlen, i;
uint32_t seqnr;
if (tok.length < 8 + 8 + 20 + 8 + 8)
return GSS_S_BAD_MIC;
memcpy (cksum, data + 8 + 8, 20);
/* XXX decrypt data iff confidential option chosen */
p = data + 8;
rc = shishi_decrypt_iv_etype (k5->sh,
k5->key,
0, SHISHI_DES3_CBC_NONE,
cksum, 8, p, 8, &t, &outlen);
if (rc != SHISHI_OK || outlen != 8)
return GSS_S_FAILURE;
memcpy (p, t, 8);
free (t);
if (memcmp (p + 4, k5->acceptor ? "\x00\x00\x00\x00" :
"\xFF\xFF\xFF\xFF", 4) != 0)
return GSS_S_BAD_MIC;
seqnr = C2I (p);
if (seqnr != (k5->acceptor ? k5->initseqnr : k5->acceptseqnr))
return GSS_S_BAD_MIC;
if (k5->acceptor)
k5->initseqnr++;
else
k5->acceptseqnr++;
/* Check pad */
padlen = data[tok.length - 1];
if (padlen > 8)
return GSS_S_BAD_MIC;
for (i = 1; i <= padlen; i++)
if (data[tok.length - i] != (int) padlen)
return GSS_S_BAD_MIC;
/* Write header next to confounder */
memcpy (data + 8 + 20, data, 8);
/* Checksum header + confounder + data + pad */
rc = shishi_checksum (k5->sh,
k5->key,
SHISHI_KEYUSAGE_GSS_R2,
SHISHI_HMAC_SHA1_DES3_KD, data + 20 + 8,
tok.length - 20 - 8, &t, &tmplen);
if (rc != SHISHI_OK || tmplen != 20)
return GSS_S_FAILURE;
memcpy (data + 8 + 8, t, tmplen);
free (t);
/* Compare checksum */
if (tmplen != 20 || memcmp (cksum, data + 8 + 8, 20) != 0)
return GSS_S_BAD_MIC;
/* Copy output data */
output_message_buffer->length = tok.length - 8 - 20 - 8 - 8 - padlen;
output_message_buffer->value = malloc (output_message_buffer->length);
if (!output_message_buffer->value)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
memcpy (output_message_buffer->value, data + 20 + 8 + 8 + 8,
tok.length - 20 - 8 - 8 - 8 - padlen);
}
break;
default:
return GSS_S_FAILURE;
}
return GSS_S_COMPLETE;
}
|
↓
|
gss_krb5_accept_sec_context
|
30
|
100
|
190
|
lib/krb5/context.c
|
OM_uint32
gss_krb5_accept_sec_context (OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
const gss_cred_id_t acceptor_cred_handle,
const gss_buffer_t input_token_buffer,
const gss_channel_bindings_t input_chan_bindings,
gss_name_t * src_name,
gss_OID * mech_type,
gss_buffer_t output_token,
OM_uint32 * ret_flags,
OM_uint32 * time_rec,
gss_cred_id_t * delegated_cred_handle)
{
gss_buffer_desc in;
gss_ctx_id_t cx;
_gss_krb5_ctx_t cxk5;
_gss_krb5_cred_t crk5;
OM_uint32 tmp_min_stat;
int rc;
if (minor_status)
*minor_status = 0;
if (ret_flags)
*ret_flags = 0;
if (!acceptor_cred_handle)
/* XXX support GSS_C_NO_CREDENTIAL: acquire_cred() default server */
return GSS_S_NO_CRED;
if (*context_handle)
return GSS_S_FAILURE;
crk5 = acceptor_cred_handle->krb5;
cx = calloc (sizeof (*cx), 1);
if (!cx)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
cxk5 = calloc (sizeof (*cxk5), 1);
if (!cxk5)
{
free (cx);
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
cx->mech = GSS_KRB5;
cx->krb5 = cxk5;
/* XXX cx->peer?? */
*context_handle = cx;
cxk5->sh = crk5->sh;
cxk5->key = crk5->key;
cxk5->acceptor = 1;
rc = shishi_ap (cxk5->sh, &cxk5->ap);
if (rc != SHISHI_OK)
return GSS_S_FAILURE;
rc = gss_decapsulate_token (input_token_buffer, GSS_KRB5, &in);
if (rc != GSS_S_COMPLETE)
return GSS_S_BAD_MIC;
if (in.length < TOK_LEN)
{
gss_release_buffer (&tmp_min_stat, &in);
return GSS_S_BAD_MIC;
}
if (memcmp (in.value, TOK_AP_REQ, TOK_LEN) != 0)
{
gss_release_buffer (&tmp_min_stat, &in);
return GSS_S_BAD_MIC;
}
rc = shishi_ap_req_der_set (cxk5->ap, (char *) in.value + TOK_LEN,
in.length - TOK_LEN);
gss_release_buffer (&tmp_min_stat, &in);
if (rc != SHISHI_OK)
return GSS_S_FAILURE;
rc = shishi_ap_req_process (cxk5->ap, crk5->key);
if (rc != SHISHI_OK)
{
if (minor_status)
*minor_status = GSS_KRB5_S_G_VALIDATE_FAILED;
return GSS_S_FAILURE;
}
rc = shishi_authenticator_seqnumber_get (cxk5->sh,
shishi_ap_authenticator (cxk5->ap),
&cxk5->initseqnr);
if (rc != SHISHI_OK)
return GSS_S_FAILURE;
rc = _gss_krb5_checksum_parse (minor_status,
context_handle, input_chan_bindings);
if (rc != GSS_S_COMPLETE)
return GSS_S_FAILURE;
cxk5->tkt = shishi_ap_tkt (cxk5->ap);
cxk5->key = shishi_ap_key (cxk5->ap);
if (shishi_apreq_mutual_required_p (crk5->sh, shishi_ap_req (cxk5->ap)))
{
Shishi_asn1 aprep;
char *der;
size_t len;
rc = shishi_ap_rep_asn1 (cxk5->ap, &aprep);
if (rc != SHISHI_OK)
{
printf ("Error creating AP-REP: %s\n", shishi_strerror (rc));
return GSS_S_FAILURE;
}
rc = shishi_encapreppart_seqnumber_get (cxk5->sh,
shishi_ap_encapreppart
(cxk5->ap), &cxk5->acceptseqnr);
if (rc != SHISHI_OK)
{
/* A strict 1964 implementation would return
GSS_S_DEFECTIVE_TOKEN here. gssapi-cfx permit absent
sequence number, though. */
cxk5->acceptseqnr = 0;
}
rc = shishi_asn1_to_der (crk5->sh, aprep, &der, &len);
if (rc != SHISHI_OK)
{
printf ("Error der encoding aprep: %s\n", shishi_strerror (rc));
return GSS_S_FAILURE;
}
rc = _gss_encapsulate_token_prefix (TOK_AP_REP, TOK_LEN,
der, len,
GSS_KRB5->elements,
GSS_KRB5->length,
&output_token->value,
&output_token->length);
if (rc != 0)
return GSS_S_FAILURE;
if (ret_flags)
*ret_flags = GSS_C_MUTUAL_FLAG;
}
else
{
output_token->value = NULL;
output_token->length = 0;
}
if (src_name)
{
gss_name_t p;
p = malloc (sizeof (*p));
if (!p)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
rc = shishi_encticketpart_client (cxk5->sh,
shishi_tkt_encticketpart (cxk5->tkt),
&p->value, &p->length);
if (rc != SHISHI_OK)
return GSS_S_FAILURE;
p->type = GSS_KRB5_NT_PRINCIPAL_NAME;
*src_name = p;
}
/* PROT_READY is not mentioned in 1964/gssapi-cfx but we support
it anyway. */
if (ret_flags)
*ret_flags |= GSS_C_PROT_READY_FLAG;
if (minor_status)
*minor_status = 0;
return GSS_S_COMPLETE;
}
|
↓
|
gss_display_status
|
23
|
70
|
157
|
lib/error.c
|
OM_uint32
gss_display_status (OM_uint32 * minor_status,
OM_uint32 status_value,
int status_type,
const gss_OID mech_type,
OM_uint32 * message_context, gss_buffer_t status_string)
{
size_t i;
bindtextdomain (PACKAGE PO_SUFFIX, LOCALEDIR);
if (minor_status)
*minor_status = 0;
if (message_context)
status_value &= ~*message_context;
switch (status_type)
{
case GSS_C_GSS_CODE:
if (message_context)
{
*message_context |=
GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET;
if ((status_value & ~*message_context) == 0)
*message_context = 0;
}
switch (GSS_ROUTINE_ERROR (status_value))
{
case 0:
break;
case GSS_S_BAD_MECH:
case GSS_S_BAD_NAME:
case GSS_S_BAD_NAMETYPE:
case GSS_S_BAD_BINDINGS:
case GSS_S_BAD_STATUS:
case GSS_S_BAD_SIG:
case GSS_S_NO_CRED:
case GSS_S_NO_CONTEXT:
case GSS_S_DEFECTIVE_TOKEN:
case GSS_S_DEFECTIVE_CREDENTIAL:
case GSS_S_CREDENTIALS_EXPIRED:
case GSS_S_CONTEXT_EXPIRED:
case GSS_S_FAILURE:
case GSS_S_BAD_QOP:
case GSS_S_UNAUTHORIZED:
case GSS_S_UNAVAILABLE:
case GSS_S_DUPLICATE_ELEMENT:
case GSS_S_NAME_NOT_MN:
status_string->value =
strdup (_(gss_routine_errors
[(GSS_ROUTINE_ERROR (status_value) >>
GSS_C_ROUTINE_ERROR_OFFSET) - 1].text));
if (!status_string->value)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
status_string->length = strlen (status_string->value);
return GSS_S_COMPLETE;
break;
default:
return GSS_S_BAD_STATUS;
break;
}
if (message_context)
{
*message_context |=
GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET;
if ((status_value & ~*message_context) == 0)
*message_context = 0;
}
switch (GSS_CALLING_ERROR (status_value))
{
case 0:
break;
case GSS_S_CALL_INACCESSIBLE_READ:
case GSS_S_CALL_INACCESSIBLE_WRITE:
case GSS_S_CALL_BAD_STRUCTURE:
status_string->value =
strdup (_(gss_calling_errors
[(GSS_CALLING_ERROR (status_value) >>
GSS_C_CALLING_ERROR_OFFSET) - 1].text));
if (!status_string->value)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
status_string->length = strlen (status_string->value);
return GSS_S_COMPLETE;
break;
default:
return GSS_S_BAD_STATUS;
break;
}
for (i = 0; i < sizeof (gss_supplementary_errors) /
sizeof (gss_supplementary_errors[0]); i++)
if (gss_supplementary_errors[i].err &
GSS_SUPPLEMENTARY_INFO (status_value))
{
status_string->value =
strdup (_(gss_supplementary_errors[i].text));
if (!status_string->value)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
status_string->length = strlen (status_string->value);
*message_context |= gss_supplementary_errors[i].err;
if ((status_value & ~*message_context) == 0)
*message_context = 0;
return GSS_S_COMPLETE;
}
if (GSS_SUPPLEMENTARY_INFO (status_value))
return GSS_S_BAD_STATUS;
if (message_context)
*message_context = 0;
status_string->value = strdup (_("No error"));
if (!status_string->value)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
status_string->length = strlen (status_string->value);
break;
case GSS_C_MECH_CODE:
{
_gss_mech_api_t mech;
mech = _gss_find_mech (mech_type);
return mech->display_status (minor_status, status_value, status_type,
mech_type, message_context,
status_string);
}
break;
default:
return GSS_S_BAD_STATUS;
}
return GSS_S_COMPLETE;
}
|
↓
|
gss_krb5_wrap
|
22
|
113
|
213
|
lib/krb5/msg.c
|
OM_uint32
gss_krb5_wrap (OM_uint32 * minor_status,
const gss_ctx_id_t context_handle,
int conf_req_flag,
gss_qop_t qop_req,
const gss_buffer_t input_message_buffer,
int *conf_state, gss_buffer_t output_message_buffer)
{
_gss_krb5_ctx_t k5 = context_handle->krb5;
size_t padlength;
gss_buffer_desc data;
char *p;
size_t tmplen;
int rc;
switch (shishi_key_type (k5->key))
{
/* XXX implement other checksums */
case SHISHI_DES_CBC_MD5:
{
char header[8];
char seqno[8];
char *eseqno;
char *cksum;
char confounder[8];
/* Typical data:
;; 02 01 00 00 ff ff ff ff 0c 22 1f 79 59 3d 00 cb
;; d5 78 2f fb 50 d2 b8 59 fb b4 e0 9b d0 a2 fa dc
;; 01 00 20 00 04 04 04 04
Translates into:
;; HEADER ENCRYPTED SEQ.NUMBER
;; DES-MAC-MD5 CKSUM CONFOUNDER
;; PADDED DATA
*/
padlength = 8 - input_message_buffer->length % 8;
data.length = 4 * 8 + input_message_buffer->length + padlength;
p = malloc (data.length);
if (!p)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
/* XXX encrypt data iff confidential option chosen */
/* Setup header and confounder */
memcpy (header, TOK_WRAP, 2); /* TOK_ID: Wrap 0201 */
memcpy (header + 2, "\x00\x00", 2); /* SGN_ALG: DES-MAC-MD5 */
memcpy (header + 4, "\xFF\xFF", 2); /* SEAL_ALG: none */
memcpy (header + 6, "\xFF\xFF", 2); /* filler */
rc = shishi_randomize (k5->sh, 0, confounder, 8);
if (rc != SHISHI_OK)
return GSS_S_FAILURE;
/* Compute checksum over header, confounder, input string, and pad */
memcpy (p, header, 8);
memcpy (p + 8, confounder, 8);
memcpy (p + 16, input_message_buffer->value,
input_message_buffer->length);
memset (p + 16 + input_message_buffer->length,
(int) padlength, padlength);
rc = shishi_checksum (k5->sh,
k5->key,
0, SHISHI_RSA_MD5_DES_GSS,
p,
16 + input_message_buffer->length + padlength,
&cksum, &tmplen);
if (rc != SHISHI_OK || tmplen != 8)
return GSS_S_FAILURE;
/* seq_nr */
if (k5->acceptor)
{
seqno[0] = k5->acceptseqnr & 0xFF;
seqno[1] = k5->acceptseqnr >> 8 & 0xFF;
seqno[2] = k5->acceptseqnr >> 16 & 0xFF;
seqno[3] = k5->acceptseqnr >> 24 & 0xFF;
memset (seqno + 4, 0xFF, 4);
}
else
{
seqno[0] = k5->initseqnr & 0xFF;
seqno[1] = k5->initseqnr >> 8 & 0xFF;
seqno[2] = k5->initseqnr >> 16 & 0xFF;
seqno[3] = k5->initseqnr >> 24 & 0xFF;
memset (seqno + 4, 0, 4);
}
rc = shishi_encrypt_iv_etype (k5->sh, k5->key, 0,
SHISHI_DES_CBC_NONE, cksum, 8,
seqno, 8, &eseqno, &tmplen);
if (rc != SHISHI_OK || tmplen != 8)
return GSS_S_FAILURE;
/* put things in place */
memcpy (p, header, 8);
memcpy (p + 8, eseqno, 8);
free (eseqno);
memcpy (p + 16, cksum, 8);
free (cksum);
memcpy (p + 24, confounder, 8);
memcpy (p + 32, input_message_buffer->value,
input_message_buffer->length);
memset (p + 32 + input_message_buffer->length,
(int) padlength, padlength);
data.value = p;
rc = gss_encapsulate_token (&data, GSS_KRB5, output_message_buffer);
if (rc != GSS_S_COMPLETE)
return GSS_S_FAILURE;
if (k5->acceptor)
k5->acceptseqnr++;
else
k5->initseqnr++;
}
break;
case SHISHI_DES3_CBC_HMAC_SHA1_KD:
{
char *tmp;
padlength = 8 - input_message_buffer->length % 8;
data.length = 8 + 8 + 20 + 8 + input_message_buffer->length
+ padlength;
p = malloc (data.length);
if (!p)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
/* XXX encrypt data iff confidential option chosen */
/* Compute checksum over header, confounder, input string, and pad */
memcpy (p, TOK_WRAP, 2); /* TOK_ID: Wrap */
memcpy (p + 2, "\x04\x00", 2); /* SGN_ALG: 3DES */
memcpy (p + 4, "\xFF\xFF", 2); /* SEAL_ALG: none */
memcpy (p + 6, "\xFF\xFF", 2); /* filler */
rc = shishi_randomize (k5->sh, 0, p + 8, 8);
if (rc != SHISHI_OK)
return GSS_S_FAILURE;
memcpy (p + 16, input_message_buffer->value,
input_message_buffer->length);
memset (p + 16 + input_message_buffer->length,
(int) padlength, padlength);
rc = shishi_checksum (k5->sh,
k5->key,
SHISHI_KEYUSAGE_GSS_R2,
SHISHI_HMAC_SHA1_DES3_KD, p,
16 + input_message_buffer->length + padlength,
&tmp, &tmplen);
if (rc != SHISHI_OK || tmplen != 20)
return GSS_S_FAILURE;
memcpy (p + 16, tmp, tmplen);
memcpy (p + 36, p + 8, 8);
/* seq_nr */
if (k5->acceptor)
{
(p + 8)[0] = k5->acceptseqnr & 0xFF;
(p + 8)[1] = k5->acceptseqnr >> 8 & 0xFF;
(p + 8)[2] = k5->acceptseqnr >> 16 & 0xFF;
(p + 8)[3] = k5->acceptseqnr >> 24 & 0xFF;
memset (p + 8 + 4, 0xFF, 4);
}
else
{
(p + 8)[0] = k5->initseqnr & 0xFF;
(p + 8)[1] = k5->initseqnr >> 8 & 0xFF;
(p + 8)[2] = k5->initseqnr >> 16 & 0xFF;
(p + 8)[3] = k5->initseqnr >> 24 & 0xFF;
memset (p + 8 + 4, 0, 4);
}
rc = shishi_encrypt_iv_etype (k5->sh, k5->key, 0, SHISHI_DES3_CBC_NONE, p + 16, 8, /* cksum */
p + 8, 8, &tmp, &tmplen);
if (rc != SHISHI_OK || tmplen != 8)
return GSS_S_FAILURE;
memcpy (p + 8, tmp, tmplen);
free (tmp);
memcpy (p + 8 + 8 + 20 + 8, input_message_buffer->value,
input_message_buffer->length);
memset (p + 8 + 8 + 20 + 8 + input_message_buffer->length,
(int) padlength, padlength);
data.value = p;
rc = gss_encapsulate_token (&data, GSS_KRB5, output_message_buffer);
if (rc != GSS_S_COMPLETE)
return GSS_S_FAILURE;
if (k5->acceptor)
k5->acceptseqnr++;
else
k5->initseqnr++;
break;
}
default:
return GSS_S_FAILURE;
}
return GSS_S_COMPLETE;
}
|
↓
|
gss_krb5_init_sec_context
|
17
|
40
|
112
|
lib/krb5/context.c
|
OM_uint32
gss_krb5_init_sec_context (OM_uint32 * minor_status,
const gss_cred_id_t initiator_cred_handle,
gss_ctx_id_t * context_handle,
const gss_name_t target_name,
const gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
const gss_channel_bindings_t input_chan_bindings,
const gss_buffer_t input_token,
gss_OID * actual_mech_type,
gss_buffer_t output_token,
OM_uint32 * ret_flags, OM_uint32 * time_rec)
{
gss_ctx_id_t ctx = *context_handle;
_gss_krb5_ctx_t k5 = ctx->krb5;
OM_uint32 maj_stat;
int rc;
if (minor_status)
*minor_status = 0;
if (initiator_cred_handle)
{
/* We only support the default initiator. See k5internal.h for
adding a Shishi_tkt to the credential structure. I'm not sure
what the use would be -- user-to-user authentication perhaps?
Later: if you have tickets for foo@BAR and bar@FOO, it may be
useful to call gss_acquire_cred first to chose which one to
initiate the context with. Not many applications need this. */
return GSS_S_NO_CRED;
}
if (target_name == NULL)
{
return GSS_S_BAD_NAME;
}
if (k5 == NULL)
{
k5 = ctx->krb5 = calloc (sizeof (*k5), 1);
if (!k5)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
rc = shishi_init (&k5->sh);
if (rc != SHISHI_OK)
return GSS_S_FAILURE;
}
if (!k5->reqdone)
{
maj_stat = init_request (minor_status,
initiator_cred_handle,
context_handle,
target_name,
mech_type,
req_flags,
time_req,
input_chan_bindings,
input_token,
actual_mech_type,
output_token, ret_flags, time_rec);
if (GSS_ERROR (maj_stat))
return maj_stat;
k5->flags = req_flags & ( /* GSS_C_DELEG_FLAG | */
GSS_C_MUTUAL_FLAG |
GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG |
GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
/* PROT_READY is not mentioned in 1964/gssapi-cfx but we support
it anyway. */
k5->flags |= GSS_C_PROT_READY_FLAG;
if (ret_flags)
*ret_flags = k5->flags;
k5->key = shishi_ap_key (k5->ap);
k5->reqdone = 1;
}
else if (k5->reqdone && k5->flags & GSS_C_MUTUAL_FLAG && !k5->repdone)
{
maj_stat = init_reply (minor_status,
initiator_cred_handle,
context_handle,
target_name,
mech_type,
req_flags,
time_req,
input_chan_bindings,
input_token,
actual_mech_type,
output_token, ret_flags, time_rec);
if (GSS_ERROR (maj_stat))
return maj_stat;
if (ret_flags)
*ret_flags = k5->flags;
k5->repdone = 1;
}
else
maj_stat = GSS_S_FAILURE;
if (time_rec)
*time_rec = gss_krb5_tktlifetime (k5->tkt);
return maj_stat;
}
|
↓
|
gss_init_sec_context
|
16
|
38
|
88
|
lib/context.c
|
OM_uint32
gss_init_sec_context (OM_uint32 * minor_status,
const gss_cred_id_t initiator_cred_handle,
gss_ctx_id_t * context_handle,
const gss_name_t target_name,
const gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
const gss_channel_bindings_t input_chan_bindings,
const gss_buffer_t input_token,
gss_OID * actual_mech_type,
gss_buffer_t output_token,
OM_uint32 * ret_flags, OM_uint32 * time_rec)
{
OM_uint32 maj_stat;
_gss_mech_api_t mech;
int freecontext = 0;
if (output_token)
{
output_token->length = 0;
output_token->value = NULL;
}
if (ret_flags)
*ret_flags = 0;
if (!context_handle)
{
if (minor_status)
*minor_status = 0;
return GSS_S_NO_CONTEXT | GSS_S_CALL_INACCESSIBLE_READ;
}
if (output_token == GSS_C_NO_BUFFER)
{
if (minor_status)
*minor_status = 0;
return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
}
if (*context_handle == GSS_C_NO_CONTEXT)
mech = _gss_find_mech (mech_type);
else
mech = _gss_find_mech ((*context_handle)->mech);
if (mech == NULL)
{
if (minor_status)
*minor_status = 0;
return GSS_S_BAD_MECH;
}
if (actual_mech_type)
*actual_mech_type = mech->mech;
if (*context_handle == GSS_C_NO_CONTEXT)
{
*context_handle = calloc (sizeof (**context_handle), 1);
if (!*context_handle)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
(*context_handle)->mech = mech->mech;
freecontext = 1;
}
maj_stat = mech->init_sec_context (minor_status,
initiator_cred_handle,
context_handle,
target_name,
mech_type,
req_flags,
time_req,
input_chan_bindings,
input_token,
actual_mech_type,
output_token, ret_flags, time_rec);
if (GSS_ERROR (maj_stat) && freecontext)
{
free (*context_handle);
*context_handle = GSS_C_NO_CONTEXT;
}
return maj_stat;
}
|
↓
|
gss_krb5_canonicalize_name
|
14
|
40
|
83
|
lib/krb5/name.c
|
OM_uint32
gss_krb5_canonicalize_name (OM_uint32 * minor_status,
const gss_name_t input_name,
const gss_OID mech_type, gss_name_t * output_name)
{
OM_uint32 maj_stat;
if (minor_status)
*minor_status = 0;
/* We consider (a zero terminated) GSS_KRB5_NT_PRINCIPAL_NAME the
canonical mechanism name type. Convert everything into it. */
if (gss_oid_equal (input_name->type, GSS_C_NT_EXPORT_NAME))
{
if (input_name->length > 15)
{
*output_name = malloc (sizeof (**output_name));
if (!*output_name)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
(*output_name)->type = GSS_KRB5_NT_PRINCIPAL_NAME;
(*output_name)->length = input_name->length - 15;
(*output_name)->value = malloc ((*output_name)->length + 1);
if (!(*output_name)->value)
{
free (*output_name);
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
memcpy ((*output_name)->value, input_name->value + 15,
(*output_name)->length);
(*output_name)->value[(*output_name)->length] = '\0';
}
else
{
return GSS_S_BAD_NAME;
}
}
else if (gss_oid_equal (input_name->type, GSS_C_NT_HOSTBASED_SERVICE))
{
char *p;
/* We don't support service-names without hostname part because
we can't compute a canonicalized name of the local host.
Calling gethostname does not give a canonicalized name. */
if (!memchr (input_name->value, '@', input_name->length))
{
*minor_status = GSS_KRB5_S_G_BAD_SERVICE_NAME;
return GSS_S_COMPLETE;
}
/* We don't do DNS name canoncalization since that is
insecure. */
maj_stat = gss_duplicate_name (minor_status, input_name, output_name);
if (GSS_ERROR (maj_stat))
return maj_stat;
(*output_name)->type = GSS_KRB5_NT_PRINCIPAL_NAME;
p = memchr ((*output_name)->value, '@', (*output_name)->length);
if (p)
*p = '/';
}
else if (gss_oid_equal (input_name->type, GSS_KRB5_NT_PRINCIPAL_NAME))
{
maj_stat = gss_duplicate_name (minor_status, input_name, output_name);
if (GSS_ERROR (maj_stat))
return maj_stat;
}
else
{
*output_name = GSS_C_NO_NAME;
return GSS_S_BAD_NAMETYPE;
}
return GSS_S_COMPLETE;
}
|
↓
|
gss_add_oid_set_member
|
13
|
29
|
56
|
lib/misc.c
|
OM_uint32
gss_add_oid_set_member (OM_uint32 * minor_status,
const gss_OID member_oid, gss_OID_set * oid_set)
{
OM_uint32 major_stat;
int present;
if (!member_oid || member_oid->length == 0 || member_oid->elements == NULL)
{
if (minor_status)
*minor_status = 0;
return GSS_S_FAILURE;
}
major_stat = gss_test_oid_set_member (minor_status, member_oid,
*oid_set, &present);
if (GSS_ERROR (major_stat))
return major_stat;
if (present)
{
if (minor_status)
*minor_status = 0;
return GSS_S_COMPLETE;
}
if ((*oid_set)->count + 1 == 0) /* integer overflow */
{
if (minor_status)
*minor_status = 0;
return GSS_S_FAILURE;
}
(*oid_set)->count++;
{
gss_OID tmp;
tmp = realloc ((*oid_set)->elements, (*oid_set)->count *
sizeof (*(*oid_set)->elements));
if (!tmp)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
(*oid_set)->elements = tmp;
}
major_stat = _gss_copy_oid (minor_status, member_oid,
(*oid_set)->elements + ((*oid_set)->count - 1));
if (GSS_ERROR (major_stat))
return major_stat;
return GSS_S_COMPLETE;
}
|
↓
|
acquire_cred1
|
12
|
35
|
69
|
lib/krb5/cred.c
|
static OM_uint32
acquire_cred1 (OM_uint32 * minor_status,
const gss_name_t desired_name,
OM_uint32 time_req,
const gss_OID_set desired_mechs,
gss_cred_usage_t cred_usage,
gss_cred_id_t * output_cred_handle,
gss_OID_set * actual_mechs, OM_uint32 * time_rec)
{
gss_name_t name = desired_name;
_gss_krb5_cred_t k5 = (*output_cred_handle)->krb5;
OM_uint32 maj_stat;
if (desired_name == GSS_C_NO_NAME)
{
gss_buffer_desc buf = { 4, (char *) "host" };
maj_stat = gss_import_name (minor_status, &buf,
GSS_C_NT_HOSTBASED_SERVICE, &name);
if (GSS_ERROR (maj_stat))
return maj_stat;
}
maj_stat = gss_krb5_canonicalize_name (minor_status, name,
GSS_KRB5, &k5->peerptr);
if (GSS_ERROR (maj_stat))
return maj_stat;
if (k5->peerptr == GSS_C_NO_NAME)
{
maj_stat = gss_release_name (minor_status, &name);
if (GSS_ERROR (maj_stat))
return maj_stat;
return GSS_S_BAD_NAME;
}
if (shishi_init_server (&k5->sh) != SHISHI_OK)
return GSS_S_FAILURE;
{
char *p;
p = malloc (k5->peerptr->length + 1);
if (!p)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
memcpy (p, k5->peerptr->value, k5->peerptr->length);
p[k5->peerptr->length] = 0;
k5->key = shishi_hostkeys_for_serverrealm (k5->sh, p, NULL);
free (p);
}
if (!k5->key)
{
if (minor_status)
*minor_status = GSS_KRB5_S_KG_KEYTAB_NOMATCH;
return GSS_S_NO_CRED;
}
if (time_rec)
*time_rec = GSS_C_INDEFINITE;
return GSS_S_COMPLETE;
}
|
↓
|
_gss_krb5_checksum_parse
|
11
|
39
|
72
|
lib/krb5/checksum.c
|
OM_uint32
_gss_krb5_checksum_parse (OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
const gss_channel_bindings_t input_chan_bindings)
{
gss_ctx_id_t ctx = *context_handle;
_gss_krb5_ctx_t k5 = ctx->krb5;
char *out = NULL;
size_t len = 0;
int rc;
char *md5hash;
if (shishi_ap_authenticator_cksumtype (k5->ap) != 0x8003)
{
if (minor_status)
*minor_status = GSS_KRB5_S_G_VALIDATE_FAILED;
return GSS_S_FAILURE;
}
rc = shishi_ap_authenticator_cksumdata (k5->ap, out, &len);
if (rc != SHISHI_TOO_SMALL_BUFFER)
return GSS_S_FAILURE;
out = malloc (len);
if (!out)
{
if (minor_status)
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
rc = shishi_ap_authenticator_cksumdata (k5->ap, out, &len);
if (rc != SHISHI_OK)
{
free (out);
return GSS_S_FAILURE;
}
if (memcmp (out, "\x10\x00\x00\x00", 4) != 0)
{
free (out);
return GSS_S_DEFECTIVE_TOKEN;
}
if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS)
{
rc = hash_cb (minor_status, context_handle,
input_chan_bindings, &md5hash);
if (rc != GSS_S_COMPLETE)
{
free (out);
return GSS_S_DEFECTIVE_TOKEN;
}
rc = memcmp (&out[4], md5hash, 16);
free (md5hash);
}
else
{
char zeros[16];
memset (&zeros[0], 0, sizeof zeros);
rc = memcmp (&out[4], zeros, 16);
}
free (out);
if (rc != 0)
return GSS_S_DEFECTIVE_TOKEN;
return GSS_S_COMPLETE;
}
|
↓
|
_gss_decapsulate_token
|
11
|
35
|
53
|
lib/asn1.c
|
int
_gss_decapsulate_token (const char *in, size_t inlen,
char **oid, size_t *oidlen,
char **out, size_t *outlen)
{
size_t i;
size_t asn1lenlen;
if (inlen-- == 0)
return -1;
if (*in++ != '\x60')
return -1;
i = inlen;
asn1lenlen = _gss_asn1_get_length_der (in, inlen, &i);
if (inlen < i)
return -1;
inlen -= i;
in += i;
if (inlen != asn1lenlen)
return -1;
if (inlen-- == 0)
return -1;
if (*in++ != '\x06')
return -1;
i = inlen;
asn1lenlen = _gss_asn1_get_length_der (in, inlen, &i);
if (inlen < i)
return -1;
inlen -= i;
in += i;
if (inlen < asn1lenlen)
return -1;
*oidlen = asn1lenlen;
*oid = (char *) in;
inlen -= asn1lenlen;
in += asn1lenlen;
if (outlen)
*outlen = inlen;
if (out)
*out = (char *) in;
return 0;
}
|
↓
|
gss_inquire_saslname_for_mech
|
11
|
24
|
47
|
lib/saslname.c
|
OM_uint32
gss_inquire_saslname_for_mech (OM_uint32 * minor_status,
const gss_OID desired_mech,
gss_buffer_t sasl_mech_name,
gss_buffer_t mech_name,
gss_buffer_t mech_description)
{
_gss_mech_api_t m;
if (!desired_mech)
{
if (minor_status)
*minor_status = 0;
return GSS_S_CALL_INACCESSIBLE_READ;
}
m = _gss_find_mech_no_default (desired_mech);
if (!m)
{
if (minor_status)
*minor_status = 0;
return GSS_S_BAD_MECH;
}
bindtextdomain (PACKAGE PO_SUFFIX, LOCALEDIR);
if (dup_data (minor_status, sasl_mech_name,
m->sasl_name, 0) != GSS_S_COMPLETE)
return GSS_S_FAILURE;
if (dup_data (minor_status, mech_name, m->mech_name, 0) != GSS_S_COMPLETE)
{
if (sasl_mech_name)
free (sasl_mech_name->value);
return GSS_S_FAILURE;
}
if (dup_data (minor_status, mech_description,
m->mech_description, 1) != GSS_S_COMPLETE)
{
if (sasl_mech_name)
free (sasl_mech_name->value);
if (mech_name)
free (mech_name->value);
return GSS_S_FAILURE;
}
return GSS_S_COMPLETE;
}
|
|
init_request
|
10
|
38
|
81
|
lib/krb5/context.c
|
|
hash_cb
|
10
|
36
|
61
|
lib/krb5/checksum.c
|
|
gss_acquire_cred
|
10
|
27
|
63
|
lib/cred.c
|
|
gss_duplicate_name
|
10
|
26
|
42
|
lib/name.c
|
|
inquire_cred
|
10
|
21
|
40
|
lib/krb5/cred.c
|
|
gss_accept_sec_context
|
9
|
26
|
67
|
lib/context.c
|
|
gss_krb5_acquire_cred
|
9
|
25
|
53
|
lib/krb5/cred.c
|
|
gss_krb5_display_status
|
9
|
25
|
68
|
lib/krb5/error.c
|
|
gss_delete_sec_context
|
8
|
22
|
43
|
lib/context.c
|
|
gss_import_name
|
8
|
21
|
37
|
lib/name.c
|
|
gss_release_cred
|
8
|
21
|
36
|
lib/cred.c
|
|
gss_inquire_cred_by_mech
|
8
|
20
|
51
|
lib/cred.c
|
|
gss_inquire_cred
|
8
|
20
|
43
|
lib/cred.c
|
|
gss_display_name
|
8
|
17
|
30
|
lib/name.c
|
|
gss_compare_name
|
7
|
9
|
20
|
lib/name.c
|
|
_gss_find_mech_by_saslname
|
7
|
9
|
17
|
lib/meta.c
|
|
init_reply
|
7
|
24
|
58
|
lib/krb5/context.c
|
|
gss_decapsulate_token
|
7
|
21
|
35
|
lib/asn1.c
|
|
_gss_asn1_get_length_der
|
7
|
20
|
43
|
lib/asn1.c
|
|
_gss_copy_oid
|
7
|
14
|
25
|
lib/misc.c
|
|
_gss_krb5_checksum_pack
|
6
|
25
|
124
|
lib/krb5/checksum.c
|
|
_gss_inquire_mechs_for_name3
|
6
|
17
|
30
|
lib/name.c
|
|
gss_export_name
|
6
|
16
|
33
|
lib/name.c
|
|
gss_inquire_mechs_for_name
|
6
|
15
|
30
|
lib/name.c
|
|
_gss_asn1_length_der
|
6
|
15
|
32
|
lib/asn1.c
|
|
gss_test_oid_set_member
|
6
|
14
|
28
|
lib/misc.c
|
|
gss_inquire_mech_for_saslname
|
6
|
13
|
27
|
lib/saslname.c
|
|
gss_inquire_names_for_mech
|
5
|
17
|
29
|
lib/name.c
|
|
gss_release_oid_set
|
5
|
14
|
20
|
lib/misc.c
|
|
gss_context_time
|
5
|
11
|
23
|
lib/context.c
|
|
gss_get_mic
|
5
|
11
|
26
|
lib/msg.c
|
|
gss_krb5_delete_sec_context
|
5
|
11
|
21
|
lib/krb5/context.c
|
|
dup_data
|
5
|
11
|
21
|
lib/saslname.c
|
|
gss_unwrap
|
5
|
11
|
27
|
lib/msg.c
|
|
gss_wrap
|
5
|
11
|
28
|
lib/msg.c
|
|
gss_encapsulate_token
|
5
|
11
|
25
|
lib/asn1.c
|
|
gss_verify_mic
|
5
|
11
|
26
|
lib/msg.c
|
|
gss_krb5_context_time
|
5
|
10
|
23
|
lib/krb5/context.c
|
|
gss_release_name
|
5
|
10
|
20
|
lib/name.c
|
|
_gss_encapsulate_token_prefix
|
4
|
25
|
39
|
lib/asn1.c
|
|
gss_krb5_export_name
|
4
|
20
|
32
|
lib/krb5/name.c
|
|
_gss_inquire_mechs_for_name1
|
4
|
12
|
22
|
lib/name.c
|
|
_gss_inquire_mechs_for_name2
|
4
|
11
|
22
|
lib/name.c
|
|
gss_indicate_mechs
|
4
|
11
|
20
|
lib/misc.c
|
|
_gss_indicate_mechs1
|
4
|
11
|
18
|
lib/meta.c
|
|
gss_create_empty_oid_set
|
4
|
10
|
18
|
lib/misc.c
|
|
gss_oid_equal
|
4
|
1
|
8
|
lib/oid.c
|
|
gss_krb5_release_cred
|
3
|
9
|
16
|
lib/krb5/cred.c
|
|
gss_krb5_tktlifetime
|
3
|
8
|
16
|
lib/krb5/utils.c
|
|
_gss_find_mech_no_default
|
3
|
7
|
11
|
lib/meta.c
|
|
gss_canonicalize_name
|
3
|
7
|
18
|
lib/name.c
|
|
gss_release_buffer
|
3
|
7
|
15
|
lib/misc.c
|
|
_gss_find_mech
|
3
|
4
|
12
|
lib/meta.c
|
|
gss_check_version
|
3
|
3
|
8
|
lib/version.c
|
|
gss_krb5_inquire_cred_by_mech
|
2
|
5
|
19
|
lib/krb5/cred.c
|
|
gss_userok
|
2
|
1
|
7
|
lib/ext.c
|
|
pack_uint32
|
1
|
4
|
8
|
lib/krb5/checksum.c
|
|
gss_process_context_token
|
1
|
1
|
7
|
lib/context.c
|
|
gss_unseal
|
1
|
1
|
11
|
lib/obsolete.c
|
|
gss_seal
|
1
|
1
|
12
|
lib/obsolete.c
|
|
gss_krb5_verify_mic
|
1
|
1
|
8
|
lib/krb5/msg.c
|
|
gss_verify
|
1
|
1
|
9
|
lib/obsolete.c
|
|
gss_krb5_get_mic
|
1
|
1
|
9
|
lib/krb5/msg.c
|
|
gss_sign
|
1
|
1
|
9
|
lib/obsolete.c
|
|
gss_add_cred
|
1
|
1
|
14
|
lib/cred.c
|
|
gss_krb5_inquire_cred
|
1
|
1
|
11
|
lib/krb5/cred.c
|
|
gss_import_sec_context
|
1
|
1
|
7
|
lib/context.c
|
|
gss_export_sec_context
|
1
|
1
|
7
|
lib/context.c
|
|
gss_wrap_size_limit
|
1
|
1
|
9
|
lib/context.c
|
|
gss_inquire_context
|
1
|
1
|
11
|
lib/context.c
|