Skip to content

Commit 08b18b0

Browse files
committed
Simplifying handling of security buffer descriptors.
1 parent 50d9b72 commit 08b18b0

6 files changed

Lines changed: 100 additions & 87 deletions

File tree

NtApiDotNet/NtApiDotNet.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@
565565
<Compile Include="Win32\Security\Authentication\Schannel\SchannelSessionControlToken.cs" />
566566
<Compile Include="Win32\Security\Authentication\Schannel\SchannelSessionFlags.cs" />
567567
<Compile Include="Win32\Security\Authentication\Schannel\SchannelShutdownControlToken.cs" />
568+
<Compile Include="Win32\Security\Buffers\SecurityBufferDescriptor.cs" />
568569
<Compile Include="Win32\Security\Credential\AuthIdentity\SecWinNtAuthIdentity.cs" />
569570
<Compile Include="Win32\Security\Credential\AuthIdentity\SecWinNtAuthIdentityCreateOptions.cs" />
570571
<Compile Include="Win32\Security\Credential\AuthIdentity\SecWinNtAuthIdentityEncryptionOptions.cs" />

NtApiDotNet/Win32/Security/Authentication/AuthenticationPackage.cs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -350,18 +350,12 @@ public IServerAuthenticationContext CreateServer(AuthenticationCredentials crede
350350
public void ChangeAccountPassword(string domain, string username,
351351
string old_password, string new_password, bool impersonating = false)
352352
{
353-
var password_info_buffer = new SecurityBufferAllocMem(SecurityBufferType.ChangePassResponse);
354-
List<SecurityBuffer> buffers = new List<SecurityBuffer>
353+
var change_pass_buffer = new SecurityBufferAllocMem(SecurityBufferType.ChangePassResponse);
354+
using (var desc = SecurityBufferDescriptor.Create(change_pass_buffer))
355355
{
356-
password_info_buffer
357-
};
358-
using (var list = new DisposableList())
359-
{
360-
var output = buffers.ToBufferList(list);
361-
var desc = output.ToDesc(list);
362-
SecurityNativeMethods.ChangeAccountPassword(Name, domain, username,
363-
old_password, new_password, impersonating, 0, desc).CheckResult();
364-
buffers.UpdateBuffers(desc);
356+
SecurityNativeMethods.ChangeAccountPassword(Name, domain, username,
357+
old_password, new_password, impersonating, 0, desc.Value).CheckResult();
358+
desc.UpdateBuffers();
365359
}
366360
}
367361

NtApiDotNet/Win32/Security/Authentication/SecurityContextUtils.cs

Lines changed: 26 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
using NtApiDotNet.Win32.Security.Native;
1919
using System;
2020
using System.Collections.Generic;
21-
using System.Linq;
2221
using System.Runtime.InteropServices;
2322
using System.Security.Cryptography.X509Certificates;
2423

@@ -75,35 +74,6 @@ internal static string GetPackageName(SecHandle context)
7574
return null;
7675
}
7776

78-
internal static List<SecBuffer> ToBufferList(this IEnumerable<SecurityBuffer> buffers, DisposableList list)
79-
{
80-
return buffers.Select(b => b.ToBuffer(list)).ToList();
81-
}
82-
83-
internal static SecBufferDesc ToDesc(this IEnumerable<SecBuffer> buffers, DisposableList list)
84-
{
85-
var arr = buffers.ToArray();
86-
if (arr.Length == 0)
87-
return null;
88-
return list.AddResource(new SecBufferDesc(arr));
89-
}
90-
91-
internal static void UpdateBuffers(this IList<SecurityBuffer> buffers, SecBufferDesc desc)
92-
{
93-
if (desc == null)
94-
return;
95-
var update_buffers = desc.ToArray();
96-
for (int i = 0; i < buffers.Count; ++i)
97-
{
98-
buffers[i].FromBuffer(update_buffers[i]);
99-
}
100-
}
101-
102-
internal static void UpdateBuffers(this IEnumerable<SecurityBuffer> buffers, SecBufferDesc desc)
103-
{
104-
UpdateBuffers(buffers.ToArray(), desc);
105-
}
106-
10777
internal static byte[] MakeSignature(
10878
SecHandle context,
10979
int flags,
@@ -115,12 +85,10 @@ internal static byte[] MakeSignature(
11585
SecurityBufferOut signature_buffer = new SecurityBufferOut(SecurityBufferType.Token, max_sig_size);
11686
sig_buffers.Add(signature_buffer);
11787

118-
using (var list = new DisposableList())
88+
using (var desc = SecurityBufferDescriptor.Create(sig_buffers))
11989
{
120-
List<SecBuffer> buffers = sig_buffers.ToBufferList(list);
121-
SecBufferDesc desc = buffers.ToDesc(list);
122-
SecurityNativeMethods.MakeSignature(context, flags, desc, sequence_no).CheckResult();
123-
sig_buffers.UpdateBuffers(desc);
90+
SecurityNativeMethods.MakeSignature(context, flags, desc.Value, sequence_no).CheckResult();
91+
desc.UpdateBuffers();
12492
return signature_buffer.ToArray();
12593
}
12694
}
@@ -144,11 +112,10 @@ internal static bool VerifySignature(
144112
{
145113
List<SecurityBuffer> sig_buffers = new List<SecurityBuffer>(messages);
146114
sig_buffers.Add(new SecurityBufferInOut(SecurityBufferType.Token | SecurityBufferType.ReadOnly, signature));
147-
using (var list = new DisposableList())
115+
using (var desc = SecurityBufferDescriptor.Create(sig_buffers))
148116
{
149-
List<SecBuffer> buffers = sig_buffers.ToBufferList(list);
150-
SecBufferDesc desc = buffers.ToDesc(list);
151-
return SecurityNativeMethods.VerifySignature(context, desc, sequence_no, out int _) == SecStatusCode.SUCCESS;
117+
return SecurityNativeMethods.VerifySignature(context, desc.Value,
118+
sequence_no, out int _) == SecStatusCode.SUCCESS;
152119
}
153120
}
154121

@@ -218,12 +185,10 @@ internal static void EncryptMessageNoSignature(
218185
throw new ArgumentNullException(nameof(messages));
219186
}
220187

221-
using (var list = new DisposableList())
188+
using (var desc = SecurityBufferDescriptor.Create(messages))
222189
{
223-
var buffers = messages.ToBufferList(list);
224-
var desc = buffers.ToDesc(list);
225-
SecurityNativeMethods.EncryptMessage(context, flags, desc, sequence_no).CheckResult();
226-
messages.UpdateBuffers(desc);
190+
SecurityNativeMethods.EncryptMessage(context, flags, desc.Value, sequence_no).CheckResult();
191+
desc.UpdateBuffers();
227192
}
228193
}
229194

@@ -283,12 +248,10 @@ internal static void DecryptMessageNoSignature(
283248
throw new ArgumentNullException(nameof(messages));
284249
}
285250

286-
using (var list = new DisposableList())
251+
using (var desc = SecurityBufferDescriptor.Create(messages))
287252
{
288-
var buffers = messages.ToBufferList(list);
289-
var desc = buffers.ToDesc(list);
290-
SecurityNativeMethods.DecryptMessage(context, desc, sequence_no, out _).CheckResult();
291-
messages.UpdateBuffers(desc);
253+
SecurityNativeMethods.DecryptMessage(context, desc.Value, sequence_no, out _).CheckResult();
254+
desc.UpdateBuffers();
292255
}
293256
}
294257

@@ -371,25 +334,20 @@ internal static SecStatusCode InitializeSecurityContext(
371334
LargeInteger expiry,
372335
bool throw_on_error)
373336
{
374-
using (DisposableList list = new DisposableList())
337+
using (SecurityBufferDescriptor in_buffer_desc = SecurityBufferDescriptor.Create(input),
338+
out_buffer_desc = SecurityBufferDescriptor.Create(output))
375339
{
376-
var input_buffers = input?.ToBufferList(list);
377-
var output_buffers = output?.ToBufferList(list);
378-
379-
var in_buffer_desc = input_buffers.ToDesc(list);
380-
var out_buffer_desc = output_buffers.ToDesc(list);
381-
382340
var result = SecurityNativeMethods.InitializeSecurityContext(credential.CredHandle,
383-
context, target_name, req_attributes, 0, data_rep, in_buffer_desc, 0,
384-
new_context, out_buffer_desc, out ret_attributes, expiry).CheckResult(throw_on_error);
341+
context, target_name, req_attributes, 0, data_rep, in_buffer_desc.Value, 0,
342+
new_context, out_buffer_desc.Value, out ret_attributes, expiry).CheckResult(throw_on_error);
385343
if (!result.IsSuccess())
386344
return result;
387345

388346
try
389347
{
390348
if (result == SecStatusCode.SEC_I_COMPLETE_NEEDED || result == SecStatusCode.SEC_I_COMPLETE_AND_CONTINUE)
391349
{
392-
var comp_result = SecurityNativeMethods.CompleteAuthToken(new_context, out_buffer_desc).CheckResult(throw_on_error);
350+
var comp_result = SecurityNativeMethods.CompleteAuthToken(new_context, out_buffer_desc.Value).CheckResult(throw_on_error);
393351
if (!comp_result.IsSuccess())
394352
return comp_result;
395353
}
@@ -398,7 +356,7 @@ internal static SecStatusCode InitializeSecurityContext(
398356
{
399357
if (result.IsSuccess())
400358
{
401-
output?.UpdateBuffers(out_buffer_desc);
359+
out_buffer_desc.UpdateBuffers();
402360
}
403361
}
404362

@@ -418,23 +376,19 @@ internal static SecStatusCode AcceptSecurityContext(
418376
LargeInteger expiry,
419377
bool throw_on_error)
420378
{
421-
using (DisposableList list = new DisposableList())
379+
using (SecurityBufferDescriptor in_buffer_desc = SecurityBufferDescriptor.Create(input),
380+
out_buffer_desc = SecurityBufferDescriptor.Create(output))
422381
{
423-
var input_buffers = input?.ToBufferList(list);
424-
var output_buffers = output?.ToBufferList(list);
425-
426-
var in_buffer_desc = input_buffers.ToDesc(list);
427-
var out_buffer_desc = output_buffers.ToDesc(list);
428-
429382
SecStatusCode result = SecurityNativeMethods.AcceptSecurityContext(credential.CredHandle, context,
430-
in_buffer_desc, req_attributes, data_rep, new_context, out_buffer_desc, out ret_attributes, expiry).CheckResult(throw_on_error);
383+
in_buffer_desc.Value, req_attributes, data_rep, new_context,
384+
out_buffer_desc.Value, out ret_attributes, expiry).CheckResult(throw_on_error);
431385
if (!result.IsSuccess())
432386
return result;
433387
try
434388
{
435389
if (result == SecStatusCode.SEC_I_COMPLETE_NEEDED || result == SecStatusCode.SEC_I_COMPLETE_AND_CONTINUE)
436390
{
437-
var comp_result = SecurityNativeMethods.CompleteAuthToken(context, out_buffer_desc).CheckResult(throw_on_error);
391+
var comp_result = SecurityNativeMethods.CompleteAuthToken(context, out_buffer_desc.Value).CheckResult(throw_on_error);
438392
if (!comp_result.IsSuccess())
439393
return comp_result;
440394
}
@@ -443,7 +397,7 @@ internal static SecStatusCode AcceptSecurityContext(
443397
{
444398
if (result.IsSuccess())
445399
{
446-
output?.UpdateBuffers(out_buffer_desc);
400+
out_buffer_desc.UpdateBuffers();
447401
}
448402
}
449403

@@ -510,11 +464,9 @@ internal static AuthenticationContextKeyInfo GetKeyInfo(SecHandle context)
510464

511465
internal static SecStatusCode ApplyControlToken(SecHandle context, IEnumerable<SecurityBuffer> input, bool throw_on_error)
512466
{
513-
using (var list = new DisposableList())
467+
using (var desc = SecurityBufferDescriptor.Create(input))
514468
{
515-
var buffers = input?.ToBufferList(list);
516-
var desc = buffers?.ToDesc(list);
517-
return SecurityNativeMethods.ApplyControlToken(context, desc).CheckResult(throw_on_error);
469+
return SecurityNativeMethods.ApplyControlToken(context, desc.Value).CheckResult(throw_on_error);
518470
}
519471
}
520472
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2022 Google LLC. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using NtApiDotNet.Win32.Security.Native;
16+
using System;
17+
using System.Collections.Generic;
18+
using System.Linq;
19+
20+
namespace NtApiDotNet.Win32.Security.Buffers
21+
{
22+
internal sealed class SecurityBufferDescriptor : IDisposable
23+
{
24+
private readonly DisposableList _list;
25+
private readonly SecurityBuffer[] _buffers;
26+
private readonly SecBuffer[] _sec_buffers;
27+
28+
private SecurityBufferDescriptor(IEnumerable<SecurityBuffer> buffers)
29+
{
30+
_list = new DisposableList();
31+
_buffers = buffers?.ToArray() ?? Array.Empty<SecurityBuffer>();
32+
_sec_buffers = _buffers.Select(b => b.ToBuffer(_list)).ToArray();
33+
if (_sec_buffers.Length > 0)
34+
{
35+
Value = _list.AddResource(new SecBufferDesc(_sec_buffers));
36+
}
37+
}
38+
39+
public static SecurityBufferDescriptor Create(params SecurityBuffer[] buffers)
40+
{
41+
return new SecurityBufferDescriptor(buffers);
42+
}
43+
44+
public static SecurityBufferDescriptor Create(IEnumerable<SecurityBuffer> buffers)
45+
{
46+
return new SecurityBufferDescriptor(buffers);
47+
}
48+
49+
public void Dispose()
50+
{
51+
_list.Dispose();
52+
}
53+
54+
public void UpdateBuffers()
55+
{
56+
if (Value == null)
57+
return;
58+
var update_buffers = Value.ToArray();
59+
for (int i = 0; i < _buffers.Length; ++i)
60+
{
61+
_buffers[i].FromBuffer(update_buffers[i]);
62+
}
63+
}
64+
65+
public SecBufferDesc Value { get; }
66+
}
67+
}

NtApiDotNet/Win32/Security/Buffers/SecurityBufferUtils.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace NtApiDotNet.Win32.Security.Buffers
2424
public static class SecurityBufferUtils
2525
{
2626
/// <summary>
27-
/// Convert a list of buffers data buffers to a byte array.
27+
/// Convert a list of data buffers to a byte array.
2828
/// </summary>
2929
/// <param name="buffers">List of data security buffers. Only buffers used for input are processed.</param>
3030
/// <returns>The data buffers as one bytes array.</returns>

NtApiDotNet/Win32/Security/Native/SecBufferDesc.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
namespace NtApiDotNet.Win32.Security.Native
2020
{
21-
#pragma warning disable 1591
2221
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
2322
internal sealed class SecBufferDesc : IDisposable
2423
{

0 commit comments

Comments
 (0)