Podpisywanie plików za pomocą kluczy SSH
Napisał: Patryk Krawaczyński
09/05/2023 w Administracja, Bezpieczeństwo Brak komentarzy. (artykuł nr 858, ilość słów: 610)
O
podpisywaniu commitów przez SSH już wiemy. Ale czy wiesz, że możesz użyć polecenia ssh-keygen
do podpisywania i weryfikowania podpisów na dowolnych danych, takich jak pliki w wypuszczane wersje oprogramowania? Funkcja ta została dodana wraz w wersją OpenSSH 8.0, dlatego jeśli używasz Debian Bullseye / Ubuntu 20.04 lub nowsze – masz już zainstalowaną wystarczająco nową wersję SSH, aby korzystać z tej funkcjonalności. W dodatku jeśli korzystasz z serwisu GitHub lub jakiejkolwiek innej usługi, która używa kluczy SSH do uwierzytelniania to pewnie masz już klucz SSH, którego można użyć do generowania podpisów (jeśli nie to zajmiemy się tym później). Dystrybucja kluczy SSH jest łatwa, ponieważ publiczne klucze SSH to krótkimi jednowierszowymi ciągami, które łatwo skopiować. W dodatku możemy użyć wspomnianego serwisu GitHub jako dystrybutora kluczy – możesz pobrać klucze publiczne SSH dla dowolnego użytkownika odwiedzając adres URL w postaci: https://github.com/$nazwa_użytkownika.keys np. NFsec.
Podpisywanie pliku jest proste. Pierwszym krokiem jest wygenerowanie klucza:
ssh-keygen -o -a 200 -t ed25519 -C "codesign@nfsec.pl"
Opcjonalnie możemy teraz dodać nasz klucz publiczny znajdujący się w ścieżce: /home/$USER/.ssh/codesign.pub do konta Github. Posiadając już klucz możemy podpisać dowolny plik:
ssh-keygen -Y sign -f ~/.ssh/codesign -n file secretfile.txt
- ~/.ssh/codesign to ścieżka do naszego prywatnego klucza Ed25519.
- file to przestrzeń nazw (ang. namespace), które opisuje cel podpisu – np. SSH standardowo definiuje dwie przestrzenie: file do podpisywania plików ogólnych i email do podpisywania wiadomości e-mail. Git używa git do swoich podpisów. Jeśli używamy podpisywania do innych celów, jak niestandardowy protokół, musimy określić własną przestrzeń nazw. Zapobiega to atakom międzyprotokołowym, w których prawidłowy podpis jest usuwany z wiadomości dla jednego protokołu i dołączany do wiadomości z innego protokołu. Jeśli protokołu nie używają odrębnych przestrzeni nazw dla swoich podpisów, istnieje ryzyko, że podpis zostanie uznany za ważny przez drugi protokół, mimo że był przeznaczony dla pierwszego protokołu. W przypadku zastosowań niestandardowych zaleca się używanie nazw zgodnych ze wzorcem
NAMESPACE@YOUR.DOMAIN
w celu generowania jednoznacznych przestrzeni nazw np.reverseshell@nfsec.pl
. - secretfile.txt jest ścieżką do pliku, który chcemy podpisać.
Podpis jest zapisywany w nowym pliku o nazwie $plik.sig, który wygląda tak:
Signing file secretfile.txt Write signature to secretfile.txt.sig agresor@darkstar:~$ cat secretfile.txt.sig -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgrRbF7gwmUXSgP3m6oi7rbXwh9R Q3wNr7AzoLylRwXI8AAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx OQAAAEDONLNxj7EoF0N6Fmt7H6KwQtGEld1YKA5aQgZv2PtXtTD7uNo26IlU+7wAEDL4DS CCgwYGO3ZKr+cvRQecP4QD -----END SSH SIGNATURE-----
Jeśli określimy “-” dla nazwy pliku to plik do podpisania jest odczytywany ze standardowego wejścia (stdin), a podpis jest zapisywany do standardowego wyjścia:
agresor@darkstar:~$ ssh-keygen -Y sign -f ~/.ssh/codesign -n file - < topsecret.txt Signing data on standard input -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgrRbF7gwmUXSgP3m6oi7rbXwh9R Q3wNr7AzoLylRwXI8AAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx OQAAAEAvy8gpEf/4R4lgFPE90Lzkl2asbbBMhZ7BUQe7UJF5eDF1mHgMtbpDIZyuIYAdrA F5KQapdjT01fYa2QdoAvQM -----END SSH SIGNATURE-----
Weryfikacja podpisów:
Weryfikacja podpisów jest trochę bardziej skomplikowana niż sam proces ich tworzenia. Na początku musimy utworzyć plik dozwolonych sygnatariuszy, w którym będziemy umieszczać klucze publiczne i adresy e-mail, na przykład:
agresor@darkstar:~$ cat .ssh/allowed_signers codesign@nfsec.pl ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0Wxe4MJlF0oD95uqIu6218IfUUN8Da+wM6C8
Po utworzeniu pliku dozwolonych sygnatariuszy, których podpisy chcemy sprawdzać weryfikacja przebiega w następujący sposób:
ssh-keygen -Y verify -f ~/.ssh/allowed_signers -I codesign@nfsec.pl -n file \ -s secretfile.txt.sig < secretfile.txt
- allowed_signers jest ścieżką do pliku z dozwolonymi sygnatariuszami.
- codesign@nfsec.pl jest adresem e-mail osoby, która rzekomo podpisała plik - po nim następuje wyszukiwanie klucza publicznego w pliku allowed_signers.
- file jest typem przestrzeni nazw, która musi być zgodna z przestrzenią nazw użytą do podpisania.
- secretfile.txt.sig jest ścieżką do pliku z podpisem.
- secretfile.txt jest ścieżką do pliku, który został podpisany i ma zostać zweryfikowany.
Jeśli podpis jest prawidłowy, polecenie zakończy działanie kodem 0 i wyświetli komunikat podobny do tego:
Good "file" signature for codesign@nfsec.pl with ED25519 key SHA256:eQ7Wr247GN4rjEnRmSP09Ibe
W przeciwnym razie polecenie zakończy działanie z kodem niezerowym i wyświetli komunikat o błędzie.
Więcej informacji: Upgrade Your SSH Key to Ed25519, Switching from an RSA SSH Key to Ed25519 on Ubuntu 22.04, It's Now Possible To Sign Arbitrary Data With Your SSH Keys