return GSSERRS(0, GSS_S_COMPLETE);
}
+gss_OID_desc reset_crypto_oid = {
+ GSS_NTLMSSP_RESET_CRYPTO_OID_LENGTH,
+ discard_const(GSS_NTLMSSP_RESET_CRYPTO_OID_STRING)
+};
+
+uint32_t gssntlm_reset_crypto(uint32_t *minor_status,
+ struct gssntlm_ctx *ctx,
+ const gss_buffer_t value)
+{
+ uint32_t retmin;
+ uint32_t retmaj;
+
+ if (value->length != 4) {
+ return GSSERRS(ERR_BADARG, GSS_S_FAILURE);
+ }
+
+ /* reset crypto state */
+ if (ctx->neg_flags & (NTLMSSP_NEGOTIATE_SIGN |
+ NTLMSSP_NEGOTIATE_SEAL)) {
+ uint32_t val;
+
+ memcpy(&val, value->value, value->length);
+
+ /* A val of 1 means we want to reset the verifier handle,
+ * which is the receive handle for NTLM, otherwise we reset
+ * the send handle. */
+ retmin = ntlm_reset_rc4_state(ctx->neg_flags, (val == 1),
+ &ctx->exported_session_key,
+ &ctx->crypto_state);
+ if (retmin) {
+ return GSSERRS(retmin, GSS_S_FAILURE);
+ }
+ }
+
+ return GSSERRS(0, GSS_S_COMPLETE);
+}
+
uint32_t gssntlm_set_sec_context_option(uint32_t *minor_status,
gss_ctx_id_t *context_handle,
const gss_OID desired_object,
/* set seq num */
if (gss_oid_equal(desired_object, &set_seq_num_oid)) {
return gssntlm_set_seq_num(minor_status, ctx, value);
+ } else if (gss_oid_equal(desired_object, &reset_crypto_oid)) {
+ return gssntlm_reset_crypto(minor_status, ctx, value);
}
return GSSERRS(ERR_BADARG, GSS_S_UNAVAILABLE);
#define GSS_SPNEGO_REQUIRE_MIC_OID_STRING GSS_NTLMSSP_BASE_OID_STRING "\x02"
#define GSS_SPNEGO_REQUIRE_MIC_OID_LENGTH GSS_NTLMSSP_BASE_OID_LENGTH + 1
+/* SPNEGO Reset Crypto OID
+ * MS-SPNG 3.3.5.1 warns hat the NTLM mechanism requires to reset the
+ * crypto engine when the SPNEGO layer uses a MechListMIC.
+ * This OID is queried by the SPNEGO mechanism after a MIC processing to
+ * cause the crypto engine to be reset.
+ */
+#define GSS_NTLMSSP_RESET_CRYPTO_OID_STRING GSS_NTLMSSP_BASE_OID_STRING "\x03"
+#define GSS_NTLMSSP_RESET_CRYPTO_OID_LENGTH GSS_NTLMSSP_BASE_OID_LENGTH + 1
+
#define GSS_NTLMSSP_CS_DOMAIN "ntlmssp_domain"
#define GSS_NTLMSSP_CS_NTHASH "ntlmssp_nthash"
#define GSS_NTLMSSP_CS_PASSWORD "ntlmssp_password"
struct ntlm_key *session_key,
struct ntlm_signseal_state *signseal_state);
+/**
+ * @brief Resets the RC4 state for the send or receive handle
+ *
+ * @param flags Incoming challenge/authenticate flags
+ * @param recv Wheter to reset the send or recive buffer
+ * @param session_key The session key
+ * @param signseal_state Sign and seal keys and state
+ *
+ * @return 0 on success or error.
+ */
+int ntlm_reset_rc4_state(uint32_t flags, bool recv,
+ struct ntlm_key *session_key,
+ struct ntlm_signseal_state *state);
+
/**
* @brief Verifies a NTLM v1 NT Response
*
}
}
+int ntlm_reset_rc4_state(uint32_t flags, bool recv,
+ struct ntlm_key *session_key,
+ struct ntlm_signseal_state *state)
+{
+ struct ntlm_buffer rc4_key;
+ int ret;
+
+ if (!(flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
+ return no_ext_sec_handle(flags, session_key,
+ &state->send.seal_handle);
+ }
+
+ if (recv) {
+ RC4_FREE(&state->recv.seal_handle);
+ rc4_key.data = state->recv.seal_key.data;
+ rc4_key.length = state->recv.seal_key.length;
+ ret = RC4_INIT(&rc4_key, NTLM_CIPHER_DECRYPT,
+ &state->recv.seal_handle);
+ } else {
+ RC4_FREE(&state->send.seal_handle);
+ rc4_key.data = state->send.seal_key.data;
+ rc4_key.length = state->send.seal_key.length;
+ ret = RC4_INIT(&rc4_key, NTLM_CIPHER_ENCRYPT,
+ &state->send.seal_handle);
+ }
+ return ret;
+}
+
static int ntlm_seal_regen(struct ntlm_signseal_handle *h)
{
struct ntlm_buffer payload;