Created
September 6, 2023 20:58
-
-
Save jtgasper3/955578ec7453c23fa8d7e38f8dc223ac to your computer and use it in GitHub Desktop.
Azure Function for MDM Client Cert validation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#r "Newtonsoft.Json" | |
#r "System.Formats.Asn1" | |
using System.Formats.Asn1; | |
using System.Net; | |
using System.Security.Cryptography; | |
using System.Security.Cryptography.X509Certificates; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.Extensions.Primitives; | |
using Newtonsoft.Json; | |
static X509Certificate2 interCertificate = new X509Certificate2(Convert.FromBase64String( | |
@"MIIEfTCCAmWgAwIBAgIQQt4O1ZNyWaBPqw1mUq1F8jANBgkqhkiG9w0BAQsFADA4 | |
MTYwNAYDVQQDEy1NaWNyb3NvZnQgSW50dW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBB | |
dXRob3JpdHkwHhcNMjMwNTA1MDAwMDAwWhcNMjYwNTA1MDAwMDAwWjApMScwJQYD | |
VQQDEx5NaWNyb3NvZnQgSW50dW5lIE1ETSBEZXZpY2UgQ0EwggEiMA0GCSqGSIb3 | |
DQEBAQUAA4IBDwAwggEKAoIBAQDYOy/IV8f+BmH5y9/zJUv5oROn3MEQua39r03K | |
7fgAqwEsAFtU/4ZWnFbriFSx0xZsDkZxxUy9BlOQZ+2sr/eJ2j6uI6CocR4woRkt | |
JR6pQ5EXdsJb9lZOfV9+q6PwLnAIBQTTpUq+XtE8T1MwwGQ5NWW1JqQMDPo3nR0T | |
h14tDQNrLtCPe7c2f+qaG2x+uRvWGMgTmxtGpYiipQB8upnInAZZ5wVdhu+/GMZg | |
TSYJvn+3Px33NOB+0mpVanq7CwzyXA+dqGio8sZJDfOS1fPYDKqPj52l3rct3doa | |
2o98gPHWaDs7Rj+GiAKeidUkN3uhQUyNfi8+YJEHb8OVGjEFAgMBAAGjgZEwgY4w | |
HQYDVR0OBBYEFC5aTr/lv8IEGDqYYmHaaj3AsHw4MB8GA1UdIwQYMBaAFCtJzrEH | |
JUyd5gqT85C5MPfmRJ+SMBAGCSsGAQQBgjcVAQQDAgEAMA4GA1UdDwEB/wQEAwIB | |
hjAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMA0G | |
CSqGSIb3DQEBCwUAA4ICAQCoci1EyidjS6xqi3S37/TJdIGqM0OcvTsi12WPIVxA | |
MFRaF638dgu9FrRpTDCquc06lBHtIfBWCU7VFkGIGGIZ54L4en/dGi0ZBXjv4vfp | |
RQ+LsoJZnYtCF3MbvlPXfQr3nk1k6m7c1utsuSzL0VgeEJJ++5KXlMRHrFdlXXm5 | |
N8MJNw78I/e7sbwNZxvA4UdxnEpqHeKDj1+nppANJDKrobIp9WzmYCFA8Qu3bX/N | |
g9OnxLnpGi8mCIvPCkPu3oo1RtHxjf/tQtdSE4V1/8mggYLNNftjWk6ElqA+gRGY | |
gJCssJrfG/bRYk+9ZQjavu3oG0B+SD7j3UeAOQqoOaPi8faF95tpgpVfJqQ6bm9w | |
qBdODWfE4TYIPd0QG5nsYr86JThEtsL36U9j74wC33+4YHV4UviUiycyQiQQCSIF | |
xSY2u9cLpFO4rjM+Qe/n8KWQURTW8i3wUFReVrMp9l+y70GklU/HHkXv8SDtFi6Q | |
0+aK2duUhbHr+8P2nPuPNetfryVsdE+RVL4pFWEfIvbOKOI5EQj3Bh4/XkbhQtZk | |
+FR7VkUIm5A9Kp+OzsQADkYhWE1N4xL/ysfRWmOcjB1MT1m7Zfie3YsR7j+rY4NL | |
b+snuHqqpYRDSZpngZAJgRYHI1xSUxOk+zJ8XyHG+eyeZdfwlrWLKuMJEFw4pczs | |
0Q==")); | |
static X509Certificate2 rootCertificate = new X509Certificate2(Convert.FromBase64String( | |
@"MIIFaTCCA1GgAwIBAgIQWhvaqZFB9KVNpmVRc71GWjANBgkqhkiG9w0BAQsFADA4 | |
MTYwNAYDVQQDEy1NaWNyb3NvZnQgSW50dW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBB | |
dXRob3JpdHkwHhcNMjEwODEyMDAwMDAwWhcNMjYwODEyMDAwMDAwWjA4MTYwNAYD | |
VQQDEy1NaWNyb3NvZnQgSW50dW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3Jp | |
dHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQL63MwZDlW02yCipf | |
dAUGn5Q8sSIc6zjdTkdCRh2SZGVFVLCgFr/EULGw3q7xaOS/mTA2I+koZM+95JvE | |
xfsIy+S7I7rLQjYNuJZVXl0s1xj4hfewF1jk8nWjdEwYfZkbZ+/6pYTOtHg/U3tV | |
seT63tg6Vc94dkUpOmN4tlyuie2qbMbc1VmAyyITcoIFtRspdE9qW1NnwgzGJz/Q | |
KaL2H7LtGyNGwXhH4jSwZa8ZNcwKjJ7wdaG2SNxOgrZsCHv272vugNiGEy4yYwGU | |
CyGOAksOaHEobW87Y92s/q4/5beBa979ZCeH4VSpRo2LcQFH9ZM9r05VpFimg8Pu | |
pcOl2g1WcuBj1MBBjT/YPaVgbZUp9wvqqefhW6m/JGTYaPJ4YrnMnrzem6kwGP5K | |
3xwHWL/5ANTjWDx6+b7dZ5f1AKf2DQFaxslMk4CqTElABI8Te1QzTG/QOmSzewtV | |
cwcWGo4F7yJyBbnYcqvN5XJWURFjecuoTvyxPG3R2ljfTKSyJhrTkP0hw3Zxr3cn | |
pY0ZtK80mKE0A9pFG597Qy3q/9TJNRtDjeQrr7DCPwQ8cvfeyT568J+hUyAeN7PV | |
hOV/OXkWXZND9bbkYKNE4ebfiNTGCeJX9iIGjZfbzz86eDqEVpgHcJstnWN6VWbR | |
qkrK/p6m5fqYNZCMAN+g4OyHZQIDAQABo28wbTAdBgNVHQ4EFgQUK0nOsQclTJ3m | |
CpPzkLkw9+ZEn5IwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQEw | |
FgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI | |
hvcNAQELBQADggIBAGrkO1h+8wKHJHCMf/jRz5DhvigyDOyohx2LlbhL/i/0uSka | |
/u/m9uhi0UXXYX9Y15tpRUjZDqtQAjpnFePNcxe3/RRp5kuqVHaMyOHShjTTJ6YD | |
hKhlZP37qSBuWv+x2RsUrPzVdpFyljJWyJ1yruBJqgJ2sq3lskb8cO94fhcc2StT | |
uO9aB+0YY2ce5OHtOgj39Enx+PRCpweIodhAKdZuTVAX1M4qeBJD87Gg/7b4VfaS | |
aM6Frzrh9VuylCM258Xx1CYGgzTYJCcvCYOHA74nS3XigalsKonbdVHUEac+4D7i | |
P33JSlV1wlxYPPJqayiBam21YtSHmdJKV3pwkFbvlX2+pNioX86E48YaNz4faq3v | |
Cl4xHqMfVfOOG8QLiOnNlHsBKsffD420CKi2SJaKETPJnOLG61265jiT4Yr1mUeW | |
G+tQTquFeFdTTSGfToyXE58IMLhI19hQtf/2HU9aZK/vJsjWPYKCucPCXwQZA2Kk | |
Z/RT8HsSPPet3GyP3gL0nzfacohJ7RKwClE82exXgiGK/UAFqvEL9pwbLJtX4Hx/ | |
+OhT4zQ9CSppKjSBDIRR8gV6G2HY5gWKXq9K+/Dv+m1APPWsR1kTsqy+tAQPRxlK | |
7bDsXt5GawcCP+FM0vJwd5O+ZPB3x5VLG5OLv48cCRUxf1alMQSfsJz/r2L4")); | |
public static async Task<IActionResult> Run(HttpRequest req, ILogger log) | |
{ | |
log.LogInformation("C# HTTP trigger function processed a request."); | |
// string name = req.Query["name"]; | |
bool valid = false; | |
using (var chain = new X509Chain()) { | |
chain.ChainPolicy.CustomTrustStore.Add(interCertificate); | |
chain.ChainPolicy.CustomTrustStore.Add(rootCertificate); | |
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; | |
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; | |
valid = chain.Build(req.HttpContext.Connection.ClientCertificate); | |
if (!valid) { | |
foreach (X509ChainElement element in chain.ChainElements) { | |
log.LogInformation("Subject name: {0}", element.Certificate.Issuer); | |
log.LogInformation("Issuer name: {0}", element.Certificate.Issuer); | |
log.LogInformation("Certificate valid until: {0}", element.Certificate.NotAfter); | |
log.LogInformation("Certificate is valid: {0}", element.Certificate.Verify()); | |
log.LogInformation("Error status length: {0}", element.ChainElementStatus.Length); | |
for (int index = 0; index < element.ChainElementStatus.Length; index++) { | |
log.LogInformation("- {0}: {1}: {2}", index, element.ChainElementStatus[index].Status.ToString(), element.ChainElementStatus[index].StatusInformation.ToString()); | |
} | |
} | |
} | |
} | |
string subject = req.HttpContext.Connection.ClientCertificate.Subject; | |
string issuer = req.HttpContext.Connection.ClientCertificate.Issuer; | |
var extensions = req.HttpContext.Connection.ClientCertificate.Extensions; | |
var tenantIdExt = extensions.Where(x => x.Oid.Value.Equals("1.2.840.113556.5.14")).FirstOrDefault(); | |
byte[] value = System.Formats.Asn1.AsnDecoder.ReadOctetString(tenantIdExt.RawData, System.Formats.Asn1.AsnEncodingRules.DER, out _); | |
string encodedTenantId = string.Join(string.Empty, Array.ConvertAll(value, b => b.ToString("X2"))); | |
log.LogInformation(encodedTenantId); // TenantId bytes are a bit scambled, so either compare to scambled equivalent or descramble and compare to real value. | |
// string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); | |
// dynamic data = JsonConvert.DeserializeObject(requestBody); | |
// string name = name ?? data?.name; | |
// string responseMessage = string.IsNullOrEmpty(name) | |
// ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." | |
// : $"Hello, {subject} ({issuer}). The cert is valid: {valid}"; | |
string responseMessage = $"Hello, {subject} ({issuer}). The cert is valid: {valid}"; | |
return new OkObjectResult(responseMessage); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment