Obtenir la date d'expiration d'un certificat
Il existe quelques applications Web qui vous aident à vérifier l’état actuel des certificats des domaines que nous utilisons, et nous en avons quelques-unes.
J’ai créé une fonction Azure qui s’exécute une fois par jour et vérifie quelques-uns des domaines dont je dois jeter un œil, c’est une application console super simple qui si la date d’expiration du certificat est inférieure à 30 jours, elle enverra un e-mail.
La logique elle-même du fonctionnement de la fonction ne sera pas affichée, j’aimerais montrer la fonction qui effectue la vérification de base du certificat et les données que nous obtenons.
La fonction
static async Task<X509Certificate2> CheckCertificateAsync(string urlPath)
{
var certificate = new X509Certificate2();
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (request, cert, chain, policyErrors) =>
{
certificate = new X509Certificate2(cert);
return true;
}
};
using HttpClient httpClient = new HttpClient(httpClientHandler);
await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, urlPath));
return certificate;
}
Cette méthode CheckCertificateAsync nous renverra un certificat X509Certificate2 qui nous permettra de faire un tas de choses, notamment de jeter un œil à la date d’expiration.
Résultat sérialisé
Il s’agit de la valeur sérialisée de l’objet certificate :
{
"Archived":false,
"Extensions":[
{
"KeyUsages":160,
"Critical":true,
"Oid":{
"Value":"2.5.29.15",
"FriendlyName":"Key Usage"
},
"RawData":"AwIFoA=="
},
{
"EnhancedKeyUsages":[
{
"Value":"1.3.6.1.5.5.7.3.1",
"FriendlyName":"Server Authentication"
},
{
"Value":"1.3.6.1.5.5.7.3.2",
"FriendlyName":"Client Authentication"
}
],
"Critical":false,
"Oid":{
"Value":"2.5.29.37",
"FriendlyName":"Enhanced Key Usage"
},
"RawData":"MBQGCCsGAQUFBwMBBggrBgEFBQcDAg=="
},
{
"CertificateAuthority":false,
"HasPathLengthConstraint":false,
"PathLengthConstraint":0,
"Critical":true,
"Oid":{
"Value":"2.5.29.19",
"FriendlyName":"Basic Constraints"
},
"RawData":"MAA="
},
{
"SubjectKeyIdentifier":"634E1585565AA49402C21642A4A5979A38025797",
"Critical":false,
"Oid":{
"Value":"2.5.29.14",
"FriendlyName":"Subject Key Identifier"
},
"RawData":"BBRjThWFVlqklALCFkKkpZeaOAJXlw=="
},
{
"Critical":false,
"Oid":{
"Value":"2.5.29.35",
"FriendlyName":"Authority Key Identifier"
},
"RawData":"MBaAFBQusxe3WFbLrlAJQOYfr52LFMLG"
},
{
"Critical":false,
"Oid":{
"Value":"1.3.6.1.5.5.7.1.1",
"FriendlyName":"Authority Information Access"
},
"RawData":"MEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iub3JnLw=="
},
{
"Critical":false,
"Oid":{
"Value":"2.5.29.17",
"FriendlyName":"Subject Alternative Name"
},
"RawData":"MB6CHGJsb2cuZW1pbGlhbm9tb250ZXNkZW9jYS5jb20="
},
{
"Critical":false,
"Oid":{
"Value":"2.5.29.32",
"FriendlyName":"Certificate Policies"
},
"RawData":"MEMwCAYGZ4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5cHQub3Jn"
},
{
"Critical":false,
"Oid":{
"Value":"1.3.6.1.4.1.11129.2.4.2",
"FriendlyName":"SCT List"
},
"RawData":"BIH0APIAdwBByMqx3yJGShDGoToJQodeTjGLGwPr60vHaPCQYpYG9gAAAYCeJIwYAAAEAwBIMEYCIQCG8sf4iBitUjNCc1dsxVd5mdRQCKapRqqnTHKxSKHjHgIhAJFGNXEZkCHKygT1T7bE4orpd6p2l1+GmifMEIuRsgHbAHcARqVV63X6kSAwtaKJafTzfREsQXS+/Um4havy/HD+bUcAAAGAniSMNgAABAMASDBGAiEAoxv1LBn/vfyR7s67kRLB/n1tq3eicuA/8/V0S2YzQCYCIQDXaS3FZbdIVNxQvKxPFxM1awBO/sGxBXafz0lspOoWSA=="
}
],
"FriendlyName":"",
"HasPrivateKey":false,
"PrivateKey":null,
"IssuerName":{
"Name":"CN=R3, O=Let's Encrypt, C=US",
"Oid":{
"Value":null,
"FriendlyName":null
},
"RawData":"MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJSMw=="
},
"NotAfter":"2022-08-05T10:50:35+01:00",
"NotBefore":"2022-05-07T10:50:36+01:00",
"PublicKey":{
"EncodedKeyValue":{
"Oid":{
"Value":"1.2.840.113549.1.1.1",
"FriendlyName":"RSA"
},
"RawData":"MIIBCgKCAQEAq8cbDO3GAfjqqbPPCBdPost8NMRmEubv85gXecll7mZMH5qSfTPuB/ouFWL3tPMf1U8usWeoSUK/48yatzBGwmj1KKlkaW9MS2QkydztRp+kH8LvbzbQvGknuOLWGHBALLT17o/3DYxuA5LnXdY+vLvJWygQoFr2N/XhnhUjcm6OaQEJpIykydfbBQGQSEuQIIw4egpgdHkYJjCOYAsXuSSggN8/FADTCec0RzVjfFTSoJ3hV9HLE9M8MCSXjuo0AJ/MbAxq91S8XmDcRjHCCd7Zw+NjHo8cxZCQ6NqGvn3xwx8ahmmbC+CyDEcIyJJZK2Yv+qE4oS8QZfaX/RaHMwIDAQAB"
},
"EncodedParameters":{
"Oid":{
"Value":"1.2.840.113549.1.1.1",
"FriendlyName":"RSA"
},
"RawData":"BQA="
},
"Key":{
"Key":{
"Algorithm":{
"Algorithm":"RSA"
},
"AlgorithmGroup":{
"AlgorithmGroup":"RSA"
},
"ExportPolicy":0,
"Handle":{
"IsInvalid":false,
"IsClosed":false
},
"IsEphemeral":true,
"IsMachineKey":false,
"KeyName":null,
"KeySize":2048,
"KeyUsage":16777215,
"ParentWindowHandle":{
"value":0
},
"Provider":{
"Provider":"Microsoft Software Key Storage Provider"
},
"ProviderHandle":{
"IsInvalid":false,
"IsClosed":false
},
"UIPolicy":{
"ProtectionLevel":0,
"FriendlyName":null,
"Description":null,
"UseContext":null,
"CreationTitle":null
},
"UniqueName":null
},
"LegalKeySizes":[
{
"MinSize":512,
"MaxSize":16384,
"SkipSize":64
}
],
"KeyExchangeAlgorithm":"RSA",
"SignatureAlgorithm":"RSA",
"KeySize":2048
},
"Oid":{
"Value":"1.2.840.113549.1.1.1",
"FriendlyName":"RSA"
}
},
"RawData":"MIIFQDCCBCigAwIBAgISBNwTmwP/RTcrEeIgAdMrpaFtMA0GCSqGSIb3DQEBCwUAMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJSMzAeFw0yMjA1MDcwOTUwMzZaFw0yMjA4MDUwOTUwMzVaMCcxJTAjBgNVBAMTHGJsb2cuZW1pbGlhbm9tb250ZXNkZW9jYS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrxxsM7cYB+Oqps88IF0+iy3w0xGYS5u/zmBd5yWXuZkwfmpJ9M+4H+i4VYve08x/VTy6xZ6hJQr/jzJq3MEbCaPUoqWRpb0xLZCTJ3O1Gn6Qfwu9vNtC8aSe44tYYcEAstPXuj/cNjG4Dkudd1j68u8lbKBCgWvY39eGeFSNybo5pAQmkjKTJ19sFAZBIS5AgjDh6CmB0eRgmMI5gCxe5JKCA3z8UANMJ5zRHNWN8VNKgneFX0csT0zwwJJeO6jQAn8xsDGr3VLxeYNxGMcIJ3tnD42MejxzFkJDo2oa+ffHDHxqGaZsL4LIMRwjIklkrZi/6oTihLxBl9pf9FoczAgMBAAGjggJZMIICVTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFGNOFYVWWqSUAsIWQqSll5o4AleXMB8GA1UdIwQYMBaAFBQusxe3WFbLrlAJQOYfr52LFMLGMFUGCCsGAQUFBwEBBEkwRzAhBggrBgEFBQcwAYYVaHR0cDovL3IzLm8ubGVuY3Iub3JnMCIGCCsGAQUFBzAChhZodHRwOi8vcjMuaS5sZW5jci5vcmcvMCcGA1UdEQQgMB6CHGJsb2cuZW1pbGlhbm9tb250ZXNkZW9jYS5jb20wTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEGBgorBgEEAdZ5AgQCBIH3BIH0APIAdwBByMqx3yJGShDGoToJQodeTjGLGwPr60vHaPCQYpYG9gAAAYCeJIwYAAAEAwBIMEYCIQCG8sf4iBitUjNCc1dsxVd5mdRQCKapRqqnTHKxSKHjHgIhAJFGNXEZkCHKygT1T7bE4orpd6p2l1+GmifMEIuRsgHbAHcARqVV63X6kSAwtaKJafTzfREsQXS+/Um4havy/HD+bUcAAAGAniSMNgAABAMASDBGAiEAoxv1LBn/vfyR7s67kRLB/n1tq3eicuA/8/V0S2YzQCYCIQDXaS3FZbdIVNxQvKxPFxM1awBO/sGxBXafz0lspOoWSDANBgkqhkiG9w0BAQsFAAOCAQEAjSEID5MWonbSiyHbmPYWO8ImCCOjkLGxgY8WJODbrWxFy+xU44UwrWOCkqYZUlv2LRmPqSyZDrIeeHK9VMbGh71oXX+XovikgAr6PpI0Mp897nPWj0XvOBaSYG0s+f+CXMtyt0tWCsQOcl+iT82+Ja71f8gbVL6l7xESewEE78pTKEH8EqD22r8VSD7FNICD8EYQr13v3AuVWObSU/R8Td6SrSVEknw1HgJS4e9nvmrMxBGKOJ+aWrAGiUydehg8M9o2gbGckMhz6D7cwB5l618cYaXKkW1dEOYZHl++qUj1/VPK+FNkiDZOPVNN//PbZuOLwAUIlZvhqGWX5/9PBg==",
"SerialNumber":"04DC139B03FF45372B11E22001D32BA5A16D",
"SignatureAlgorithm":{
"Value":"1.2.840.113549.1.1.11",
"FriendlyName":"sha256RSA"
},
"SubjectName":{
"Name":"CN=blog.emilianomontesdeoca.com",
"Oid":{
"Value":null,
"FriendlyName":null
},
"RawData":"MCcxJTAjBgNVBAMTHGJsb2cuZW1pbGlhbm9tb250ZXNkZW9jYS5jb20="
},
"Thumbprint":"28CF960F772ABFF22AA193C291492C27F8E13D4D",
"Version":3,
"Handle":{
"value":2658150705632
},
"Issuer":"CN=R3, O=Let's Encrypt, C=US",
"Subject":"CN=blog.emilianomontesdeoca.com"
}
Date d’expiration
Afin de connaître le délai d’expiration, nous devons jeter un œil aux NotAfter et NotBefore, qui se trouvent à l’intérieur de cet objet :
"NotAfter":"2022-08-05T10:50:35+01:00",
"NotBefore":"2022-05-07T10:50:36+01:00",
##Application console
L’extrait suivant est une simple application console construite sur .NET 6, qui produira le résultat suivant, dans lequel vous pourrez vérifier n’importe laquelle des certifications de votre choix :
using Newtonsoft.Json;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
var url = "https://blog.emilianomontesdeoca.com/";
static async Task<X509Certificate2> CheckCertificateAsync(string urlPath)
{
var certificate = new X509Certificate2();
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (request, cert, chain, policyErrors) =>
{
certificate = new X509Certificate2(cert);
return true;
}
};
using HttpClient httpClient = new HttpClient(httpClientHandler);
await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, urlPath));
return certificate;
}
var cert = await CheckCertificateAsync(url);
var serializedValue = JsonConvert.SerializeObject(cert);
Console.WriteLine(serializedValue);
Console.ReadLine();
Projet de démonstration
Vous pouvez trouver l’application console dans mon Github, dans le référentiel appelé expiration-date-certificate.