PKI – budowa certyfikatu (1)

Poprzednio opisałem podstawowe pojęcia dotyczące infrastruktury klucza publicznego. Teraz chciałbym bliżej zająć się samym certyfikatem. Tym jaką on ma budowę, które elementy są ważne, a które opcjonalne.

Będzie to bardzo ogólny opis dotyczący podstawowych elementów certyfikatów. Po więcej mogę odesłać do RFC 5280. Natomiast w temacie rozszerzeń planuję dedykowany wpis.

Budowa certyfikatów zdefiniowana jest w RFC5280. Poniżej poglądowy schemat wraz z opisem pól.

Wersja
Liczba mówiąca o wersji certyfikatu – v1(0), v2(1), v3(2)
Numer seryjny
Dodatni numer całkowity, nadawany przez CA. Każdy certyfikat musi mieć unikalny numer w ramach CA.
Podpis
Pole zawiera nazwę algorytmu wykorzystanego do podpisu certyfikatu. Parametry są opcjonalne i będą się różnić w zależności od wskazanego algorytmu.
Wydawca
Nazwa wystawcy certyfikatu w postaci „distinguished name”.
Termin ważności
Czasy ważności „nie przed” i „nie po”. Zapisane w UTC bądź jako GeneralizedTime (od roku 2050).
Właściciel
Nazwa podmiotu, dla którego wydany jest certyfikat, w postaci „distinguished name”.
Informacja o kluczu publicznym
Pole służy do przechowywania klucza publicznego oraz informacji o algorytmie, z którym ten klucz może być wykorzystywany.
Unikatowy ID wystawcy
Unikalny ID właściciela
Pola aktualnie nie są używane. Są to elementy opcjonalne, dozwolone od wersji v2.
Rozszerzenia
Dodatkowe atrybuty certyfikatów. Są to elementy opcjonalne, dozwolone od wersji v3.
Przykładowy certyfikat

Poniżej przykładowa struktura certyfikatu w wersji pierwszej. W taki sposób certyfikat przedstawiany jest przez narzędzie OpenSSL.

Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 4096 (0x1000)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=PL, ST=LODZKIE, O=pworwag.com.pl, CN=PWORWAG.COM.PL INTERMEDIATE CA
        Validity
            Not Before: Apr  8 11:37:55 2023 GMT
            Not After : Apr 17 11:37:55 2024 GMT
        Subject: C=PL, ST=LODZKIE, O=pworwag.com.pl, CN=DailyRoutine JWT
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:e6:6c:d5:18:ab:57:a5:71:96:78:67:00:d7:59:
                    e4:6e:df:2c:ee:a5:48:89:2c:10:e7:85:99:d0:81:
                    c4:b3:ba:ab:20:ea:2d:b1:44:fe:63:1a:61:80:c0:
                    e7:15:17:2b:78:f8:8c:04:a5:82:1a:a2:39:d1:ba:
                    6c:63:4c:82:67:ae:66:6b:b0:d1:ea:c7:cb:40:4f:
                    1e:8a:b0:82:6c:b6:0a:3c:f7:fb:c7:d3:ba:1e:8f:
                    5b:9a:a5:94:96:4f:8d:b6:58:af:fa:1d:c8:5e:57:
                    4f:d0:f5:80:9f:7d:3b:99:f5:9e:a1:6f:02:64:40:
                    eb:2c:ad:e3:a8:2f:a9:ad:72:0e:b8:d3:b6:b1:47:
                    1d:2f:b9:2b:b0:34:ed:36:f8:16:75:9d:12:7e:ff:
                    d6:1b:51:9a:f7:6f:b9:e5:e2:a6:c5:a7:1d:99:14:
                    3f:17:fb:07:ea:62:52:db:ef:29:b9:eb:14:4a:13:
                    fa:42:d9:b1:95:90:e1:4b:02:45:9d:53:c9:c4:0b:
                    76:a0:dc:ed:ed:f6:ff:37:2e:ef:bc:b4:e1:88:c7:
                    5a:d8:c3:a9:d1:9b:65:ca:49:be:66:25:23:e5:67:
                    7d:bf:32:11:f7:fa:90:f0:c2:64:25:6b:0f:3c:4e:
                    05:ed:5f:a9:ad:5f:e0:fe:57:51:9c:eb:c5:a5:16:
                    47:d3
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         39:48:a2:66:9c:ca:d2:9b:7c:10:99:bf:8e:39:91:d7:73:d2:
         3b:75:14:5b:49:6b:bf:76:71:73:fe:d2:fd:3c:82:68:cb:e4:
         15:44:ff:d6:c1:50:59:bc:51:6a:67:42:6a:bc:da:6e:d4:5e:
         cc:e3:9d:30:38:9b:e8:6b:58:6b:6f:0d:ca:b8:a8:48:7f:ae:
         f7:e7:dc:58:8f:eb:75:bb:f4:9d:04:7a:9c:5a:be:4b:4c:89:
         7d:f3:ee:3d:50:66:8f:ba:e4:c6:6e:d4:96:8c:ee:2f:b5:b0:
         11:57:cb:ad:8d:4c:6d:45:72:e2:34:2d:ae:34:37:5e:20:52:
         78:11:03:96:35:78:71:d2:3e:01:b4:82:fa:9d:cf:cf:5f:cf:
         9d:1c:8f:34:a0:21:38:f0:0a:56:fa:12:ce:51:82:56:ea:47:
         2b:95:20:25:47:2d:bc:2b:45:7c:e3:49:0e:a5:09:74:7a:0d:
         28:72:4c:d7:5f:02:57:a8:66:eb:f4:10:9d:f5:79:b5:77:f4:
         95:3e:c7:05:29:90:16:e2:31:b8:06:99:c8:53:78:2d:d1:fd:
         4e:f2:b7:ff:a0:b4:58:b9:f1:20:5f:6b:49:2a:0a:56:0a:ea:
         e1:e5:b3:e1:6d:c3:94:f1:d7:07:62:4a:67:80:c8:06:f3:29:
         16:64:ed:58:f1:c1:91:53:ce:62:66:43:ae:c6:c7:d5:da:db:
         18:db:0f:ce:a3:19:65:79:3a:db:60:03:bf:6e:1a:dc:ae:e4:
         df:4e:0c:01:ea:5b:b1:46:fe:c7:c8:bb:15:9b:1a:cd:0d:e8:
         b1:44:3d:0d:12:73:1e:4e:2c:55:0b:97:57:61:26:e1:44:1b:
         cb:5a:72:ee:fd:ba:94:ef:02:76:43:43:93:66:4b:e2:99:6f:
         bb:fe:51:ee:67:37:8c:bf:32:d1:ac:1d:12:5d:1f:80:9e:9c:
         e5:58:4a:30:5e:17:3a:0b:eb:4e:6b:75:42:34:a4:18:24:16:
         9f:ed:ba:2b:c5:8a:91:a8:b7:e8:05:d6:77:dd:d3:48:f7:1e:
         aa:84:e0:c4:c6:6d:bc:64:d9:58:31:f3:e4:f7:ff:4b:5f:f3:
         ae:ef:c9:aa:63:09:a6:5e:5f:49:c4:27:87:ff:2d:93:4f:fb:
         36:59:5d:14:3b:66:46:f4:3a:4d:5d:7a:c4:e6:a7:b9:4a:69:
         32:bd:b0:6f:5a:29:66:3e:c9:7a:84:a2:7f:93:fb:9d:da:54:
         81:d9:ef:c3:2c:f7:ee:06:22:52:99:95:f8:38:62:51:8b:aa:
         83:1a:cc:06:5f:49:59:ae:01:ef:e9:3e:38:ba:3f:f3:0b:48:
         df:d4:eb:1b:8d:87:d9:cf

Podstawowe parametry łatwo jest odczytać programowo. Przykład poniżej.

using System.Security.Cryptography.X509Certificates;

var store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
Console.WriteLine($" Certificates count: {store.Certificates.Count}\n\n");
var c = store.Certificates[0];
Console.WriteLine($"           Version: {c.Version}");
Console.WriteLine($"      SerialNumber: {c.SerialNumber}");
Console.WriteLine($"SignatureAlgorithm: {c.SignatureAlgorithm.FriendlyName}");
Console.WriteLine($"            Issuer: {c.Issuer}");
Console.WriteLine($"         NotBefore: {c.NotBefore}");
Console.WriteLine($"          NotAfter: {c.NotAfter}");
Console.WriteLine($"           Subject: {c.Subject}");
var pk = c.PublicKey;
Console.WriteLine($"PublicKeyAlgorithm: {c.PublicKey.Oid.FriendlyName}");
Console.WriteLine($"  Extensions count: {c.Extensions.Count}");
store.Close();