#include "system/time.h"
#include "../lib/crypto/crypto.h"
#include "libcli/auth/libcli_auth.h"
+#include "heimdal/lib/hcrypto/aes.h"
+
+static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *in,
+ struct netr_Credential *out)
+{
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ AES_KEY key;
+ uint8_t aes_in[AES_BLOCK_SIZE];
+ uint8_t aes_out[AES_BLOCK_SIZE];
+
+ AES_set_encrypt_key(creds->session_key, 128, &key);
+
+ ZERO_STRUCT(aes_in);
+ memcpy(aes_in, in->data, 8);
+ AES_encrypt(aes_in, aes_out, &key);
+ memcpy(out->data, aes_out, 8);
+
+ ZERO_STRUCT(key);
+ ZERO_STRUCT(aes_in);
+ ZERO_STRUCT(aes_out);
+ } else {
+ des_crypt112(out->data, in->data, creds->session_key, 1);
+ }
+}
/*
initialise the credentials state for old-style 64 bit session keys
ZERO_STRUCT(creds->session_key);
des_crypt128(creds->session_key, sum2, machine_password->hash);
-
- des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
- des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
-
- creds->seed = creds->client;
}
/*
MD5Final(tmp, &md5);
hmac_md5_update(tmp, sizeof(tmp), &ctx);
hmac_md5_final(creds->session_key, &ctx);
+}
- des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
- des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
+/*
+ initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
- creds->seed = creds->client;
+ this call is made after the netr_ServerReqChallenge call
+*/
+static void netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password)
+{
+ struct HMACSHA256Context ctx;
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+
+ ZERO_STRUCT(creds->session_key);
+
+ hmac_sha256_init(machine_password->hash,
+ sizeof(machine_password->hash),
+ &ctx);
+ hmac_sha256_update(client_challenge->data, 8, &ctx);
+ hmac_sha256_update(server_challenge->data, 8, &ctx);
+ hmac_sha256_final(digest, &ctx);
+
+ memcpy(creds->session_key, digest, sizeof(creds->session_key));
+
+ ZERO_STRUCT(digest);
+ ZERO_STRUCT(ctx);
}
+static void netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge)
+{
+ netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
+
+ netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
+
+ creds->seed = creds->client;
+}
/*
step the credentials to the next element in the chain, updating the
DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
- des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
+ netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
DEBUG(5,("\tCLIENT %08x:%08x\n",
IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
DEBUG(5,("\tseed+time+1 %08x:%08x\n",
IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
- des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
+ netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
DEBUG(5,("\tSERVER %08x:%08x\n",
IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
- if (negotiate_flags & NETLOGON_NEG_128BIT) {
+ if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_init_hmac_sha256(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
} else {
netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
}
+ netlogon_creds_first_step(creds, client_challenge, server_challenge);
+
dump_data_pw("Session key", creds->session_key, 16);
dump_data_pw("Credential ", creds->client.data, 8);
struct netr_Credential *credentials_out,
uint32_t negotiate_flags)
{
-
struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
-
+ bool ok = false;
+ bool try_aes = true;
+ bool try_strong = true;
+ bool try_weak = true;
+ bool fallback = false;
+
if (!creds) {
return NULL;
}
return NULL;
}
- if (negotiate_flags & NETLOGON_NEG_128BIT) {
+ if (!ok && try_aes) {
+ if (fallback) {
+ DEBUG(2,("credentials check fallback to aes key\n"));
+ }
+ creds->negotiate_flags |= NETLOGON_NEG_SUPPORTS_AES;
+ netlogon_creds_init_hmac_sha256(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ netlogon_creds_first_step(creds, client_challenge, server_challenge);
+ ok = netlogon_creds_server_check_internal(creds, credentials_in);
+ if (!ok) {
+ creds->negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
+ fallback = true;
+ }
+ }
+
+ if (!ok && try_strong) {
+ if (fallback) {
+ DEBUG(2,("credentials check fallback to strong key\n"));
+ }
+ creds->negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
+ creds->negotiate_flags |= NETLOGON_NEG_STRONG_KEYS;
netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
machine_password);
- } else {
+ netlogon_creds_first_step(creds, client_challenge, server_challenge);
+ ok = netlogon_creds_server_check_internal(creds, credentials_in);
+ if (!ok) {
+ creds->negotiate_flags &= ~NETLOGON_NEG_STRONG_KEYS;
+ fallback = true;
+ }
+ }
+
+ if (!ok && try_weak) {
+ if (fallback) {
+ DEBUG(2,("credentials check fallback to weak key\n"));
+ }
+ creds->negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
+ creds->negotiate_flags &= ~NETLOGON_NEG_STRONG_KEYS;
netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
machine_password);
+ netlogon_creds_first_step(creds, client_challenge, server_challenge);
+ ok = netlogon_creds_server_check_internal(creds, credentials_in);
}
/* And before we leak information about the machine account
* password, check that they got the first go right */
- if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
+ if (!ok) {
talloc_free(creds);
return NULL;
}