Digital Certificate Lifecycle Management – podstawy procesu i użyteczne narzędzia

logo6Celem artykułu jest przybliżenie jego czytelnikom idei PKI w sposób maksymalnie pragmatyczny, co oznacza, że będą oni mogli – eksperymentując z kodem załączonego skryptu – praktycznie przećwiczyć przebieg głównych procesów składających się na cykl zarządzania certyfikatami cyfrowymi.

Artykuł obejmuje następujące tematy: zbudowanie prostego serwera certyfikatów, generowanie par kluczy kryptograficznych RSA dla użytkowników końcowych, tworzenie wniosku o certyfikat (CSR – Certificate Signing request) zgodnego ze standardem PKCS#10, podpisywanie CSR oraz bezpieczną dystrybucję certyfikatów i kluczy kryptograficznych w postaci plików o strukturze zgodnej ze standardem PKCS#12 do użytkowników końcowych.

Certificate lifecycle management – podstawy

W tym celu, aby mogło dojść do wystawienia certyfikatu dla użytkownika końcowego musi wcześniej nastąpić:

  • wygenerowanie pary kluczy RSA
  • utworzenie CSR – wniosku o certyfikat

W kryptosystemie klucza publicznego każdy użytkownik, czy też – szerzej rzecz ujmując – każdy podmiot (bo mówimy tutaj także o podmiotach instytucjonalnych) jest wyposażony w co najmniej jedną parę kluczy. Para obejmuje klucz publiczny i klucz prywatny. Pierwszy z nich jest tym, którym inni użytkownicy posługują się, kiedy chcą wysłać nam zaszyfrowaną asymetrycznie wiadomość, drugi – jako nasz pilnie strzeżony sekret – służy wyłącznie nam do odszyfrowywania takich właśnie uprzednio zaszyfrowanych wiadomości.

Idea kryptografii klucza publicznego jest zatem niezwykle prosta – cokolwiek zostanie zaszyfrowane jednym kluczem z pary, może być odszyfrowane wyłącznie kluczem komplementarnym (z dokładnie tej samej, nie innej pary). W naszym interesie jest dystrybuować nasz klucz publiczny do jak najszerszego grona innych użytkowników, którzy są lub będą zainteresowani kryptograficznym zabezpieczeniem wymiany informacji z nami. Jednak niezmiernie rzadko przekazujemy innym nasz klucz publiczny w surowej formie. Przeważnie wcześniej wysyłamy go wraz z dodatkowymi informacjami o nas, jako jego posiadaczu do serwera ośrodka certyfikacyjnego. Postępujemy tak, ponieważ chcemy, by zaufana strona trzecia, czyli właśnie ośrodek certyfikacyjny, potwierdziła autentyczność naszego klucza. Co to oznacza? Otóż to, że zaufana strona trzecia w niezaprzeczalny sposób dokonuje powiązania samego klucza publicznego z informacjami na temat jego właściciela, wcześniej jeszcze „po drodze” – rzecz jasna – tego właściciela uwierzytelniając. Na tym właśnie polega idea certyfikatów cyfrowych, które są niczym innym, tylko podpisaną elektronicznie przez ośrodek certyfikacyjny strukturą składającą się z klucza publicznego oraz atrybutów jednoznacznie wskazujących na jego właściciela. Taka struktura jeszcze bez podpisu elektronicznego ośrodka certyfikacyjnego nosi miano wniosku o certyfikat (Certificate Signing Request opisanego w standardzie PKCS#10).

Wreszcie, kiedy ośrodek certyfikacyjny podpisał już CSR, co oznacza, że wystawił pełnoprawny certyfikat klucza publicznego, pojawia się jeszcze jeden problem. Mianowicie, jeżeli to nie sam użytkownik końcowy wygenerował parę kluczy dla siebie, po czym nie on sam osobiście stworzył i wysłał CSR do ośrodka certyfikacyjnego, a zrobił to w jego imieniu jakiś podmiot pośredniczący, na przykład wspomniany już departament IT w przedsiębiorstwie, wówczas problemem staje się to, jak bezpiecznie dostarczyć w jakiejś łatwej do zainstalowania formie, zarówno sam certyfikat jak i klucz prywatny. Jedno bez drugiego tak naprawdę nie ma bowiem sensu. Przypomnę, że klucz publiczny znajdujący się w treści certyfikatu służy szyfrowaniu informacji wysyłanej do nas, zaś klucz prywatny jest jedynym kluczem, który umożliwia odszyfrowanie wiadomości zaszyfrowanej uprzednio kluczem komplementarnym. Prawdę powiedziawszy, klucz prywatny pełni dodatkowo jeszcze jedną bardzo ważną funkcję. Mianowicie, szyfruje skróty komunikatów, a zaszyfrowany kluczem prywatnym skrót komunikatu, to przecież nic innego, tylko sygnatura cyfrowa czyli podpis elektroniczny – potężny mechanizm weryfikacji autentyczności i integralności komunikatów elektronicznych.

Jeśli więc zachodzi potrzeba, by w celu bezpiecznej dystrybucji „zapakować” certyfikat i klucz prywatny, aby w postaci takiej paczki dostarczyć je użytkownikowi końcowemu, z pomocą przychodzi standard PKCS#12, który definiuje standard takowej paczki.

Podkreślam, że PKCS#12 służy jedynie dostarczeniu certyfikatu i klucza prywatnego jego właścicielowi. Nie może z oczywistych powodów być wykorzystywany do dostarczania naszego certyfikatu cyfrowego innym podmiotom. Tym oczywiście chętnie udostępnimy certyfikat, ale bez naszego sekretu, czyli klucza prywatnego.

Choć dystrybucja certyfikatów w takiej czy innej formie jest częścią cyklu zarządzania certyfikatami, to w tym materiale nie zostanie ona opisana. Dość wspomnieć jedynie, że może ona odbywać się z wykorzystaniem serwerów usług katalogowych lub innych narzędzi.

Podstawowe operacje PKI – demonstracyjne narzędzie skryptowe

Interfejs programu został podzielony na zakładki odpowiadające poszczególnym etapom procesu prowadzącego od wygenerowania pary kluczy do utworzenia paczki obejmującej certyfikat cyfrowy i klucz prywatny zgodnej z PKCS#12.

W pierwszym etapie, od którego zależą kolejne, po nim następujące, generujemy parę kluczy RSA. Przedtem decydujemy, jakich rozmiarów mają być nasze klucze. Obowiązuje zasada, że im większy klucz, tym jest on bezpieczniejszy, ale jednocześnie tym większa złożoność obliczeniowa operacji kryptograficznych dokonywanych z jego użyciem.

pki-01

Rozsądny poziom bezpieczeństwa oferują klucze co najmniej 1024 bitowe, choć zalecane są klucze RSA o długości co najmniej 2048 bitów.

Tak naprawdę, zanim dojdzie do wygenerowania pary kluczy dla użytkownika końcowego program przeprowadza jeszcze jedną ogromnie ważną operację – tworzy i powołuje do życia serwer certyfikatów. Dzieje się to całkowicie transparentnie i jedynym tego śladem dostrzegalnym dla uruchamiającego program jest komunikat, z którego dowiadujemy się, że operacja przebiegła z sukcesem lub z błędem.

pki-02

Jeśli ustanowienie serwera certyfikatów przebiegło pomyślnie, otrzymujemy komunikat w następującej postaci.

Jak widać, w treści komunikatu znajduje się certyfikat naszego testowego ośrodka certyfikacyjnego.

Mając za sobą etap generowania pary kluczy, teraz trzeba zająć się przedłożeniem naszego klucza publicznego wraz z dodatkowymi informacjami o nas jako o właścicielu klucza, do uwierzytelniania przez zaufaną stroną trzecią, czyli przez nasz ośrodek certyfikacyjny. Ośrodek certyfikacyjny podpisze taki wniosek o certyfikat, a ów wniosek w postaci podpisanej przez CA stanie się po prostu pełnoprawnym certyfikatem X.509v3.

Wszystko, czego potrzebujemy na tym etapie, to przygotowanie struktury zgodnej ze standardem PKCS#10, czyli wspomnianego wniosku o wystawienie certyfikatu (CSR – Certificate Signing Request), która obejmuje nasz klucz publiczny i dodatkowe informacje o właścicielu. Staną się one atrybutami certyfikatu cyfrowego.

pki-03

Wniosek możemy zakodować do postaci binaranej (DER – Directory Encoding Rule) lub do postaci znakowej (PEM – Privacy Enhanced Mail) w zależności od wymagań ośrodka certyfikacyjnego. My zdecydowaliśmy się na kodowanie PEM, bo wniosek w postaci znakowej lepiej prezentuje się w okienku dialogowym naszego programu. Dodam, że nasz testowy serwer certyfikatów potrafi bez problemów obsłużyć oba standardy kodowania.

Wniosek o certyfikat wędruje w następnej kolejności do ośrodka certyfikacyjnego. Nasz testowy ośrodek jest wkomponowany w skrypt, więc wspomniana wędrówka jest jedynie symboliczna. W warunkach rzeczywistych, zanim ośrodek certyfikacyjny wystawi nam certyfikat klucza publicznego, kontaktuje się z nami wprost lub pośrednio poprzez tzw. ośrodek rejestracyjny (RA – Registration Authority), prosi o dokumenty, czy nawet wizytę w ośrodku, by uwierzytelnić nas jako właściciela klucza. Chodzi o to, żeby zminimalizować ryzyko, podszycia się oszustów pod legalnego właściciela klucza. Jest to ogromnie ważne, bo bardzo często klucze kryptograficzne są po wystawieniu certyfikatu wykorzystywane do elektronicznego podpisywania wielomilionowych transakcji lub szyfrowania ogromnie wrażliwych informacji.

pki-04

Kiedy mamy już certyfikat i wcześniej wygenerowaną parę kluczy, wówczas bardzo łatwo możemy go sobie zainstalować w systemie. W przykładzie na ilustracji poniżej widać certyfikat zakodowany znakowo w standardzie PEM.

Jeśli jednak klucze kryptograficzne, jak wcześniej wspomniałem, nie były generowane przez użytkownika na jego stacji, a uczynił to w imieniu użytkownika końcowego jakiś podmiot pośredniczący, na przykład departament IT generując pary kluczy dla wszystkich pracowników przedsiębiorstwa, to teraz trzeba dostarczyć użytkownikowi nie tylko sam certyfikat, ale także jego klucz prywatny, bo dopiero taka para ma sens.

pki-05

W tym celu, by móc to uczynić, należy utworzyć „paczkę” obejmującą wspomniane elementy. Trzeba pamiętać, że klucz prywatny to super-sekret każdego właściciela, więc należy go zabezpieczać tak dobrze, jak to tylko możliwe, przez cały czas jego ważności. My, na potrzeby zabezpieczeń na czas transportu, zaszyfrujemy klucz prywatny algorytmem 3DES. Zastosujemy w tym celu szyfrowanie oparte o hasło, zgodne ze standardem PKCS#5.

Kod źródłowy skryptu (język Ruby z wykorzystaniem bibliotek GTK2 i OpenSSL)

require 'gtk2'
require 'openssl'
require 'base64'

def message(title, msg_text)
   dialog = Gtk::MessageDialog.new(
      $main_application_window,
      Gtk::Dialog::MODAL | Gtk::Dialog::DESTROY_WITH_PARENT,
      Gtk::MessageDialog::INFO,
      Gtk::MessageDialog::BUTTONS_OK,
      msg_text
   )
   dialog.title = title
   dialog.run
   dialog.destroy
end

def make_root_ca()
   puts "Please wait... Generating keys and certificate for Root CA Demo Server"
   begin
      $root_key = OpenSSL::PKey::RSA.new 2048
      $root_ca = OpenSSL::X509::Certificate.new
      $root_ca.version = 2
      $root_ca.serial = 1
      $root_ca.subject = OpenSSL::X509::Name.parse "/DC=Worshiper of Reason/DC=Rorshiper of reason/CN=Worshiper of Reason CA"
      $root_ca.issuer = $root_ca.subject # root CA's are "self-signed"
      $root_ca.public_key = $root_key.public_key
      $root_ca.not_before = Time.now
      $root_ca.not_after = $root_ca.not_before + 2 * 365 * 24 * 60 * 60 # 2 years validity
      ef = OpenSSL::X509::ExtensionFactory.new
      ef.subject_certificate = $root_ca
      ef.issuer_certificate = $root_ca
      $root_ca.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
      $root_ca.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
      $root_ca.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
      $root_ca.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
      $root_ca.sign($root_key, OpenSSL::Digest::SHA256.new)
      message("CA CERT", "CA certificate properly set-up:\n#{$root_ca.to_pem}")
   rescue => e
      message("Error", "Problem with CA Server setup")
   end
end

def generate_keys(output_widget, size, name)
   output_widget.buffer.text = "Key size: #{size} for user #{name}"
   begin
      $key = OpenSSL::PKey::RSA.new size
      output_widget.buffer.text += "\nPublic key:\n#{$key.public_key.to_pem}"
      output_widget.buffer.text += "Private key:\n#{$key.to_pem}"
      result = 1
   rescue => e
      message("Error", "Problem: #{e}")
      result = 0
   end
   return result
end

def generate_csr(csr_data) 
   request = OpenSSL::X509::Request.new
   request.version = 0 
   request.subject = OpenSSL::X509::Name.new([
      ['C',             csr_data[:country],         OpenSSL::ASN1::PRINTABLESTRING],
      ['ST',            csr_data[:state],           OpenSSL::ASN1::PRINTABLESTRING],
      ['L',             csr_data[:city],            OpenSSL::ASN1::PRINTABLESTRING],
      ['O',             csr_data[:organization],    OpenSSL::ASN1::UTF8STRING],
      ['OU',            csr_data[:department],      OpenSSL::ASN1::UTF8STRING],
      ['CN',            csr_data[:common_name],     OpenSSL::ASN1::UTF8STRING],
      ['emailAddress',  csr_data[:email],           OpenSSL::ASN1::UTF8STRING]
   ])  
   request.public_key = $key.public_key
   request.sign($key, OpenSSL::Digest::SHA1.new)
   return request
end 
 
def check_csr(request)
   csr = OpenSSL::X509::Request.new request
   rais 'CSR can not be verified' unless csr.verify csr.public_key
end

def sign_csr(request, key, username)
   $cert = OpenSSL::X509::Certificate.new
   $cert.version = 2
   $cert.serial = 2
   $cert.subject = OpenSSL::X509::Name.parse "/DC=#{username}/DC=#{username}/CN=#{username}"
   $cert.issuer = $root_ca.subject # root CA is the issuer
   $cert.public_key = $key.public_key
   $cert.not_before = Time.now
   $cert.not_after = $cert.not_before + 1 * 365 * 24 * 60 * 60 # 1 years validity
   ef = OpenSSL::X509::ExtensionFactory.new
   ef.subject_certificate = $cert
   ef.issuer_certificate = $root_ca
   $cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true))
   $cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
   $cert.sign($root_key, OpenSSL::Digest::SHA256.new)
   return $cert
end

def make_pkcs12(passphrase, username, private_key, certificate)
   pkcs12 = OpenSSL::PKCS12.create(passphrase, username, private_key, certificate)
   encoded = Base64.encode64(pkcs12.to_der)
   $pkcs12 = encoded
   return encoded
end

# -----------

window = Gtk::Window.new(Gtk::Window::TOPLEVEL)
window.set_title  "PKI basic operations demo - Janusz Nawrat (2015)"
window.border_width = 5
window.set_size_request(600, -1)

window.signal_connect('delete_event') { false }
window.signal_connect('destroy') { Gtk.main_quit }
window.signal_connect('delete_event') { Gtk.main_quit }

main_nb = Gtk::Notebook.new
key_label = Gtk::Label.new("Generating RSA keys")
csr_label = Gtk::Label.new("Preparing CSR (PKCS#10)")
cert_label = Gtk::Label.new("Certification Authority")
pkcs12_label = Gtk::Label.new("Cert & key distribution (PKCS#12)")

key_box = Gtk::VBox.new()
csr_box = Gtk::VBox.new()
cert_box = Gtk::VBox.new()
pkcs12_box = Gtk::VBox.new()

# --------- generate RSA key pair ----------

key_table = Gtk::Table.new(2, 2, true)
key_box.add(key_table)

name_label = Gtk::Label.new("User name")
key_size_lb = Gtk::Label.new("Key size")
name_entry = Gtk::Entry.new()

key_size_combo = Gtk::ComboBox.new()
key_size = ["512", "1024", "2048", "4096"]
key_size.each do |size|
   key_size_combo.append_text size 
end
key_size_combo.active = 1

key_size_combo.signal_connect "changed" do
   size = key_size[key_size_combo.active]
end

name_entry.text = "Janusz Nawrat"

key_inout_frame = Gtk::Frame.new(" Output console ")
key_inout_textview = Gtk::TextView.new()
key_inout_textview.set_size_request(-1, 200)
key_inout_textview.border_width = 5
key_inout_scrolled = Gtk::ScrolledWindow.new()
key_inout_scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
key_inout_scrolled.add(key_inout_textview)
key_inout_frame.add(key_inout_scrolled)
font = Pango::FontDescription.new("Courier New 10")
key_inout_textview.modify_font(font)

cancel_key_bt = Gtk::Button.new("Exit")
save_pubkey_bt = Gtk::Button.new("Save public key")
save_privkey_bt = Gtk::Button.new("Save private key")
ok_key_bt = Gtk::Button.new("Generate RSA key pair")

cancel_key_bt.signal_connect("clicked") do
   Gtk.main_quit
end

save_pubkey_bt.signal_connect("clicked") do
   begin
      file_key = File.new("#{name_entry.text.to_s}_pubkey.pem", "w")
      file_key.write($key.public_key.to_pem)
      file_key.close
      message("Success", "RSA public key successfuly saved to file: #{name_entry.text.to_s}_pubkey.pem")
   rescue => e
      message("Error", "Problem with saving RSA public key to file #{name_entry.text.to_s}_pubkey.pem")
   end
end

save_privkey_bt.signal_connect("clicked") do
   begin
      file_key = File.new("#{name_entry.text.to_s}_privkey.pem", "w")
      file_key.write($key.to_pem)
      file_key.close
      message("Success", "RSA private key successfuly saved to file: #{name_entry.text.to_s}_privkey.pem")
   rescue => e
      message("Error", "Problem with saving RSA private key to file #{name_entry.text.to_s}_privkey.pem")
   end
end

ok_key_bt.signal_connect("clicked") do
   result = generate_keys(key_inout_textview, key_size[key_size_combo.active].to_i, name_entry.text)
   if result == 1
      save_pubkey_bt.sensitive = true
      save_privkey_bt.sensitive = true
   end
end

save_pubkey_bt.sensitive = false
save_privkey_bt.sensitive = false

key_table.attach(name_label, 0, 1, 0, 1)
key_table.attach(name_entry, 1, 2, 0, 1)
key_table.attach(key_size_lb, 2, 3, 0, 1)
key_table.attach(key_size_combo, 3, 4, 0, 1)
key_table.attach(key_inout_frame, 0, 4, 1, 10)

key_table.attach(ok_key_bt, 0, 1, 10, 11)
key_table.attach(save_pubkey_bt, 1, 2, 10, 11)
key_table.attach(save_privkey_bt, 2, 3, 10, 11)
key_table.attach(cancel_key_bt, 3, 4, 10, 11)

# ------------- CSR - PKCS#10 -------------

param1_hbox = Gtk::HBox.new(false, 2)
param2_hbox = Gtk::HBox.new(false, 2)

label_country = Gtk::Label.new("Country: ")
label_state = Gtk::Label.new("State: ")
label_city = Gtk::Label.new("City: ")
label_org = Gtk::Label.new("Org: ")
label_dept = Gtk::Label.new("Dept: ")
label_common_name = Gtk::Label.new("Common Name: ")
label_email = Gtk::Label.new("E-mail: ")

entry_country = Gtk::Entry.new(); entry_state = Gtk::Entry.new()
entry_city = Gtk::Entry.new(); entry_org = Gtk::Entry.new()
entry_dept = Gtk::Entry.new(); entry_common_name = Gtk::Entry.new()
entry_email = Gtk::Entry.new()

entry_country.width_chars = 4
entry_state.width_chars = 5
entry_city.width_chars = 10
entry_org.width_chars = 15
entry_dept.width_chars = 15

entry_country.text = "PL"; entry_state.text = "KR"
entry_city.text = "KR"; entry_org.text = "Worshiper_of_Reason"
entry_dept.text = "DEPT"; entry_common_name.text = "Janusz Nawrat"
entry_email.text = "janusz@Worshiper_of_Reason.com"

param1_hbox.pack_start(label_country, false, false, 1); param1_hbox.pack_start(entry_country, true, true, 1)
param1_hbox.pack_start(label_state, false, false, 1); param1_hbox.pack_start(entry_state, true, true, 1)
param1_hbox.pack_start(label_city, false, false, 1); param1_hbox.pack_start(entry_city, true, true, 1)
param1_hbox.pack_start(label_org, false, false, 1); param1_hbox.pack_start(entry_org, true, true, 1)
param1_hbox.pack_start(label_dept, false, false, 1); param1_hbox.pack_start(entry_dept, false, false, 1)
param2_hbox.pack_start(label_common_name, false, false, 1); param2_hbox.pack_start(entry_common_name, true, true, 1)
param2_hbox.pack_start(label_email, false, false, 1); param2_hbox.pack_start(entry_email, true, true, 1)

csr_box.pack_start(param1_hbox, 1, 1, 3); csr_box.pack_start(param2_hbox, 1, 1, 3)

csr_inout_frame = Gtk::Frame.new(" Output console ")
csr_inout_textview = Gtk::TextView.new()
csr_inout_textview.set_size_request(-1, 200)
csr_inout_textview.border_width = 5
csr_inout_scrolled = Gtk::ScrolledWindow.new()
csr_inout_scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
csr_inout_scrolled.add(csr_inout_textview)
csr_inout_frame.add(csr_inout_scrolled)
csr_inout_textview.modify_font(font)

csr_box.pack_start(csr_inout_frame, 1, 1, 2)

button_hbox = Gtk::HBox.new(true, 1)

cancel_csr_bt = Gtk::Button.new("Exit")
save_csr_bt = Gtk::Button.new("Save PKCS#10 (CSR)")
ok_csr_bt = Gtk::Button.new("Generate PKCS#10 (CSR)")

save_csr_bt.sensitive = false

button_hbox.pack_start(ok_csr_bt, 1, 1, 0)
button_hbox.pack_start(save_csr_bt, 1, 1, 0)
button_hbox.pack_start(cancel_csr_bt, 1, 1, 0)

csr_box.pack_start(button_hbox, 1, 1, 2)

cancel_csr_bt.signal_connect("clicked") do
   Gtk.main_quit
end

save_csr_bt.signal_connect("clicked") do
   begin
      file_csr = File.new("#{entry_common_name.text.to_s}_csr.pem", "w")
      file_csr.write($csr)
      file_csr.close
      message("Success", "CSR successfuly saved to file: #{entry_common_name.text.to_s}_csr.pem")
   rescue => e
      message("Error", "Problem with saving CSR to file #{entry_common_name.text.to_s}_csr.pem")
   end
end

ok_csr_bt.signal_connect("clicked") do
   csr_data = { 
      :country      => entry_country.text.to_s,
      :state        => entry_state.text.to_s,
      :city         => entry_city.text.to_s,
      :organization => entry_org.text.to_s,
      :department   => entry_dept.to_s, 
      :common_name  => entry_common_name.text.to_s,
      :email        => entry_email.text.to_s
   }
   if $key != ""
      $csr = generate_csr(csr_data)
      if $csr != ""
         save_csr_bt.sensitive = true
      end
      csr_inout_textview.buffer.text += "PKCS#10 of #{csr_data[:common_name]}:\n#{$csr}"
   else 
      message("Warning", "First generate RSA key pair")
   end
end

# ---------- Certification Authority ---------------
ca_inout_frame = Gtk::Frame.new(" Output console ")
ca_inout_textview = Gtk::TextView.new()
ca_inout_textview.set_size_request(-1, 280)
ca_inout_textview.border_width = 5
ca_inout_scrolled = Gtk::ScrolledWindow.new()
ca_inout_scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
ca_inout_scrolled.add(ca_inout_textview)
ca_inout_frame.add(ca_inout_scrolled)
ca_inout_textview.modify_font(font)

cert_box.pack_start(ca_inout_frame, 1, 1, 2)

ca_button_hbox = Gtk::HBox.new(true, 1)

cancel_ca_bt = Gtk::Button.new("Exit")
save_ca_bt = Gtk::Button.new("Save certificate to file")
ok_ca_bt = Gtk::Button.new("Issue the certificate")

save_ca_bt.sensitive = false

ca_button_hbox.pack_start(ok_ca_bt, 1, 1, 2)
ca_button_hbox.pack_start(save_ca_bt, 1, 1, 2)
ca_button_hbox.pack_start(cancel_ca_bt, 1, 1, 2)

cert_box.pack_start(ca_button_hbox, 1, 1, 2)

cancel_ca_bt.signal_connect("clicked") do
   Gtk.main_quit
end

save_ca_bt.signal_connect("clicked") do
   begin
      file_ca = File.new("#{entry_common_name.text.to_s}_cert.pem", "w")
      file_ca.write($cert)
      file_ca.close
      message("Success", "Certificate successfuly saved to file: #{entry_common_name.text.to_s}_cert.pem")
   rescue => e
      message("Error", "Problem with saving certificate to file #{entry_common_name.text.to_s}_cert.pem")
   end
end

ok_ca_bt.signal_connect("clicked") do
   if $csr != ""
      $cert = sign_csr($csr, $key, "#{entry_common_name.text.to_s}")
   else 
      message("Warning", "First generate PKCS#10 CSR request")
   end
   if $cert != ""
      save_ca_bt.sensitive = true
   end
   ca_inout_textview.buffer.text = "#{$cert}"
end

# ---------- PKCS#12 ------------

pkcs12_param_hbox = Gtk::HBox.new(false, 2)
pkcs12_param_frame = Gtk::Frame.new()
pkcs12_pass_lb = Gtk::Label.new("Password to protect private key: ")
pkcs12_pass_ent = Gtk::Entry.new()
pkcs12_param_frame.add(pkcs12_param_hbox)
pkcs12_param_hbox.pack_start(pkcs12_pass_lb, false, false, 1)
pkcs12_param_hbox.pack_start(pkcs12_pass_ent, true, true, 1)
pkcs12_pass_ent.text = "S3CyouR3!"

pkcs12_box.pack_start(pkcs12_param_frame, true, true, 2)

pkcs12_inout_frame = Gtk::Frame.new(" Output console ")
pkcs12_inout_textview = Gtk::TextView.new()
pkcs12_inout_textview.set_size_request(-1, 250)
pkcs12_inout_textview.border_width = 5
pkcs12_inout_scrolled = Gtk::ScrolledWindow.new()
pkcs12_inout_scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
pkcs12_inout_scrolled.add(pkcs12_inout_textview)
pkcs12_inout_frame.add(pkcs12_inout_scrolled)
pkcs12_inout_textview.modify_font(font)

pkcs12_box.pack_start(pkcs12_inout_frame, 1, 1, 2)

pkcs12_button_hbox = Gtk::HBox.new(true, 1)

cancel_pkcs12_bt = Gtk::Button.new("Exit")
save_pkcs12_bt = Gtk::Button.new("Save PKCS#12 to file")
ok_pkcs12_bt = Gtk::Button.new("Make PKCS#12")

save_pkcs12_bt.sensitive = false

pkcs12_button_hbox.pack_start(ok_pkcs12_bt, 1, 1, 2)
pkcs12_button_hbox.pack_start(save_pkcs12_bt, 1, 1, 2)
pkcs12_button_hbox.pack_start(cancel_pkcs12_bt, 1, 1, 2)

pkcs12_box.pack_start(pkcs12_button_hbox, 1, 1, 2)

cancel_pkcs12_bt.signal_connect("clicked") do
   Gtk.main_quit
end

save_pkcs12_bt.signal_connect("clicked") do
   begin
      file_pkcs12 = File.new("#{entry_common_name.text.to_s}.p12", "w")
      file_pkcs12.write(Base64.decode64($pkcs12))
      file_pkcs12.close
      message("Success", "PKCS#12 successfuly saved to file: #{entry_common_name.text.to_s}.p12")
   rescue => e
      message("Error", "Problem with saving PKCS#12 to file #{entry_common_name.text.to_s}.p12")
   end
end

ok_pkcs12_bt.signal_connect("clicked") do
   if $cert != ""
      $pkcs12 = make_pkcs12(pkcs12_pass_ent.text.to_s, entry_common_name.text.to_s, $key, $cert)
      if $pkcs12 != ""
         save_pkcs12_bt.sensitive = true
      end
      pkcs12_inout_textview.buffer.text = "PKCS#12 (Base64 encoded):\n#{$pkcs12}"
   else 
      message("Warning", "First enroll certificate")
   end
end

# --------------

$root_key = "" # CA's RSA key pair
$root_ca = ""  # CA's self signed certificate
$key = ""      # end-user RCA key pair
$csr = ""      # end-user certificate signing request (PKCS#10 file)
$cert = ""     # end-user X.509v3 certificate
$pkcs12 = ""   # end-user cert + private key (PKCS#12 file)

make_root_ca()

main_nb.append_page(key_box, key_label)
main_nb.append_page(csr_box, csr_label)
main_nb.append_page(cert_box, cert_label)
main_nb.append_page(pkcs12_box, pkcs12_label)

window.add(main_nb)
window.show_all
window.set_window_position :center
Gtk.main

Informacje Janusz Nawrat
Just ordinary man who likes thinking...

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

TOMASZ WEŁNA

artysta grafik | wykładowca

PRACOWNIA OKO

Szkoła Rysunku Malarstwa i Grafiki DR TOMASZA WEŁNY | KRAKÓW | Plac Matejki 10 | tel 691 81 75 74

Piękno neurobiologii

Blog Jerzego Vetulaniego

Teoria muzyki, zasady muzyki, podstawy muzyki

Teoria muzyki, zasady muzyki, podstawy muzyki - czyli to co każdy amator muzyki wiedzieć powinien :)

Personal Development & Inspirations

Przemyślenia i refleksje, którymi warto się podzielić (blog by Janusz Nawrat)

Business IT Cooperation Platform

Biznes i IT - dwa światy, które muszą współdziałać

%d bloggers like this: