OM_uint32 major, tmp;
sanon_ctx sc = (sanon_ctx)*context_handle;
gss_buffer_desc mech_input_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc initiator_pk = GSS_C_EMPTY_BUFFER;
gss_buffer_desc hok_mic = GSS_C_EMPTY_BUFFER;
gss_buffer_desc session_key = GSS_C_EMPTY_BUFFER;
+ OM_uint32 req_flags = 0;
if (output_token == GSS_C_NO_BUFFER) {
*minor = EINVAL;
if (input_token == GSS_C_NO_BUFFER) {
major = GSS_S_DEFECTIVE_TOKEN;
goto out;
- } else if (sc != NULL && sc->rfc4121 != GSS_C_NO_CONTEXT) {
+ } else if (sc != NULL) {
major = GSS_S_BAD_STATUS;
goto out;
}
if (major != GSS_S_COMPLETE)
goto out;
+ sc = calloc(1, sizeof(*sc));
if (sc == NULL) {
- sc = calloc(1, sizeof(*sc));
- if (sc == NULL) {
- *minor = ENOMEM;
- major = GSS_S_FAILURE;
- goto out;
- }
+ *minor = ENOMEM;
+ major = GSS_S_FAILURE;
+ goto out;
+ }
+
+ /* initiator token can include optional 64-bit flags */
+ if (mech_input_token.length != crypto_scalarmult_curve25519_BYTES &&
+ mech_input_token.length != crypto_scalarmult_curve25519_BYTES + 8) {
+ *minor = 0;
+ major = GSS_S_DEFECTIVE_TOKEN;
+ goto out;
}
+ initiator_pk = mech_input_token;
+ initiator_pk.length = crypto_scalarmult_curve25519_BYTES;
+
/* compute public and secret keys */
major = _gss_sanon_curve25519_base(minor, sc);
if (major != GSS_S_COMPLETE)
goto out;
+ if (mech_input_token.length > crypto_scalarmult_curve25519_BYTES) {
+ /* extra flags */
+ uint8_t *p = (uint8_t *)mech_input_token.value + crypto_scalarmult_curve25519_BYTES;
+ uint32_t dummy;
+
+ _gss_mg_decode_be_uint32(p, &dummy); /* upper 32 bits presently unused */
+ _gss_mg_decode_be_uint32(&p[4], &req_flags);
+ }
+
+ req_flags &= SANON_PROTOCOL_FLAG_MASK; /* do not let initiator set any other flags */
+
/* compute shared secret */
- major = _gss_sanon_curve25519(minor, sc, &mech_input_token,
+ major = _gss_sanon_curve25519(minor, sc, &initiator_pk, req_flags,
input_chan_bindings, &session_key);
if (major != GSS_S_COMPLETE)
goto out;
- sc->flags |= GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG |
+ req_flags |= GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG |
GSS_C_INTEG_FLAG | GSS_C_ANON_FLAG | GSS_C_TRANS_FLAG;
- major = _gss_sanon_import_rfc4121_context(minor, sc, &session_key);
+ major = _gss_sanon_import_rfc4121_context(minor, sc, req_flags, &session_key);
if (major != GSS_S_COMPLETE)
goto out;
if (src_name)
*src_name = _gss_sanon_anonymous_identity;
if (ret_flags)
- *ret_flags = sc->flags;
+ *ret_flags = req_flags;
if (time_rec)
*time_rec = GSS_C_INDEFINITE;
_gss_sanon_curve25519(OM_uint32 *minor,
sanon_ctx sc,
gss_buffer_t pk,
+ OM_uint32 gss_flags,
const gss_channel_bindings_t input_chan_bindings,
gss_buffer_t session_key)
{
kdf_label.length = sizeof("sanon-x25519") - 1;
ret = krb5_data_alloc(&kdf_context,
- 2 * crypto_scalarmult_curve25519_BYTES +
+ 2 * crypto_scalarmult_curve25519_BYTES + 8 +
(input_chan_bindings ? input_chan_bindings->application_data.length : 0));
if (ret != 0) {
krb5_free_context(context);
memcpy(p, pk->value, pk->length);
memcpy(&p[sizeof(sc->pk)], sc->pk, sizeof(sc->pk));
}
+ p += 2 * crypto_scalarmult_curve25519_BYTES;
+ _gss_mg_encode_be_uint32(0, p); /* upper 32 bits presently unused */
+ p += 4;
+ _gss_mg_encode_be_uint32(gss_flags, p);
+ p += 4;
if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS &&
input_chan_bindings->application_data.value != NULL) {
- memcpy(&p[2 * crypto_scalarmult_curve25519_BYTES],
- input_chan_bindings->application_data.value,
+ memcpy(p, input_chan_bindings->application_data.value,
input_chan_bindings->application_data.length);
}
OM_uint32
_gss_sanon_import_rfc4121_context(OM_uint32 *minor,
sanon_ctx sc,
+ OM_uint32 gss_flags,
gss_const_buffer_t session_key)
{
- return _gss_mg_import_rfc4121_context(minor, sc->is_initiator, sc->flags,
+ return _gss_mg_import_rfc4121_context(minor, sc->is_initiator, gss_flags,
KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
session_key, &sc->rfc4121);
}
}
flags |= GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG |
- GSS_C_INTEG_FLAG | GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
- GSS_C_EXTENDED_ERROR_FLAG; /* supported flags */
+ GSS_C_INTEG_FLAG | SANON_PROTOCOL_FLAG_MASK; /* supported flags */
flags &= req_flags;
flags |= GSS_C_ANON_FLAG; /* always set this flag */
if (sc == NULL) {
+ uint8_t pk_and_flags[crypto_scalarmult_curve25519_BYTES + 8];
+
if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
major = GSS_S_DEFECTIVE_TOKEN;
goto out;
}
sc->is_initiator = 1;
- sc->flags = req_flags;
/* compute public and secret keys */
major = _gss_sanon_curve25519_base(minor, sc);
if (major != GSS_S_COMPLETE)
goto out;
- mech_token.length = sizeof(sc->pk);
- mech_token.value = sc->pk;
+ if (req_flags & SANON_PROTOCOL_FLAG_MASK) {
+ memcpy(pk_and_flags, sc->pk, sizeof(sc->pk));
+ _gss_mg_encode_be_uint32(0, &pk_and_flags[sizeof(sc->pk)]);
+ _gss_mg_encode_be_uint32(req_flags & SANON_PROTOCOL_FLAG_MASK,
+ &pk_and_flags[sizeof(sc->pk) + 4]);
+ mech_token.length = sizeof(pk_and_flags);
+ mech_token.value = pk_and_flags;
+ } else {
+ mech_token.length = sizeof(sc->pk);
+ mech_token.value = sc->pk;
+ }
/* send public key to acceptor */
major = gss_encapsulate_token(&mech_token,
pk.value = input_token->value;
/* compute shared secret */
- major = _gss_sanon_curve25519(minor, sc, &pk, input_chan_bindings, &session_key);
+ major = _gss_sanon_curve25519(minor, sc, &pk, flags & SANON_PROTOCOL_FLAG_MASK,
+ input_chan_bindings, &session_key);
if (major != GSS_S_COMPLETE)
goto out;
flags |= GSS_C_TRANS_FLAG;
- sc->flags |= GSS_C_TRANS_FLAG;
- major = _gss_sanon_import_rfc4121_context(minor, sc, &session_key);
+ major = _gss_sanon_import_rfc4121_context(minor, sc, flags, &session_key);
if (major != GSS_S_COMPLETE)
goto out;
if (open_context)
*open_context = 0;
if (ctx_flags)
- *ctx_flags = sc->flags;
+ *ctx_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG |
+ GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG | GSS_C_ANON_FLAG;
} else {
major = gss_inquire_context(minor, sc->rfc4121, NULL, NULL, NULL,
NULL, ctx_flags, locally_initiated,
return major;
}
-static OM_uint32
-make_flags_meta_data(OM_uint32 *minor,
- OM_uint32 flags,
- gss_buffer_t meta_data)
-{
- uint8_t data[4];
- gss_buffer_desc buffer = { sizeof(data), data };
-
- _gss_mg_encode_le_uint32(flags, data);
-
- return _gss_copy_buffer(minor, &buffer, meta_data);
-}
-
OM_uint32 GSSAPI_CALLCONV
_gssspi_sanon_query_meta_data(OM_uint32 *minor,
gss_const_OID mech_oid,
OM_uint32 req_flags,
gss_buffer_t meta_data)
{
- OM_uint32 major;
- int local = (targ_name != GSS_C_NO_NAME);
+ int is_initiator = (targ_name != GSS_C_NO_NAME);
*minor = 0;
- if (local) {
- if (!_gss_sanon_available_p(cred_handle, targ_name, req_flags))
- return GSS_S_UNAVAILABLE;
-
- /*
- * Obscure Windows interoperability hack: use metadata to convey
- * RFC4757 extended flags from initiator to acceptor.
- */
- req_flags &= (GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG);
- if (req_flags) {
- major = make_flags_meta_data(minor, req_flags, meta_data);
- if (major != GSS_S_COMPLETE)
- return major;
- }
- }
-
- return GSS_S_COMPLETE;
-}
-
-static OM_uint32
-parse_flags_meta_data(OM_uint32 *minor,
- gss_const_buffer_t meta_data,
- OM_uint32 *flags)
-{
- *minor = 0;
- *flags = 0;
-
- if (meta_data->length == 0)
- return GSS_S_COMPLETE;
-
- if (meta_data->length < 4)
- return GSS_S_DEFECTIVE_TOKEN;
-
- _gss_mg_decode_le_uint32(meta_data->value, flags);
+ if (is_initiator &&
+ !_gss_sanon_available_p(cred_handle, targ_name, req_flags))
+ return GSS_S_UNAVAILABLE;
return GSS_S_COMPLETE;
}
OM_uint32 req_flags,
gss_const_buffer_t meta_data)
{
- sanon_ctx sc = (sanon_ctx)*context_handle;
- int local = (targ_name != GSS_C_NO_NAME);
- OM_uint32 major, init_flags;
-
*minor = 0;
-
- if (local)
- return GSS_S_COMPLETE;
-
- if (sc == NULL) {
- sc = calloc(1, sizeof(*sc));
- if (sc == NULL) {
- *minor = ENOMEM;
- return GSS_S_FAILURE;
- }
- *context_handle = (gss_ctx_id_t)sc;
- }
-
- major = parse_flags_meta_data(minor, meta_data, &init_flags);
- if (major != GSS_S_COMPLETE)
- return major;
-
- init_flags &= ~(GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG);
- sc->flags |= init_flags | req_flags;
-
return GSS_S_COMPLETE;
}
uint8_t sk[crypto_scalarmult_curve25519_BYTES];
/* X25519 ECDH public key */
uint8_t pk[crypto_scalarmult_curve25519_BYTES];
- /* GSS_C_*_FLAG */
- uint32_t flags;
/* krb5 context for message protection/PRF */
gss_ctx_id_t rfc4121;
- int is_initiator;
+ int is_initiator : 1;
} *sanon_ctx;
extern gss_name_t _gss_sanon_anonymous_identity;
memcmp(b1->value, b2->value, b2->length) == 0;
}
+/* flags that are valid to be sent from a SAnon initiator in the flags field */
+#define SANON_PROTOCOL_FLAG_MASK ( GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG )
+
#endif /* SANON_LOCL_H */