TODO: libcli/auth: add support for AES/HMAC-SHA256 schannel support
authorStefan Metzmacher <metze@samba.org>
Tue, 25 Aug 2009 08:09:44 +0000 (10:09 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 25 Aug 2009 15:53:44 +0000 (17:53 +0200)
metze

libcli/auth/credentials.c

index a88f8fc803dac12080b4263a283da42d9a93db51..f6054830b9cc912b29692ef1a4b58c756f85ddd3 100644 (file)
 #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)
 {
-       des_crypt112(out->data, in->data, creds->session_key, 1);
+       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);
+       }
 }
 
 /*
@@ -84,6 +102,34 @@ static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *cr
        hmac_md5_final(creds->session_key, &ctx);
 }
 
+/*
+  initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
+
+  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)
@@ -226,7 +272,12 @@ struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *me
        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_STRONG_KEYS) {
+       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);
@@ -328,6 +379,7 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me
 {
        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;
@@ -350,10 +402,28 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me
                return NULL;
        }
 
+       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);
@@ -369,6 +439,7 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me
                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);