GSSAPI: Avoid dissecting checksum in signed-only KRB_TOKEN_CFX_WRAP

In KRB_TOKEN_CFX_WRAP (RFC 4121), for signed-only Wrap tokens
("Wrap tokens without confidentiality"), the plaintext is followed
by the checksum, unlike in other implementations where the all
the GSSAPI bits, including the checksum, precede the plaintext.

For those cases, the calling dissector cannot simply dissect
the entire original tvb after the returned offset, as it's not
all plaintext. Instead, place the plaintext without checksum
subset in gssapi_decrypted_tvb and return it to the caller.
In these cases, gssapi_data_encrypted will be set to FALSE, to
allow dissectors that wish to distinguished signed-and-sealed
from signed-only. For dissectors that do not care to distinguish
the cases, this requires no change.

Update the documentation in the GSSAPI header to describe this.

Fix #9398.
This commit is contained in:
John Thacker 2024-02-25 08:41:08 -05:00
parent 09f6a3aaa6
commit 3540bbc969
6 changed files with 105 additions and 76 deletions

View File

@ -1247,41 +1247,46 @@ static void
if(ver_len==0){
return;
}
if (gssapi_encrypt.gssapi_decrypted_tvb) {
tvbuff_t *decr_tvb = gssapi_encrypt.gssapi_decrypted_tvb;
proto_tree *enc_tree = NULL;
if (gssapi_encrypt.gssapi_data_encrypted) {
if (gssapi_encrypt.gssapi_decrypted_tvb) {
tvbuff_t *decr_tvb = gssapi_encrypt.gssapi_decrypted_tvb;
proto_tree *enc_tree = NULL;
/*
* The LDAP payload (blob) was encrypted and we were able to decrypt it.
* The data was signed via a MIC token, sealed (encrypted), and "wrapped"
* within the mechanism's "blob." Call dissect_ldap_payload to dissect
* one or more LDAPMessages such as searchRequest messages within this
* payload.
*/
col_set_str(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy (decrypted): ");
/*
* The LDAP payload (blob) was encrypted and we were able to decrypt it.
* The data was signed via a MIC token, sealed (encrypted), and "wrapped"
* within the mechanism's "blob." Call dissect_ldap_payload to dissect
* one or more LDAPMessages such as searchRequest messages within this
* payload.
*/
col_set_str(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy (decrypted): ");
if (sasl_tree) {
guint decr_len = tvb_reported_length(decr_tvb);
if (sasl_tree) {
guint decr_len = tvb_reported_length(decr_tvb);
enc_tree = proto_tree_add_subtree_format(sasl_tree, decr_tvb, 0, -1,
ett_ldap_payload, NULL, "GSS-API Encrypted payload (%d byte%s)",
decr_len, plurality(decr_len, "", "s"));
enc_tree = proto_tree_add_subtree_format(sasl_tree, decr_tvb, 0, -1,
ett_ldap_payload, NULL, "GSS-API Encrypted payload (%d byte%s)",
decr_len, plurality(decr_len, "", "s"));
}
dissect_ldap_payload(decr_tvb, pinfo, enc_tree, ldap_info, is_mscldap);
} else {
/*
* The LDAP message was encrypted but couldn't be decrypted so just display the
* encrypted data all of which is found in Packet Bytes.
*/
col_add_fstr(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy: payload (%d byte%s)",
sasl_len-ver_len, plurality(sasl_len-ver_len, "", "s"));
proto_tree_add_item(sasl_tree, hf_ldap_gssapi_encrypted_payload, gssapi_tvb, ver_len, -1, ENC_NA);
}
} else {
tvbuff_t *plain_tvb;
if (gssapi_encrypt.gssapi_decrypted_tvb) {
plain_tvb = gssapi_encrypt.gssapi_decrypted_tvb;
} else {
plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len);
}
dissect_ldap_payload(decr_tvb, pinfo, enc_tree, ldap_info, is_mscldap);
}
else if (gssapi_encrypt.gssapi_data_encrypted) {
/*
* The LDAP message was encrypted but couldn't be decrypted so just display the
* encrypted data all of which is found in Packet Bytes.
*/
col_add_fstr(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy: payload (%d byte%s)",
sasl_len-ver_len, plurality(sasl_len-ver_len, "", "s"));
proto_tree_add_item(sasl_tree, hf_ldap_gssapi_encrypted_payload, gssapi_tvb, ver_len, -1, ENC_NA);
}
else {
tvbuff_t *plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len);
proto_tree *plain_tree = NULL;
/*

View File

@ -1029,6 +1029,8 @@ dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo,
returned_offset = offset;
gssapi_encrypt->gssapi_wrap_tvb = tvb_new_subset_length(tvb, offset,
inner_token_len);
gssapi_encrypt->gssapi_decrypted_tvb = tvb_new_subset_length(tvb, offset,
inner_token_len);
offset += inner_token_len;

View File

@ -27,13 +27,20 @@ typedef struct _gssapi_oid_value {
/**< Extra data for handling of decryption of GSSAPI wrapped tvbuffs.
Caller sets decrypt_gssapi_tvb if this service is requested.
If gssapi_encrypted_tvb is NULL, then the rest of the tvb data following
the gssapi blob itself is decrypted othervise the gssapi_encrypted_tvb
tvb will be decrypted (DCERPC has the data before the gssapi blob)
If, on return, gssapi_data_encrypted is FALSE, the wrapped tvbuff
was signed (i.e., an encrypted signature was present, to check
If, on a successful return, gssapi_data_encrypted is FALSE, the wrapped
tvbuff was signed (i.e., an encrypted signature was present, to check
whether the data was modified by a man in the middle) but not sealed
(i.e., the data itself wasn't encrypted).
If gssapi_encrypted_tvb is NULL, then the rest of the tvb data following
the gssapi blob itself is decrypted otherwise the gssapi_encrypted_tvb
tvb will be decrypted (DCERPC has the data before the gssapi blob).
In the latter case, gssapi_decrypted_tvb contains the decrypted data if
decryption is successful and is NULL if not.
If gssapi_data_encrypted is FALSE and gssapi_decrypted_tvb is not NULL,
then it contains the plaintext data, for cases when the plaintext data
was followed by the checksum, e.g. KRB_TOKEN_CFX_WRAP (RFC 4121),
as the calling dissector cannot simply dissect all the data after
the returned offset.
*/
typedef struct _gssapi_encrypt_info
{

View File

@ -4053,41 +4053,46 @@ static void
if(ver_len==0){
return;
}
if (gssapi_encrypt.gssapi_decrypted_tvb) {
tvbuff_t *decr_tvb = gssapi_encrypt.gssapi_decrypted_tvb;
proto_tree *enc_tree = NULL;
if (gssapi_encrypt.gssapi_data_encrypted) {
if (gssapi_encrypt.gssapi_decrypted_tvb) {
tvbuff_t *decr_tvb = gssapi_encrypt.gssapi_decrypted_tvb;
proto_tree *enc_tree = NULL;
/*
* The LDAP payload (blob) was encrypted and we were able to decrypt it.
* The data was signed via a MIC token, sealed (encrypted), and "wrapped"
* within the mechanism's "blob." Call dissect_ldap_payload to dissect
* one or more LDAPMessages such as searchRequest messages within this
* payload.
*/
col_set_str(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy (decrypted): ");
/*
* The LDAP payload (blob) was encrypted and we were able to decrypt it.
* The data was signed via a MIC token, sealed (encrypted), and "wrapped"
* within the mechanism's "blob." Call dissect_ldap_payload to dissect
* one or more LDAPMessages such as searchRequest messages within this
* payload.
*/
col_set_str(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy (decrypted): ");
if (sasl_tree) {
guint decr_len = tvb_reported_length(decr_tvb);
if (sasl_tree) {
guint decr_len = tvb_reported_length(decr_tvb);
enc_tree = proto_tree_add_subtree_format(sasl_tree, decr_tvb, 0, -1,
ett_ldap_payload, NULL, "GSS-API Encrypted payload (%d byte%s)",
decr_len, plurality(decr_len, "", "s"));
enc_tree = proto_tree_add_subtree_format(sasl_tree, decr_tvb, 0, -1,
ett_ldap_payload, NULL, "GSS-API Encrypted payload (%d byte%s)",
decr_len, plurality(decr_len, "", "s"));
}
dissect_ldap_payload(decr_tvb, pinfo, enc_tree, ldap_info, is_mscldap);
} else {
/*
* The LDAP message was encrypted but couldn't be decrypted so just display the
* encrypted data all of which is found in Packet Bytes.
*/
col_add_fstr(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy: payload (%d byte%s)",
sasl_len-ver_len, plurality(sasl_len-ver_len, "", "s"));
proto_tree_add_item(sasl_tree, hf_ldap_gssapi_encrypted_payload, gssapi_tvb, ver_len, -1, ENC_NA);
}
} else {
tvbuff_t *plain_tvb;
if (gssapi_encrypt.gssapi_decrypted_tvb) {
plain_tvb = gssapi_encrypt.gssapi_decrypted_tvb;
} else {
plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len);
}
dissect_ldap_payload(decr_tvb, pinfo, enc_tree, ldap_info, is_mscldap);
}
else if (gssapi_encrypt.gssapi_data_encrypted) {
/*
* The LDAP message was encrypted but couldn't be decrypted so just display the
* encrypted data all of which is found in Packet Bytes.
*/
col_add_fstr(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy: payload (%d byte%s)",
sasl_len-ver_len, plurality(sasl_len-ver_len, "", "s"));
proto_tree_add_item(sasl_tree, hf_ldap_gssapi_encrypted_payload, gssapi_tvb, ver_len, -1, ENC_NA);
}
else {
tvbuff_t *plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len);
proto_tree *plain_tree = NULL;
/*

View File

@ -872,18 +872,26 @@ dissect_pgsql_gssapi_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, v
/* GSS-API couldn't do anything with it. */
return tvb_captured_length(tvb);
}
if (encrypt.gssapi_decrypted_tvb) {
tvbuff_t *decr_tvb = encrypt.gssapi_decrypted_tvb;
add_new_data_source(pinfo, encrypt.gssapi_decrypted_tvb, "Decrypted GSS-API");
dissect_pgsql_msg(decr_tvb, pinfo, ptree, data);
} else if (encrypt.gssapi_data_encrypted) {
/* Encrypted but couldn't be decrypted. */
proto_tree_add_item(ptree, hf_gssapi_encrypted_payload, gssapi_tvb, ver_len, -1, ENC_NA);
if (encrypt.gssapi_data_encrypted) {
if (encrypt.gssapi_decrypted_tvb) {
tvbuff_t *decr_tvb = encrypt.gssapi_decrypted_tvb;
add_new_data_source(pinfo, encrypt.gssapi_decrypted_tvb, "Decrypted GSS-API");
dissect_pgsql_msg(decr_tvb, pinfo, ptree, data);
} else {
/* Encrypted but couldn't be decrypted. */
proto_tree_add_item(ptree, hf_gssapi_encrypted_payload, gssapi_tvb, ver_len, -1, ENC_NA);
}
} else {
/* No encrypted (sealed) payload. If any bytes are left, that is
* signed-only payload. */
if (tvb_reported_length_remaining(gssapi_tvb, ver_len)) {
dissect_pgsql_msg(tvb_new_subset_remaining(gssapi_tvb, ver_len), pinfo, ptree, data);
tvbuff_t *plain_tvb;
if (encrypt.gssapi_decrypted_tvb) {
plain_tvb = encrypt.gssapi_decrypted_tvb;
} else {
plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len);
}
if (tvb_reported_length(plain_tvb)) {
dissect_pgsql_msg(plain_tvb, pinfo, ptree, data);
}
}
return tvb_captured_length(tvb);

View File

@ -1479,6 +1479,8 @@ dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo,
returned_offset = offset;
gssapi_encrypt->gssapi_wrap_tvb = tvb_new_subset_length(tvb, offset,
inner_token_len);
gssapi_encrypt->gssapi_decrypted_tvb = tvb_new_subset_length(tvb, offset,
inner_token_len);
offset += inner_token_len;