1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-05 09:18:06 +03:00
samba-mirror/source3/rpc_client/init_lsa.c
Andreas Schneider d078ee6af6 s3:rpc_client: Implement rpc_lsa_encrypt_trustdom_info_aes()
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2024-04-09 22:52:38 +00:00

397 lines
9.6 KiB
C

/*
* Unix SMB/CIFS implementation.
* RPC Pipe client / server routines
* Copyright (C) Guenther Deschner 2008.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "librpc/gen_ndr/lsa.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
#include "rpc_client/init_lsa.h"
#include "lib/crypto/gnutls_helpers.h"
#include "librpc/rpc/dcerpc_lsa.h"
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
/*******************************************************************
inits a structure.
********************************************************************/
void init_lsa_String(struct lsa_String *name, const char *s)
{
name->string = s;
name->size = 2 * strlen_m(s);
name->length = name->size;
}
/*******************************************************************
inits a structure.
********************************************************************/
void init_lsa_StringLarge(struct lsa_StringLarge *name, const char *s)
{
name->string = s;
}
/*******************************************************************
inits a structure.
********************************************************************/
void init_lsa_AsciiString(struct lsa_AsciiString *name, const char *s)
{
name->string = s;
}
/*******************************************************************
inits a structure.
********************************************************************/
void init_lsa_AsciiStringLarge(struct lsa_AsciiStringLarge *name, const char *s)
{
name->string = s;
}
bool rpc_lsa_encrypt_trustdom_info(
TALLOC_CTX *mem_ctx,
const char *incoming_old,
const char *incoming_new,
const char *outgoing_old,
const char *outgoing_new,
DATA_BLOB session_key,
struct lsa_TrustDomainInfoAuthInfoInternal **_authinfo_internal)
{
struct timeval tv_now = timeval_current();
NTTIME now = timeval_to_nttime(&tv_now);
struct lsa_TrustDomainInfoAuthInfoInternal *authinfo_internal = NULL;
struct AuthenticationInformation in_cur_td_info = {
.AuthType = TRUST_AUTH_TYPE_CLEAR,
.LastUpdateTime = now,
};
struct AuthenticationInformation in_prev_td_buf = {
.AuthType = TRUST_AUTH_TYPE_CLEAR,
.LastUpdateTime = now,
};
struct AuthenticationInformation out_cur_td_info = {
.AuthType = TRUST_AUTH_TYPE_CLEAR,
.LastUpdateTime = now,
};
struct AuthenticationInformation out_prev_td_buf = {
.AuthType = TRUST_AUTH_TYPE_CLEAR,
.LastUpdateTime = now,
};
/*
* This corresponds to MS-LSAD 2.2.7.16 LSAPR_TRUSTED_DOMAIN_AUTH_BLOB.
*/
struct trustDomainPasswords dom_auth_info = {
.incoming = {
.count = 1,
.previous = {
.count = 1,
.array = &in_prev_td_buf,
},
.current = {
.count = 1,
.array = &in_cur_td_info,
},
},
.outgoing = {
.count = 1,
.previous = {
.count = 1,
.array = &out_prev_td_buf,
},
.current = {
.count = 1,
.array = &out_cur_td_info,
},
}
};
size_t converted_size = 0;
DATA_BLOB dom_auth_blob = data_blob_null;
enum ndr_err_code ndr_err;
bool ok;
gnutls_cipher_hd_t cipher_hnd = NULL;
gnutls_datum_t _session_key = {
.data = session_key.data,
.size = session_key.length,
};
authinfo_internal = talloc_zero(
mem_ctx, struct lsa_TrustDomainInfoAuthInfoInternal);
if (authinfo_internal == NULL) {
return false;
}
ok = convert_string_talloc(mem_ctx,
CH_UNIX,
CH_UTF16,
incoming_new,
strlen(incoming_new),
&in_cur_td_info.AuthInfo.clear.password,
&converted_size);
if (!ok) {
return false;
}
in_cur_td_info.AuthInfo.clear.size = converted_size;
ok = convert_string_talloc(mem_ctx,
CH_UNIX,
CH_UTF16,
incoming_old,
strlen(incoming_old),
&in_prev_td_buf.AuthInfo.clear.password,
&converted_size);
if (!ok) {
return false;
}
in_prev_td_buf.AuthInfo.clear.size = converted_size;
ok = convert_string_talloc(mem_ctx,
CH_UNIX,
CH_UTF16,
outgoing_new,
strlen(outgoing_new),
&out_cur_td_info.AuthInfo.clear.password,
&converted_size);
if (!ok) {
return false;
}
out_cur_td_info.AuthInfo.clear.size = converted_size;
ok = convert_string_talloc(mem_ctx,
CH_UNIX,
CH_UTF16,
outgoing_old,
strlen(outgoing_old),
&out_prev_td_buf.AuthInfo.clear.password,
&converted_size);
if (!ok) {
return false;
}
out_prev_td_buf.AuthInfo.clear.size = converted_size;
generate_random_buffer(dom_auth_info.confounder,
sizeof(dom_auth_info.confounder));
ndr_err = ndr_push_struct_blob(
&dom_auth_blob,
authinfo_internal,
&dom_auth_info,
(ndr_push_flags_fn_t)ndr_push_trustDomainPasswords);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return false;
}
generate_random_buffer(dom_auth_info.confounder,
sizeof(dom_auth_info.confounder));
gnutls_cipher_init(&cipher_hnd,
GNUTLS_CIPHER_ARCFOUR_128,
&_session_key,
NULL);
gnutls_cipher_encrypt(cipher_hnd,
dom_auth_blob.data,
dom_auth_blob.length);
gnutls_cipher_deinit(cipher_hnd);
authinfo_internal->auth_blob.size = dom_auth_blob.length;
authinfo_internal->auth_blob.data = dom_auth_blob.data;
*_authinfo_internal = authinfo_internal;
return true;
}
bool rpc_lsa_encrypt_trustdom_info_aes(
TALLOC_CTX *mem_ctx,
const char *incoming_old,
const char *incoming_new,
const char *outgoing_old,
const char *outgoing_new,
DATA_BLOB session_key,
struct lsa_TrustDomainInfoAuthInfoInternalAES **pauthinfo_internal)
{
struct timeval tv_now = timeval_current();
NTTIME now = timeval_to_nttime(&tv_now);
struct AuthenticationInformation in_cur_td_info = {
.AuthType = TRUST_AUTH_TYPE_CLEAR,
.LastUpdateTime = now,
};
struct AuthenticationInformation in_prev_td_buf = {
.AuthType = TRUST_AUTH_TYPE_CLEAR,
.LastUpdateTime = now,
};
struct AuthenticationInformation out_cur_td_info = {
.AuthType = TRUST_AUTH_TYPE_CLEAR,
.LastUpdateTime = now,
};
struct AuthenticationInformation out_prev_td_buf = {
.AuthType = TRUST_AUTH_TYPE_CLEAR,
.LastUpdateTime = now,
};
/*
* This corresponds to MS-LSAD 2.2.7.16 LSAPR_TRUSTED_DOMAIN_AUTH_BLOB.
*/
struct trustDomainPasswords dom_auth_info = {
.incoming = {
.count = 1,
.previous = {
.count = 1,
.array = &in_prev_td_buf,
},
.current = {
.count = 1,
.array = &in_cur_td_info,
},
},
.outgoing = {
.count = 1,
.previous = {
.count = 1,
.array = &out_prev_td_buf,
},
.current = {
.count = 1,
.array = &out_cur_td_info,
},
}
};
struct lsa_TrustDomainInfoAuthInfoInternalAES *authinfo_internal = NULL;
size_t converted_size = 0;
DATA_BLOB dom_auth_blob = data_blob_null;
enum ndr_err_code ndr_err;
bool ok;
/* Salt */
DATA_BLOB iv = {
.length = 0,
};
gnutls_datum_t iv_datum = {
.size = 0,
};
/* Encrypted ciphertext */
DATA_BLOB ciphertext = data_blob_null;
NTSTATUS status;
authinfo_internal = talloc_zero(
mem_ctx, struct lsa_TrustDomainInfoAuthInfoInternalAES);
if (authinfo_internal == NULL) {
return false;
}
ok = convert_string_talloc(mem_ctx,
CH_UNIX,
CH_UTF16,
incoming_new,
strlen(incoming_new),
&in_cur_td_info.AuthInfo.clear.password,
&converted_size);
if (!ok) {
return false;
}
in_cur_td_info.AuthInfo.clear.size = converted_size;
ok = convert_string_talloc(mem_ctx,
CH_UNIX,
CH_UTF16,
incoming_old,
strlen(incoming_old),
&in_prev_td_buf.AuthInfo.clear.password,
&converted_size);
if (!ok) {
return false;
}
in_prev_td_buf.AuthInfo.clear.size = converted_size;
ok = convert_string_talloc(mem_ctx,
CH_UNIX,
CH_UTF16,
outgoing_new,
strlen(outgoing_new),
&out_cur_td_info.AuthInfo.clear.password,
&converted_size);
if (!ok) {
return false;
}
out_cur_td_info.AuthInfo.clear.size = converted_size;
ok = convert_string_talloc(mem_ctx,
CH_UNIX,
CH_UTF16,
outgoing_old,
strlen(outgoing_old),
&out_prev_td_buf.AuthInfo.clear.password,
&converted_size);
if (!ok) {
return false;
}
out_prev_td_buf.AuthInfo.clear.size = converted_size;
generate_random_buffer(dom_auth_info.confounder,
sizeof(dom_auth_info.confounder));
ndr_err = ndr_push_struct_blob(
&dom_auth_blob,
authinfo_internal,
&dom_auth_info,
(ndr_push_flags_fn_t)ndr_push_trustDomainPasswords);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return false;
}
/* Create salt */
iv.data = iv_datum.data = authinfo_internal->salt;
iv.length = iv_datum.size = sizeof(authinfo_internal->salt);
generate_nonce_buffer(authinfo_internal->salt,
sizeof(authinfo_internal->salt));
/* Create encryption key */
status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(
authinfo_internal,
&dom_auth_blob,
&session_key,
&lsa_aes256_enc_key_salt,
&lsa_aes256_mac_key_salt,
&iv,
&ciphertext,
authinfo_internal->auth_data);
if (!NT_STATUS_IS_OK(status)) {
return false;
}
if (ciphertext.length < 520) {
return false;
}
authinfo_internal->cipher.data = ciphertext.data;
authinfo_internal->cipher.size = ciphertext.length;
*pauthinfo_internal = authinfo_internal;
return true;
}