Architektura PrivMX – PKI

Infrastruktura kluczy publicznych PrivMX

PrivMX PKI to elementy architektury PrivMX realizujące publikację i weryfikację kluczy publicznych użytkowników i serwerów. Mają one znaczenie przede wszystkim w przypadku systemów zdecentralizowanych i umożliwiają m.in. weryfikację nadawców wiadomości – sprawdzenie czy odebrana właśnie wiadomość zawiera poprawny podpis nadawcy.

PrivMX nie wykorzystuje w tym celu rozwiązań klasycznego PKI zakładającego wykorzystanie zewnętrznych urzędów certyfikacji. Nie wykorzystuje również rozwiązań PGP opartych o wzajemne podpisywanie kluczy publikowanych na zewnętrznych serwerach.

Infrastruktura kluczy publicznych PrivMX bazuje na ideach związanych ze specyfikacją CONIKS (https://coniks.org), dzięki czemu spełnione może być jedno z założeń bezpiecznej komunikacji PrivMX – likwidacja lub minimalizacja roli „zaufanej trzeciej strony” kontrolowanej przez firmy/organizacje zewnętrzne względem aplikacji.

W przypadku aplikacji zdecentralizowanych, w domyślnej konfiguracji każdy serwer PrivMX prowadzi własną bazę kluczy publicznych (keystores) swoich użytkowników i udostępnia ją poprzez API programom klienckim.

Bazy kluczy PrivMX to prywatne bazy publikujące hash (w sensie „skrót kryptograficzny” SHA256) całej swojej zawartości oraz historię zmian tego hasha przy pomocy struktury typu append-only (tj. blockchain). Dzięki temu bazy te mogą podlegać audytowi i monitorowaniu spójności przeprowadzanemu przez inne serwery PrivMX. Każdy pobierany klucz publiczny (keystore) dostarczany jest razem z dowodem poprawności, który powiązany jest z hashem całości bazy. Weryfikacja poprawności pobranego keystore składa się z dwóch kroków – sprawdzenie poprawności hasha bazy w oparciu o jego historię (przeprowadzane również wspólnie z innymi serwerami – audyty, web-of-trust) oraz sprawdzenie dostarczonego dowodu poprawności keystore.

Poniższe podrozdziały opisują nieco dokładniej cechy i działanie PrivMX PKI oraz domyślny sposób wykorzystania tych mechanizmów w aplikacji zdecentralizowanej.

Prywatna baza kluczy z publiczną historią zmian

„KeyStore” to nazwa, która w PrivMX oznacza „pęk kluczy”. Architektura PrivMX zakłada obsługę dwóch typów keystores:

  • pgpkeystore – keystore kompatybilny z PGP, zawierający pełną historię zmian, pozwalający na wykonywanie na jego danych operacji takich jak unieważnianie kluczy (revoke) oraz dodawanie podkluczy (i innych pakietów PGP tj public key, signature, userid). Zmian keystore tego typu dokonywać może posiadacz wyróżnionego klucza prywatnego.
  • simplekeystore – keystore o prostej konstrukcji, zawierający listę kluczy publicznych. Taki keystore może być modyfikowany przy pomocy dowolnego, pasującego klucza prywatnego. Historia zmian keystore tego typu nie jest w nim pamiętana.

Keystores oprócz danych kluczy i informacji o swoim typie zawierać mogą również załączniki będące dowolnymi plikami.

Standardowe implementacje serwera i klienta PrivMX dostarczają odpowiednich funkcji do posługiwania się obydwoma typami keystores. Pozwalają one na ich tworzenie, czytanie i modyfikowanie przy użyciu kluczy prywatnych użytkowników. W tym dokumencie pomijamy opis tych funkcji.

Zbiór (baza) keystores przechowywanych przez serwer PrivMX ma strukturę binarnego drzewa Merkle. W uproszczeniu przedstawić można to tak, że liście drzewa to keystores, a węzły inne niż liście składają się z hashy SHA256 swoich potomków. Hash korzenia drzewa jest zatem hashem całości bazy – nazywany jest on często „rewizją drzewa” lub „rewizją bazy”.

Każda zmiana w drzewie (tzn. dodanie lub modyfikacja keystore) powoduje zmiany na odpowiednich gałęziach drzewa oraz zmianę hasha całości bazy. Oprócz historii zmian drzewa, PrivMX PKI przechowuje również historię zmian hasha-rewizji całości bazy w postaci listy typu append-only – każdy element tej historii zawiera kolejny hash bazy oraz hash elementu poprzedniego w historii.

Ta lista, podobna do struktury blockchain, jest przez serwer PrivMX udostępniana publicznie (API.pkiGetHistory). Nie zawiera ona w sobie żadnych danych (kluczy i załączników), które są przechowywane przez PrivMX PKI, ale wystarcza do przeprowadzenia weryfikacji kluczy pobieranych z danego serwera oraz do przeprowadzania zewnętrznych audytów bazy.

Pobieranie i weryfikacja kluczy publicznych

Dostęp do keystores na poziomie API serwera odbywa się poprzez zastosowanie czytelnych identyfikatorów alfanumerycznych takich jak „server:simplito.com”, „user:john#example.com”. Identyfikatory takie przekształcane są przez serwer na zero-jedynkowe ścieżki w drzewie binarnym przy pomocy weryfikowalnej funkcji losowej (Verifiable Random Function). PrivMX PKI stosuje ścieżki-identyfikatory o ustalonej długości 256 bitów oraz przeprowadza ich kompresję, aby uniknąć tworzenia drzew o zbyt dużej głębokości.

Argumentami funkcji API.pkiKeyStoreGet są:

  • name – identyfikator alfanumeryczny zawierający dwukropek (wyznacza on namespaces);
  • includeAttachments – jeśli równe true (1), to funkcja oprócz danych kluczy zwraca również wszystkie załączniki wybranego keystore;
  • revision – hash (rewizja) bazy, z której pobrany ma zostać keystore.

Funkcja zwraca dane keystore (jeśli odpowiedni keystore istnieje w bazie), dowód poprawności oraz załączniki, jeśli były wymagane. „Dowód poprawności” to generowany przez wspomnianą funkcję VRF ciąg zawierający odpowiednie fragmenty ścieżki binarnej oraz wszystkie hashe węzłów (w tym korzenia) potrzebne do tego, aby program kliencki mógł zweryfikować, że pobrany keystore należy do bazy wymaganej rewizji i że nie brakuje w nim żadnych danych. Odpowiednie funkcje realizujące tę weryfikację dostarczone są w standardowych implementacjach klienta PrivMX.

Pominięcie parametru revision podczas pobierania keystore powoduje, iż serwer wykorzysta rewizję bazy danych obowiązującą w momencie zapytania. Wówczas sprawdzenie dowodu poprawności wymaga dodatkowo pobrania historii bazy, aby odnaleźć w niej zawarty w dowodzie hash-rewizję bazy.

Pobieranie historii bazy oraz keystores możliwe jest po nawiązaniu „standardowego” połącznienia PrivMX TLS – jest domyślnie dostępne dla wszystkich programów klienckich. Serwer udostępnia również funkcje API.pkiKeyStorePut, API.pkiKeyStoreModify, API.pkiKeyStoreDelete, do których dostęp jest limitowany i konfigurowany w zależności od konkretnej aplikacji.

Audyty, konsensus, web-of-trust

Pomimo możliwości weryfikacji kluczy, która opisana jest powyżej, program kliencki musi „wierzyć” serwerowi, z którego je pobiera. W sytuacji aplikacji zdecentralizowanej i otwartej nie jest to kwestia oczywista, gdy wykorzystywanych jest wiele serwerów należących do różnych osób i organizacji. Aby uniknąć sytuacji takiej, że klientowi przedstawiana jest historia i klucze inne niż pozostałym klientom – można sprawdzić serwer przeprowadzając audyt.

Audyt polega na rozesłaniu do wybranych (innych) serwerów prośby o weryfikację historii bazy sprawdzanego serwera. Polega to na nawiązaniu połączenia i wywołaniu w wybranych serwerach API.pkiConfirmRevision podając jedynie:

  • hostname – nazwa domeny serwera, który chcemy sprawdzić;
  • revision – hash bazy, którego istnienie na docelowym serwerze chcemy potwierdzić.

Serwery proszone o audyt sprawdzają czy serwer hostname udostępnia im spójną historię zawierającą revision. Dokonują w tym celu odpowiednich wywołań API.pkiGetHistory oraz wykorzystują zapamiętaną wcześniej historię bazy serwera hostname. Każdy z proszonych o pomoc serwerów przekazuje ostatecznie informację, czy on również widzi revision na serwerze hostname, czy nie.

Po zebraniu tych informacji program kliencki może odpowiednio poinformować użytkownika o poziomie wiarygodności serwera, którego klucze pobiera i weryfikuje. Jeśli wszystkie odpowiedzi od audytorów są pozytywne lub wszystkie są negatywne, to możemy mówić o osiągnięciu porozumienia (konsensus) odnośnie wiarygodności sprawdzanego serwera. Wszystkie sytuacje pośrednie, gdy odpowiedzi są różne lub gdy niektóre serwery nie odpowiadają, wymagają skonfigurowania w aplikacji klienckiej odpowiedniej heurystyki wyznaczającej konsensus i/lub wyznaczenia operacji dostępnych dla użytkownika (oznaczenie serwera jako niezaufanego, ponowna próba weryfikacji, konsultacje z użytkownikami innych serwerów itp.).

Ilość i dobór serwerów-audytorów to dwie najważniejsze sprawy podczas zlecania audytów. Aplikacja, która je wykonuje może wykorzystywać ustalone, zaufane serwery PrivMX lub/oraz może pozwalać użytkownikom na budowanie własnych web-of-trust – sieci zaufanych serwerów. Może wybierać audytorów losowo lub według dowolnych własnych kryteriów. Architektura PrivMX nie determinuje sposobu dobierania serwerów, jest to zależne od konkretnej aplikacji.

Przykłady wykorzystania PrivMX PKI

Poniżej opisujemy działania, które domyślnie podejmuje serwer PrivMX konfigurowany do pracy w ramach aplikacji zdecentralizowanej (np. aplikacja PrivMX WebMail dostępna pod adresem https://privmx.com).

  • Podczas instalacji serwera PrivMX ustalany jest klucz prywatny serwera, a odpowiedni klucz publiczny umieszczany jest w PrivMX PKI pod identyfikatorem „server:hostname”.
  • Każde wywołanie API.register, które rejestruje nowego użytkownika wstawia do bazy klucz publiczny użytkownika (IdentityKeyPub) z identyfikatorem „user:id#hostname”. Do tego klucza dołączone są załączniki zawierające avatar użytkownika, SID jego publicznej skrzynki pocztowej oraz inne publiczne dane profilowe. Keystore ten wykorzystywany jest przez innych użytkowników m.in. do weryfikowania wiadomości podpisanych przez użytkownika id#hostname.
  • Pierwszy użytkownik tworzący konto na nowym serwerze uzyskuje prawa administratora. W trakcie pierwszego logowania tego użytkownika do bazy dopisywany jest keystore „admin:hostname” (typu simplekeystore), którego rolą jest przechowywanie kluczy publicznych wszystkich administratorów serwera. Keystore ten udostępniany jest domyślnie wszystkim użytkownikom danego serwera, którzy mogą sprawdzić dzięki temu, czy np. dana wiadomość pochodzi od admina ich serwera.

Wspomniana aplikacja PrivMX WebMail pozwala dodatkowo administratorom serwerów na tworzenie własnych sieci web-of-trust. Wysyłają oni między sobą specjalne wiadomości-zaproszenia, których zaakceptowanie powoduje, że oba serwery dopisują się wzajemnie do swoich prywatnych list zaufanych serwerów. Listy te przechowywane są jako załączniki w keystore „admin:hostname” i są odczytywane przez każdego użytkownika podczas każdego logowania. W ten sposób administrator publikuje (proponuje) listy zaufanych serwerów swoim klientom. Dodatkowo, działanie funkcji API.pkiRevisionConfirm ograniczone jest na serwerze tak, że przeprowadza ona audyt tylko wtedy, gdy prosi ją o to serwer z listy zaufanych serwerów.


Spis treści: Architektura PrivMX
Wersja PDF: Architektura PrivMX – opis techniczny (pdf, PL)english version