Projekt aplikacji CA

Daniel Rychcik
24-11-2000

0. Wstęp

Dokument ten jest szczegółowym projektem aplikacji dla urzędu certyfikacyjnego. Zasadnicze założenia w nim zawarte zostały ustalone na drodze dyskusji, zatem proponuję aby nie wprowadzać już w nich rewolucyjnych zmian i rozpocząć pisanie.

Kwestie związane z OpenSSL-em omówiłem dość szczegółowom natomiast szczegóły współpracy z LDAP-em są jeszcze sprawą otwartą.

I. Opis ogólny

Aplikacja ma umożliwiać wykonywanie następujących czynności związanych z pracą urzędu certyfikacyjnego:

  • Wystawianie certyfikatów
  • Przeglądanie wystawionych certyfikatów
  • Wyszukiwanie certyfikatów spełniających pewne kryteria
  • Unieważnianie certyfikatów w oparciu o CRL

Aplikacja ma współpracować z bazą LDAP w której przechowywane i udostępniane na zewnątrz będą certyfikaty.

W obecnej wersji aplikacja nie przewiduje żadnej formy zarządzania kluczami prywatnymi użytkowników - wychodzimy z założenia, że docelowy odbiorca (UMK) nie wymaga aż takiego stopnia ochrony danych, natomiast przechowywanie ich w jakiejkolwiek formie wprowadza mimo wszystko pewne ryzyko nadużyć.

Wymagania aplikacji względem środowiska to:

  • System UNIX-owy (testy na Linuxie i Solarisie)
  • Pakiet openssl
  • Serwer WWW z obsługą SSL oraz PHP3 (zalecane: apache, mod_ssl, mod_php )
  • Oprogramowanie serwera LDAP
  • Wszystkie pakiety wymagane przez w/w programy (czyli na przykład BerkeleyDB, Perl 5 itp.)

II. Drzewo certyfikacji

Obiekty podlegające certyfikacji umieszczane są w ściśle zdefiniowanej strukturze opartej o notację ASN. Podstawowe założenia tej struktury to:

  • Hierarchia obiektów oparta jest wyłącznie o pola O (Organization) i OU(Organizational Unit), przy czym dopuszczamy tylko jeden atrybut O na dowolnym poziomie hierarchii (w naszym przypadku - O=UMK).
  • Pola C (Country) i L (Location) mają charakter pomocniczy i nie są związane z hierarchią
    (Ma to na celu dopuszczenie do sytuacji, w której w naszą strukturę wlączany jest np. profesor z innego kraju)
  • Każdy obiekt ma obowiązkowy atrybut email - jego interpretacja jest różna w zależności od typu certyfikatu (patrz niżej).
  • Nazwy obiektów zawarte w polu DN są skrótowe - np. identyfikator użytkownika, lub symbol urzędu certyfikacyjnego. Dokładna nazwa obiektu jest zawarta w polu unstructuredName. (będzie ono tutaj oznaczane UN, jednak w plikach konfiguracyjnych trzeba używać pełnej nazwy!)

Certyfikaty można podzielić na kilka typów w zależności od przeznaczenia i możliwych zastosowań:

Certyfikaty obiektów końcowych

  • email - certyfikat służący wyłącznie do podpisywania, lub szyfrowania poczty elektronicznej. Interpretacja pól w certyfikacie jest następująca:
    • DN - identyfikator użytkownika
    • Email - pełny adres e-mail
    • UN - imię i nazwisko
  • server - certyfikat służący do uwiarygadniania bezpiecznego serwera WWW.
    Interpretacja pól w certyfikacie:
    • DN - pełny URL serwera (https://domena/adres)
    • email - adres e-mail administratora serwera
    • UN - nazwa serwera (nie adres)
  • client - certyfikat służący do potwierdzania tożsamości klienta korzystającego z bezpiecznego serwera WWW.
  • email_client - certyfikat łączący dwie opisane wyżej funkcje.
    (Interpretacja pól w certyfikatach dwóch ostatnich typów jest identyczna jak dla typu email)

Certyfikaty urzędów certyfikacyjnych niższych rzędów

  • sslCA - certyfikat CA upoważnionego do wystawiania certyfikatów typu client i server.
  • emailCA - certyfikat CA upoważnionego do wystawiania certyfikatów typu email.
  • SSL_emailCA - certyfikat CA upoważnionego do wystawiania certyfikatów obydwu typów.

W certyfikatach CA dodatkowe pola mają identyczne znaczenie:

  • DN - nazwa skrótowa CA (np. ca_UMK)
  • email - adres e-mail administratora CA
  • UN - pełna nazwa CA (Urząd Certyfikacyjny UMK)

Dla certyfikatów CA podrzędnych określony jest zawsze jeden dodatkowy atrybut OU który określa nazwę jednostki organizacyjnej dla której tworzymy nowy urząd.

Zależności między obiektami w proponowanej realizacji PKI dla UMK przedstawione są na rysunku:

Schemat PKI

III. Powiązanie aplikacji z pakietem OpenSSL

Aplikacja będzie zbudowana tak, aby do minimum ograniczyć stopień ingerencji w system. I tak: pakiet openssl będzie uzywany do generowania kluczy, certyfikatów itp, ale cała jego konfiguracja, klucze itp. będą przechowywane w katalogu macierzystym CA. Podobnie serwer slapd - używał będzie plików zlokalizowanych w tym katalogu.

Przy instalacji systemu powinna istnieć możliwość pracy na portach nie zastrzeżonych dla systemu (>1024).

Szczególnie ważną rolę pełnią pliki konfiguracyjne openssl, dlatego zostaną tutaj omówione dokładniej, z uwzględnieniem zalecanych wartości opcji dla poszczególnych typów certyfikatów. Część informacji (zwłaszcza w sekcji X509-extensions) wynika z moich eksperymentów i analizy przykładowych plików, zatem należy je traktować ostrożnie i w miarę możliwości weryfikować w praktyce.

1. Sekcje typu CA

Przechowują podstawowe informacje o katalogach, lokalizacji kluczy/certyfikatów i pewnych wartościach domyślnych. Pierwszą linią w pliku konfiguracyjnym powinna być linia:

  HOME = <katalog domowy CA>

Jest ona używana przez większość poleceń openssl odwołujących się do specyfiki danego CA (np. x509, req, cai). Następnie pojawia się sekcja zawierająca informacje dla polecenia ca. W ogólności możemy w jednym pliku zdefiniować ustawienia dla wiekszej liczby CA, jednak my zastosujemy rozwiązanie z osobnym plikiem konfiguracyjnym dla każdego typu certyfikatu. Zatem jedynym wpisem w sekcji [ca] będzie:

  default_ca = cf_<typ>

Nastepnie pojawia się sekcja [cf_<typ>] zawierająca już konkretne parametry:

  dir                 = <katalog>
  certs               = <katalog>
  crl_dir             = <katalog>
  new_certs_dir       = <katalog>

  certificate         = <plik z certyfikatem CA>
  private_key         = <klucz prywatny CA>
  database            = <może być $HOME/index.txt>
  serial              = <może być $HOME/serial>

  default_days        = 365
  default_crl_days    = 21
  default_md          = md5
  preserve            = no
  policy              = policy_<typ>
  x509_extensions     = x509ext_<typ>

2. Sekcje [policy]

Sekcje tego typu zawierają informację dla polecenia ca o warunkach certyfikacji zgłoszonych CSR-ów. Dla każdego pola w DN możemy zdefiniować, że jest ono:

  • Wymagane i zgodne (match)
    (dane pole w CSR musi mieć identyczną wartość jak w certyfikacie CA)
  • Wymagane (supplied)
    (dane pole w CSR musi być niepuste)
  • Opcjonalne (optional)

Przykładowo dla certyfikatów e-mail CA najwyższego poziomu można przyjąć:

  C                = supplied
  L                = supplied
  O                = match
  CN               = supplied
  Email            = supplied
  unstructuredName = supplied

Punkt 5. zawiera dokładne propozycje policies dla poszczególnych typów certyfikatów

3. Sekcje [x509-extensions]

Sekcje tego typu zawierają informacje dla polecenia CA w jaki sposób ma generować certyfikaty danego typu, jakie nadawać im atrybuty itp. W szczególności określają, czy dany certyfikat jest certyfikatem obiektu końcowego (użytkownika, serwera), czy CA niższego rzędu. Ważniejsze atrybuty to:

  nsCertType         = email, client, server, sslCA, emailCA
  basicConstraints   = CA:true|false
  keyUsage           = cRLSign, keyCertSign, 
                       nonRepudiation, digitalSignature
  subjectaltName     = email:copy
  nsComment          = "Komentarz do certyfikatu"
  nsBaseUrl          = http://kompletny.adres/wystawcy/
  nsCaRevocationUrl  = sufix/listy.crl

Punkt 5. zawiera dokładne wartości rozszerzeń dla poszczególnych typów certyfikatów.

4. Sekcje [req] i [dn]

Te sekcje są używane przez polecenie req do generowania zleceń certyfikacji. Pierwsza z nich w naszym przypadku będzie krótka i ograniczy sie do:

  [ req ]
  default_bits         = 512 | 1024
  distinguished_name   = dn_<typ>

Natomiast odpowienia sekcja [ dn_<type> ] zawiera konkretne parametry dla zleceń. Dla każdego z nich można określić pewien "prompt" (w naszym przypadku jest to nieistotne, dlatego ustawiamy np. C=C, unstructuredName=unstructuredName itp. Można równiez określić domyślną wartość, dodając sufiks _default do nazwy pola. My co prawda nie będziemy z tego korzystać (dane będą i tak generowane przez formularz, a potem przetwarzane w trybie wsadowym), jednak do celów testowych definiujemy pola C,L,O jako kopie odpowienich pól z certyfikatu aktualnego CA.

5. Wnioski praktyczne

Przyjmujemy rozwiązanie, że katalog urzędu certyfikacyjnego zawiera podkatalogi certs, newcerts, private, conf i w tym ostatnim przechowywany jest szereg plików konfiguracyjnych o nazwach postaci <typ>_cf, które przy wywołaniu openssl-a są wskazywane zawsze opcją -config. W każdym z tych plików wszystkie parametry dotyczące katalogów i kluczy CA są identyczne. Różnią się tylko nazwy typów certyfikatów oraz sekcje [policy] i [x509_extensions]. W porównaniu do pojedynczego pliku konfiguracyjnego taka struktura jest łatwiejsza do automatycznego generowania i utrzymania.

Domyślne wartości policies i X509-extensions zależą od typu certyfikatu i głębokości zagnieżdżenia w hierarchii certyfikacji. Ogólnie przyjmujemy założenie, że wszelkie obiekty (serwery i klienci) certyfikowane przez dane CA maja ten sam atrybut O i atrybuty OU, różnią się za to CN-em (i trzeba to sprawdzać na etapie wprowadzania danych).

Certyfikaty podrzędnych CA są natomiast generowane tak, by zachować wszystkie O i OU aktualnego CA, ale muszą dodawać nowy poziom OU (i ma tam być zapisana nazwa podorganizacji dla której tworzymy CA). Nie należy tego mylić z CN-em nowo tworzonego CA - tam jest zapisana nazwa urzędu certyfikacyjnego!

Uwagi o O i OU dotyczą oczywiście również sekcji [req] i odpowiedniej sekcji [dn] - zachodzą tam podobne zależności.

Jesli chodzi o x509_extensions to wartości poszczególnych pól przedstawiają sie następująco:

  • nsCerttype - tu akurat zależność jest naturalna: mamy następujące możliwości: email, client, server, emailCA, sslCA. Można te opcje łączyć, tworząc np. CA mogące wystawiać certyfikaty obiektów wszystkch rodzajów, ale nie mogące tworzyć CA podrzędnych.
  • basicConstraints - musimy tu wstawić CA:false lub CA:true odpowiednio dla certyfikatu obiektu i nowego CA.
  • keyUsage - dla CA wpisujemy cRLSign, keyCertSign, dla obiektów zaś: nonRepudiation, digitalSignature.
  • Pozostałe 4 pola wymienione powyżej nie wymagają chyba dodatkowego opisu.

Nietrywialna jest również kwestia automatycznego operowania pakietem openssl. Jest on z natury przystosowany do wywoływania z linii komend i praca w trybie wsadowym (naturalnym przy pracy z poziomu przeglądarki) wymaga włożenia dużego wysiłku na przykład w przechwytywanie i obsługę błędów.

Pierwszą kwestią są hasła. Można je przekazywać do wszystkich poleceń openssl korzystając z opcji -passin oraz -passout. Pierwsza określa źródło haseł dla danych wejściowych (np. hasło PEM klucza prywatnego dla polecenia req), druga zaś - danych wyjściowych (np. to samo hasło, ale dla genrsa, jest daną wyjściową). W skryptach testowych, które pisałem korzystałem z plików pomocniczych do których zapisywałem hasła (oczywiście odpowiednio zabezpieczonych).

Generowanie zleceń certyfikacji (CSR) można zautomatyzowac używając opcji -in polecenia req. Trzeba jednak przedtem upewnić się, że zlecenie jest zgodne z parametrami podanymi w sekcji [ req ] odpowiedniego pliku konfiguracyjnego

Sama certyfikacja może być zautomatyzowana przez przekazanie parametru -batch do polecenia ca. Należy jednak przedtem upewnić się, że zlecenie jest zgodne z policy zdefiniowaną dla danego typu certyfikatów oraz (co ważniejsze) czy przypadkiem CN zlecenia nie powiela już istniejącego rekordu w bazie - nieuwzględnienie tego może wprowadzić zamieszanie w bazie certyfikatów.

IV. Funkcje aplikacji

1. Organizacja ekranu

Ekran aplikacji jest podzielony na trzy części w sposób pokazany na rysunku:

Ekran podstawowy

Górna część jest statyczna, zawiera nazwę urzędu certyfikacyjnego, ewentualnie jakiś motyw graficzny. Część lewa to tak naprawdę menu główne programu - zawiera opcje takie, jak podano na rysunku. W prawym okienku wprowadzane są dane, wyświetlane wyniki komend, itp. - szczegółowo omówię to dalej.

2. Dodawanie certyfikatów

Ta procedura jest dość długa i ważna, dlatego opiszę ją tutaj dokładniej, krok po kroku:

  • Po kliknięciu "Nowy certyfikat" użytkownik otrzymuje ekran początkowy umożliwiający wybór typu nowo tworzonego certyfikatu, wyglądający mniej więcej tak (teksty są przykładowe :) , typy certyfikatów - obowiązujące). Co ważne - powinna istnieć możliwość wybrania tylko tych typów certyfikatów, które urząd ma prawo wystawiać. Pozostałe powinny być albo "wyszarzone", albo w ogóle nie wyświetlane.

    Dodawanie - faza 1

  • Następnie w zależności od wybranego typu certyfikatu pojawia się odpowiedni formularz w które wpisywane są dane nowego obiektu. Formularze takie powinny być trzy:

    • Dla certyfikatów klienckich, czyli: email, client, email_client formularz wygląda następująco:

      Dodawanie - faza 2a

      przy czym pola C i L są początkowo ustawiane wartościami domyślnymi równymi zawartości odpowiednich pól w certyfikacie CA. Po wpisaniu identyfikatora, pole e-mail jest domyślnie ustalane jako <identyfikator>@<domena.ca>.

    • Dla certyfikatu serwera SSL formularz jest inny:

      Dodawanie - faza 2b

      Różni sie on w zasadzie tylko interpretacją pól CN, Email, UN - poza tym ma on podobny charakter jak poprzedni.

    • Dla certyfikatów podrzędnych urzędów certyfikacyjnych, czyli emailCA, sslCA, ssl_emailCA wprowadzamy następujące dane:

      Dodawanie - faza 2c

      Przez "skrót nazwy nowego CA" rozumiemy nazwę symboliczną typu ca_staff. Pełna nazwa CA to np. "Urząd certyfikacyjny staffu", zaś nowa "jednostka podrzędna" to nazwa podorganizacji dla której definiujemy CA, np staff_system.

  • Kolejnym krokiem powinno byc sprawdzenie przez system, czy wprowadzone dane nie identyfikują przypadkiem już istniejącego obiektu. Jeżeli tak się dzieje, powinien zostać wyświetlony stosowny komunikat i ponownie drugi formularz.

  • W następnym kroku aplikacja generuje kolejno: parę kluczy (prywatny + publiczny), na ich podstawie CSR (korzystając z danych wpisanych do formularza) i ostatecznie generuje certyfikat. Wszystkie błędy OpenSSL-a powinny być przechwytywane i przekazywane użytkownikowi w rozsądnej postaci.

  • Jeżeli wszystko do tej pory przebiegło bez komplikacji, to prosimy użytkownika o włożenie do stacji dyskietki i zapisujemy na niej klucz+certyfikat użytkownika zapisany w formacie PKCS #12. Następnie kasujemy lokalną kopię klucza prywatnego.

  • Wygenerowany certyfikat umieszczamy w bazie LDAP i (ewentualnie kasujemy jego lokalną kopię w katalogu certs.

3. Przeglądanie certyfikatów

a) Ekran listy certyfikatów

Lista certyfikatów

Ten ekran jest używany we wszystkich kolejnych opcjach. Powinien zawierać przyciski do przechodzenia między stronami, umożliwiać sortowanie listy według nazwy, lub numeru seryjnego (najlepiej przez klikanie na nagłówkach kolumn), wyświetlać tylko podstawowe informacje o certyfikatach (jak na rysunku). Dokładniejsze dane o certyfikacie powinny być dostępne po wybraniu przycisku "Szczegóły".

b) Opcje certyfikatu

Widok szczegółowy

Ekran widoku szczegółowego powinien zawierać wszystkie dane z certyfikatu oraz umożliwiać wykonywanie podstawowych operacji: unieważnianie certyfikatu, wysyłanie wiadomości do obiektu certyfikowanego, przesyłanie certyfikatu na podany adres.

W zależności od typu certyfikatu pewne pola powinny być odnośnikami powodującymi akcje. I tak: pole "E-mail" ma być zawsze odnośnikiem typu mailto. Dla certyfikatów serwerów SSL pole "Nazwa serwera" powinno zawierać link przenoszący nas na stronę domową tego serwera, itp.

c) Przeglądanie całej bazy

Tej opcji (podobnie jak i następnej) nie będę omawiał szczegółówo - jest ona szczególnym przypadkiem punktu e) w którym szukany ciąg jest pusty i skrypt w wyniku wyświetla wszystkie certyfikaty.

d) Przeglądanie CRL

Tak jak poprzednio - CRL to po prostu zapytanie, w którym status==unieważniony.

e) Wyszukiwanie

Po wybraniu tej opcji użytkownik widzi następujący formularz:

Ekran szukania

Może w nim zaznaczyć, w jakich polach system ma szukać tekstu, dopuszczalne typy certyfikatów i przedziały czasowe. Po wybraniu przycisku "Szukaj" system wyszukuje certyfikaty spełniające kryteria i przedstawia je w postaci listy opisanej w punkcie 3a.

4. Status

Ekran statusu

Na tej stronie mają być wyświetlane informacje diagnostyczne i statystyczne systemu widoczne na rysunku. Jesli chodzi o pole "Termin upływu ważności certyfikatu CA" to ma ono charakter raczej pomocniczy/informacyjny. W naszej realizacji CA będą miały klucze o długim okresie ważności (kilka/kilkanaście lat), a ich unieważnianie będzie realizowane w oparciu o CRL.

V. Instalacja

System urzędu certyfikacyjnego będzie instalowany z poziomu shella przy użyciu dostarczonego skryptu. Jedynym plikiem który użytkownik może dodać do instalowanego CA jest jego certyfikat stworzony przez CA wyższego rzędu (jeśli takiego pliku nie będzie, to program instalacyjny ma sam stworzyć odpowiedni certyfikat self-signed.

Skrypt instalacyjny ma wykonywac następujące czynności:

  • Tworzyć strukturę katalogów CA
  • Skopiować klucze CA do certs/ca.crt i private/ca.key.
  • Inicjalizować bazę danych (index.txt, serial).
  • Inicjalizować (tworzyć) bazę LDAP
  • Tworzyć skrypty służące do zarządzania CA (wstawiając do "gotowców" np. katalog domowy, czy rodzaje certyfikatów).
  • Kopiować strony WWW (PHP) odpowiedzialne za wygląd i działanie CA
  • Dodawać odpowiedni link symboliczny w głównym katalogu dokumentów lokalnego serwera WWW (przykładowo CA_UMK może być wtedy dostępne jako: https://www.uni.torun.pl/CA_UMK/. Oczywiście dla stron związanych z modyfikacją baz powinny zostać stworzone odpowiednie pliki .htaccess zapewniające, że tylko uprawnieni użytkownicy będą mieli do nich dostęp.