Skip to content

Commit 4956d58

Browse files
ImdsV2: Merge into Main (#5501)
1 parent e5b42ef commit 4956d58

File tree

170 files changed

+7175
-534
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

170 files changed

+7175
-534
lines changed

Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
<PackageVersion Include="System.ComponentModel.TypeConverter" Version="4.3.0" />
2020
<!-- Should match Azure Functions runtime: https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/4456 -->
2121
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="6.0.1" />
22+
<PackageVersion Include="System.Formats.Asn1" Version="9.0.8" />
2223
<PackageVersion Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
2324
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
2425
<PackageVersion Include="System.Runtime.Serialization.Formatters" Version="4.3.0" />
2526
<PackageVersion Include="System.Runtime.Serialization.Json" Version="4.3.0" />
2627
<PackageVersion Include="System.Runtime.Serialization.Primitives" Version="4.3.0" />
28+
<PackageVersion Include="System.Security.Cryptography.Cng" Version="5.0.0" PrivateAssets="All" />
2729
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="4.5.0" />
2830
<PackageVersion Include="System.Security.SecureString" Version="4.3.0" />
2931
<PackageVersion Include="System.ServiceModel.Http" Version="4.5.3" />
@@ -73,7 +75,6 @@
7375
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.35.0" />
7476
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
7577
<PackageVersion Include="System.Reflection.TypeExtensions" Version="4.7.0" />
76-
<PackageVersion Include="System.Security.Cryptography.Cng" Version="5.0.0" />
7778
<PackageVersion Include="System.Text.Json" Version="6.0.10" />
7879
<PackageVersion Include="System.Threading" Version="4.3.0" />
7980
<PackageVersion Include="System.Threading.Tasks" Version="4.3.0" />
@@ -82,6 +83,5 @@
8283
<PackageVersion Include="System.ValueTuple" Version="4.5.0" />
8384
<PackageVersion Include="System.Windows.Forms" Version="4.0.0" />
8485
<PackageVersion Include="CommandLineParser" Version="2.8.0" />
85-
<PackageVersion Include="System.Formats.Asn1" Version="9.0.0" />
8686
</ItemGroup>
8787
</Project>

LibsAndSamples.sln

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MacMauiAppWithBroker", "tes
194194
EndProject
195195
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MacConsoleAppWithBroker", "tests\devapps\MacConsoleAppWithBroker\MacConsoleAppWithBroker.csproj", "{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}"
196196
EndProject
197+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Identity.Client.MtlsPop", "src\client\Microsoft.Identity.Client.MtlsPop\Microsoft.Identity.Client.MtlsPop.csproj", "{3E1C29E5-6E67-D9B2-28DF-649A609937A2}"
198+
EndProject
197199
Global
198200
GlobalSection(SolutionConfigurationPlatforms) = preSolution
199201
Debug + MobileApps|Any CPU = Debug + MobileApps|Any CPU
@@ -1987,6 +1989,48 @@ Global
19871989
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|x64.Build.0 = Release|Any CPU
19881990
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|x86.ActiveCfg = Release|Any CPU
19891991
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|x86.Build.0 = Release|Any CPU
1992+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|Any CPU.ActiveCfg = Debug|Any CPU
1993+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|Any CPU.Build.0 = Debug|Any CPU
1994+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|ARM.ActiveCfg = Debug|Any CPU
1995+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|ARM.Build.0 = Debug|Any CPU
1996+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|ARM64.ActiveCfg = Debug|Any CPU
1997+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|ARM64.Build.0 = Debug|Any CPU
1998+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|iPhone.ActiveCfg = Debug|Any CPU
1999+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|iPhone.Build.0 = Debug|Any CPU
2000+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|iPhoneSimulator.ActiveCfg = Debug|Any CPU
2001+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|iPhoneSimulator.Build.0 = Debug|Any CPU
2002+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|x64.ActiveCfg = Debug|Any CPU
2003+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|x64.Build.0 = Debug|Any CPU
2004+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|x86.ActiveCfg = Debug|Any CPU
2005+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug + MobileApps|x86.Build.0 = Debug|Any CPU
2006+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
2007+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
2008+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|ARM.ActiveCfg = Debug|Any CPU
2009+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|ARM.Build.0 = Debug|Any CPU
2010+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|ARM64.ActiveCfg = Debug|Any CPU
2011+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|ARM64.Build.0 = Debug|Any CPU
2012+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|iPhone.ActiveCfg = Debug|Any CPU
2013+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|iPhone.Build.0 = Debug|Any CPU
2014+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
2015+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
2016+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|x64.ActiveCfg = Debug|Any CPU
2017+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|x64.Build.0 = Debug|Any CPU
2018+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|x86.ActiveCfg = Debug|Any CPU
2019+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Debug|x86.Build.0 = Debug|Any CPU
2020+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
2021+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|Any CPU.Build.0 = Release|Any CPU
2022+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|ARM.ActiveCfg = Release|Any CPU
2023+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|ARM.Build.0 = Release|Any CPU
2024+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|ARM64.ActiveCfg = Release|Any CPU
2025+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|ARM64.Build.0 = Release|Any CPU
2026+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|iPhone.ActiveCfg = Release|Any CPU
2027+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|iPhone.Build.0 = Release|Any CPU
2028+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
2029+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
2030+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|x64.ActiveCfg = Release|Any CPU
2031+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|x64.Build.0 = Release|Any CPU
2032+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|x86.ActiveCfg = Release|Any CPU
2033+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2}.Release|x86.Build.0 = Release|Any CPU
19902034
EndGlobalSection
19912035
GlobalSection(SolutionProperties) = preSolution
19922036
HideSolutionNode = FALSE
@@ -2045,6 +2089,7 @@ Global
20452089
{97995B86-AA0F-3AF9-DA40-85A6263E4391} = {9B0B5396-4D95-4C15-82ED-DC22B5A3123F}
20462090
{AEF6BB00-931F-4638-955D-24D735625C34} = {34BE693E-3496-45A4-B1D2-D3A0E068EEDB}
20472091
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0} = {34BE693E-3496-45A4-B1D2-D3A0E068EEDB}
2092+
{3E1C29E5-6E67-D9B2-28DF-649A609937A2} = {1A37FD75-94E9-4D6F-953A-0DABBD7B49E9}
20482093
EndGlobalSection
20492094
GlobalSection(ExtensibilityGlobals) = postSolution
20502095
SolutionGuid = {020399A9-DC27-4B82-9CAA-EF488665AC27}

build/template-pack-and-sign-all-nugets.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ steps:
4444
ProjectRootPath: '$(Build.SourcesDirectory)\$(MsalSourceDir)src\client'
4545
AssemblyName: 'Microsoft.Identity.Client.Extensions.Msal'
4646

47+
# Sign binary and pack Microsoft.Identity.Client.MtlsPop
48+
- template: template-pack-and-sign-nuget.yaml
49+
parameters:
50+
BuildConfiguration: ${{ parameters.BuildConfiguration }}
51+
ProjectRootPath: '$(Build.SourcesDirectory)\$(MsalSourceDir)src\client'
52+
AssemblyName: 'Microsoft.Identity.Client.MtlsPop'
53+
4754
# Copy all packages out to staging
4855
- task: CopyFiles@2
4956
displayName: 'Copy Files to: $(Build.ArtifactStagingDirectory)\packages'

build/template-run-mi-e2e-azurearc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ steps:
3737
codeCoverageEnabled: false
3838
failOnMinTestsNotRun: true
3939
minimumExpectedTests: '1'
40-
testFiltercriteria: 'TestCategory=MI_E2E_AzureArc'
40+
testFiltercriteria: '(TestCategory=MI_E2E_AzureArc|TestCategory=MI_E2E_KeyAcquisition_KeyGuard)'

build/template-run-mi-e2e-imds.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ steps:
4747
runInParallel: false
4848
failOnMinTestsNotRun: true
4949
minimumExpectedTests: '1'
50-
testFiltercriteria: 'TestCategory=MI_E2E_Imds'
50+
testFiltercriteria: '(TestCategory=MI_E2E_Imds|TestCategory=MI_E2E_KeyAcquisition_Hardware)'
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Runtime.InteropServices;
6+
using Microsoft.Win32.SafeHandles;
7+
8+
namespace Microsoft.Identity.Client.MtlsPop.Attestation
9+
{
10+
/// <summary>
11+
/// Managed façade for <c>AttestationClientLib.dll</c>. Holds initialization state,
12+
/// does ref-count hygiene on <see cref="SafeNCryptKeyHandle"/>, and returns a JWT.
13+
/// </summary>
14+
internal sealed class AttestationClient : IDisposable
15+
{
16+
private bool _initialized;
17+
18+
/// <summary>
19+
/// AttestationClient constructor. Relies on the default OS loader to locate the native DLL.
20+
/// </summary>
21+
/// <exception cref="InvalidOperationException"></exception>
22+
public AttestationClient()
23+
{
24+
string dllError = NativeDiagnostics.ProbeNativeDll();
25+
// intentionally not throwing on dllError
26+
27+
// Load & initialize (logger is required by native lib)
28+
var info = new AttestationClientLib.AttestationLogInfo
29+
{
30+
Log = AttestationLogger.ConsoleLogger,
31+
Ctx = IntPtr.Zero
32+
};
33+
34+
_initialized = AttestationClientLib.InitAttestationLib(ref info) == 0;
35+
if (!_initialized)
36+
throw new InvalidOperationException("Failed to initialize AttestationClientLib.");
37+
}
38+
39+
/// <summary>
40+
/// Calls the native <c>AttestKeyGuardImportKey</c> and returns a structured result.
41+
/// </summary>
42+
public AttestationResult Attest(string endpoint,
43+
SafeNCryptKeyHandle keyHandle,
44+
string clientId)
45+
{
46+
if (!_initialized)
47+
return new(AttestationStatus.NotInitialized, null, -1,
48+
"Native library not initialized.");
49+
50+
IntPtr buf = IntPtr.Zero;
51+
bool addRef = false;
52+
53+
try
54+
{
55+
keyHandle.DangerousAddRef(ref addRef);
56+
57+
int rc = AttestationClientLib.AttestKeyGuardImportKey(
58+
endpoint, null, null, keyHandle, out buf, clientId);
59+
60+
if (rc != 0)
61+
return new(AttestationStatus.NativeError, null, rc, null);
62+
63+
if (buf == IntPtr.Zero)
64+
return new(AttestationStatus.TokenEmpty, null, 0,
65+
"rc==0 but token buffer was null.");
66+
67+
string jwt = Marshal.PtrToStringAnsi(buf)!;
68+
return new(AttestationStatus.Success, jwt, 0, null);
69+
}
70+
catch (DllNotFoundException ex)
71+
{
72+
return new(AttestationStatus.Exception, null, -1,
73+
$"Native DLL not found: {ex.Message}");
74+
}
75+
catch (BadImageFormatException ex)
76+
{
77+
return new(AttestationStatus.Exception, null, -1,
78+
$"Architecture mismatch (x86/x64) or corrupted DLL: {ex.Message}");
79+
}
80+
catch (SEHException ex)
81+
{
82+
return new(AttestationStatus.Exception, null, -1,
83+
$"Native library raised SEHException: {ex.Message}");
84+
}
85+
catch (Exception ex)
86+
{
87+
return new(AttestationStatus.Exception, null, -1, ex.Message);
88+
}
89+
finally
90+
{
91+
if (buf != IntPtr.Zero)
92+
AttestationClientLib.FreeAttestationToken(buf);
93+
if (addRef)
94+
keyHandle.DangerousRelease();
95+
}
96+
}
97+
98+
/// <summary>
99+
/// Disposes the client, releasing any resources and un-initializing the native library.
100+
/// </summary>
101+
public void Dispose()
102+
{
103+
if (_initialized)
104+
{
105+
AttestationClientLib.UninitAttestationLib();
106+
_initialized = false;
107+
}
108+
GC.SuppressFinalize(this);
109+
}
110+
}
111+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.Win32.SafeHandles;
5+
using System;
6+
using System.IO;
7+
using System.Runtime.InteropServices;
8+
9+
namespace Microsoft.Identity.Client.MtlsPop.Attestation
10+
{
11+
internal static class AttestationClientLib
12+
{
13+
internal enum LogLevel { Error, Warn, Info, Debug }
14+
15+
internal delegate void LogFunc(
16+
IntPtr ctx, string tag, LogLevel lvl, string func, int line, string msg);
17+
18+
[StructLayout(LayoutKind.Sequential)]
19+
internal struct AttestationLogInfo
20+
{
21+
public LogFunc Log;
22+
public IntPtr Ctx;
23+
}
24+
25+
[DllImport("AttestationClientLib.dll", CallingConvention = CallingConvention.Cdecl,
26+
CharSet = CharSet.Ansi)]
27+
internal static extern int InitAttestationLib(ref AttestationLogInfo info);
28+
29+
[DllImport("AttestationClientLib.dll", CallingConvention = CallingConvention.Cdecl,
30+
CharSet = CharSet.Ansi)]
31+
internal static extern int AttestKeyGuardImportKey(
32+
string endpoint,
33+
string authToken,
34+
string clientPayload,
35+
SafeNCryptKeyHandle keyHandle,
36+
out IntPtr token,
37+
string clientId);
38+
39+
[DllImport("AttestationClientLib.dll", CallingConvention = CallingConvention.Cdecl)]
40+
internal static extern void FreeAttestationToken(IntPtr token);
41+
42+
[DllImport("AttestationClientLib.dll", CallingConvention = CallingConvention.Cdecl)]
43+
internal static extern void UninitAttestationLib();
44+
}
45+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Text;
7+
8+
namespace Microsoft.Identity.Client.MtlsPop.Attestation
9+
{
10+
internal static class AttestationErrors
11+
{
12+
internal static string Describe(AttestationResultErrorCode rc) => rc switch
13+
{
14+
AttestationResultErrorCode.ERRORCURLINITIALIZATION
15+
=> "libcurl failed to initialize (DLL missing or version mismatch).",
16+
AttestationResultErrorCode.ERRORHTTPREQUESTFAILED
17+
=> "Could not reach the attestation service (network / proxy?).",
18+
AttestationResultErrorCode.ERRORATTESTATIONFAILED
19+
=> "The enclave rejected the evidence (key type / PCR policy).",
20+
AttestationResultErrorCode.ERRORJWTDECRYPTIONFAILED
21+
=> "The JWT returned by the service could not be decrypted.",
22+
AttestationResultErrorCode.ERRORLOGGERINITIALIZATION
23+
=> "Native logger setup failed (rare).",
24+
_ => rc.ToString() // default: enum name
25+
};
26+
}
27+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.Runtime.InteropServices;
7+
8+
namespace Microsoft.Identity.Client.MtlsPop.Attestation
9+
{
10+
internal static class AttestationLogger
11+
{
12+
/// <summary>
13+
/// Attestation Logger
14+
/// </summary>
15+
internal static readonly AttestationClientLib.LogFunc ConsoleLogger = (ctx, tag, lvl, func, line, msg) =>
16+
{
17+
try
18+
{
19+
string sTag = ToText(tag);
20+
string sFunc = ToText(func);
21+
string sMsg = ToText(msg);
22+
23+
var lineText = $"[MtlsPop][{lvl}] {sTag} {sFunc}:{line} {sMsg}";
24+
25+
// Default: Trace (respects listeners; safe for all app types)
26+
Trace.WriteLine(lineText);
27+
}
28+
catch
29+
{
30+
}
31+
};
32+
33+
// Converts either string or IntPtr (char*) to text. Works with any LogFunc variant.
34+
private static string ToText(object value)
35+
{
36+
if (value is IntPtr p && p != IntPtr.Zero)
37+
{
38+
try
39+
{ return Marshal.PtrToStringAnsi(p) ?? string.Empty; }
40+
catch { return string.Empty; }
41+
}
42+
return value?.ToString() ?? string.Empty;
43+
}
44+
}
45+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
namespace Microsoft.Identity.Client.MtlsPop.Attestation
5+
{
6+
/// <summary>
7+
/// AttestationResult is the result of an attestation operation.
8+
/// </summary>
9+
/// <param name="Status">High-level outcome category.</param>
10+
/// <param name="Jwt">JWT on success; null otherwise (caller may pass null).</param>
11+
/// <param name="NativeErrorCode">Raw native return code (0 on success).</param>
12+
/// <param name="ErrorMessage">Optional descriptive text for non-success cases.</param>
13+
/// <remarks>
14+
/// This is a positional record. The compiler synthesizes init-only auto-properties:
15+
/// public AttestationStatus Status { get; init; }
16+
/// public string Jwt { get; init; }
17+
/// public int NativeErrorCode { get; init; }
18+
/// public string ErrorMessage { get; init; }
19+
/// Because they are init-only, values are fixed after construction; to "modify" use a 'with'
20+
/// expression, e.g.: var updated = result with { Jwt = newJwt };
21+
/// The netstandard2.0 target relies on the IsExternalInit shim (see IsExternalInit.cs) to enable 'init'.
22+
/// </remarks>
23+
internal sealed record AttestationResult(
24+
AttestationStatus Status,
25+
string Jwt,
26+
int NativeErrorCode,
27+
string ErrorMessage);
28+
}

0 commit comments

Comments
 (0)