sziasztok,
a cél, hogy egy webszerveren olyan kliens-tanúsitványokat tudjak létrehozni, melyek a kliensoldalon böngészőbe telepítve alkalmasak a kliens autentikálására szerveroldalon az adott website-hoz. sajnos kezdő vagyok a témában, nem kizárt, hogy akár alapvető dolgokat rosszul gondolok.
a szerveren (Ubuntu 20.04) certbot hozza létre a Let's Encrypt tanúsítványt és kulcsokat az adott vhost számára. ezzel a cert-tel és privát kulccsal próbálom létrehozni a client cert-et, de jelenleg az így generált cert-et nem fogadja el a szerver érvényes tanúsítványnak. aktuális kód-állapottól függően kétféle hibaüzenetet kapok:
Certificate Verification: Error (19): self signed certificate in certificate chain
Certificate Verification: Error (20): unable to get local issuer certificate
sajnos nem tiszta, mitől függ, mikor melyiket kapom. próbálkoztam self signed cert-tel is LE előtt, de a 19-es hiba is LE cert által generált client cert-re jött. a cert telepítve van MacOS Keychain Access-be, fel is ugrik a browser ablak, ki is tudom választani, akkor jön az ERR_BAD_SSL_CLIENT_AUTH_CERT.
a releváns kódrészletek:
$this->cert = openssl_x509_read("file://$cert_path");
$this->privkey = openssl_pkey_get_private("file://$privkey_path");
openssl_pkcs12_export($this->cert, $client_cert, $this->privkey, $pass, ["friendly_name" => $name]);
az így létrejött .p12 file-t telepítem a böngészőbe. kérdéseim:
- érdemes-e php openssl függvényekkel kísérletezni, vagy jobban járok curl-lel, esetleg exec(openssl)-lel. nem generálnék szerver oldalon cert file-t, ha nem muszáj, ezért tetszene a tisztán php megoldás.
- elképzelhető, hogy bármilyen openssl-lel generált cert self signed-nak minősül, és ez a gond?
- mit gondolok rosszul, mit csinálok rosszul, hogyan csináljam jól?
- hol találok érthető, jól használható leírást és példát erre?
köszönöm
Hozzászólások
Amit a Let's Encrypt-től kapsz tanúsítványt a weboldalad számára, az egy kiszolgálói tanúsítvány, nem CA, így azzal további tanúsítványokat nem tudsz aláírni. Ez a vonal teljesen felejtős.
Amit tehetsz, hogy csinálsz egy saját, self singned CA-t, és azzal írsz alá egy tanúsítványt a webszerver részére és a klienseknek is egyet-egyet, szintén a saját CA-val aláírva. Ekkor a Te általad készített CA-nak be kell kerülnie minden kliens CA tárolójába, hogy megbízzanak benne (az ilyen CA-val aláírt webszerverben), és a webszerverre is fel kell kerülnie a CA-nak és az általa aláírt webszerver cert-nek, hogy megbízzon a kliensek által bemutatott tanúsítványban.
Az, hogy meg tudod-e, meg lehet-e oldani, hogy a webszerver a nagyvilág felé a Let's Encrypt tanúsítványt mutassa (amit minden böngésző elfogad a Te saját CA-d nélkül is), de megbízzon a kliensek által bemutatott, saját CA által aláírt tanúsítványban, azt fejből nem tudom megmondani, utána kell olvasnod.
Mindettől függetlenül az nem jó gyakorlat, hogy a webszerver állítja ki a tanúsítványt a kliens közreműködése nélkül, mert ez nem biztosnágos. A normál eljárás, hogy a kliens generál magának privát kulcsot, azzal aláír egy CSR-t (certificate singing request), ezt a CSR-t megkapja a saját CA-d, és ha megfelel a tartalma a kritériumaidnak, akkor aláírja, és visszaküldi a certet a kliens részére valami módon. Így az igazi védelmet adó privát kulcs csak a kliensen létezik, nem utazik védtelenül a neten.
Alternatívaként megcsinálhatod, hogy mégis Te állítod ki a kliensek cert-jét privát kulcsostól, de akkor ki kell alakítanod egy biztoságos csatornát, ahol a privát kulcs eljut a kliensig... Ha nem így teszel, akkor kb. mit sem ér az egész.
Egyébként a kérdéseid alapján keress rá a PKI kulcsszóra, és olvass el minél töb leírást, hogyan is működik egy saját PKI rendszer.
Ezen felül szerintem több hasznos választ fogsz kapni, ha leírod, mi a konkrét elérendő cél azzal, hogy a kliens is hitelesíti magát (pontosabban a futtató gép jelen leírásod alapján) a webszerver felé?
köszönöm, sokat segítettél az elmélet megértésében.
amit a kiállítás módjának biztonságosságáról írsz, azt értem, de nem szeretném nagyon megbonyolítani a folyamatot a kliens userek számára, mert jellemzően laikusok, nem tudnak privát kulcsot generálni, csr-t aláírni stb. a cél nem elsősorban az extrém biztonság megteremtése, inkább kényelmi funkciónak szánom, hogy konfigurálni lehessen a belépési módot: user - pass / cert / választható / mindkettő. azt a kockázatot bevállalom, hogy harmadik fél elcsípi a szerverről letöltött kliens cert-et, és kinyeri belőle a privát kulcsot.
azt jól értem, hogy elképzelhetőnek tartod, hogy két különböző cert-et tud használni a webszerver (apache) a https kommunikációhoz és a kliens cert autentikációhoz? mert enélkül nem megoldható, amit szeretnék, csak ha a self signed-dal futtatom a vhost-ot, azt meg nem szeretném.
https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslcacertificatefile
https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslcertificatechainf…
Két külön helyen adod meg a saját certed és a CA-ig vezető certeket és azt, hogy kitől fogadsz el kliens tanúsítványt.
BlackY
"Gyakran hasznos ugyanis, ha számlálni tudjuk, hányszor futott le már egy végtelenciklus." (haroldking)
Saját CA egyszerű kezelésre érdemes kipróbálni az XCA-t.
https://www.hohnstaedt.de/xca/ -- X - Certificate and Key management
--
Légy derűs, tégy mindent örömmel!
en anno belefutottam ebbe
https://bugs.chromium.org/p/chromium/issues/detail?id=911653
neked aztan fura humorod van...
Én csak minden reklám nélkül ezt ajánlanám elolvasásra, áttekintésre első körben: https://e-szigno.hu/tudasbazis/nagy-e-szigno-konyv.html
+1000
Ezt nem ismertem, király, köszi a linket!
Tehát ha jól értem, szeretnél client cert-eket kreálni a usereknek úgy, hogy közben az oldal zöld marad és nincs hiszti a kliens böngészőkből, igaz?
Let's encript-el nem próbáltam még ilyet, de sima digicert-es cert-el simán. Sőt volt olyan is, hogy applikációknak generáltunk így real time cert-eket php api-n keresztül.
Nincs most előttem a kód, de ha a fenti módi kell neked, akkor holnap szívesen előkeresem.
valaszd kulon - van A szerver auth, aztan TE megmondhatod h ezen belul milyen certet kersz esetlegesen adott pathra felmutatni ....
összefoglalom, hol tartok most:
- elméletben és gyakorlatban is szétválasztottam a server auth-t és a client auth-t, LE kikerült a képből (köszi ggallo)
- bekonfiguráltam külön a self signed cert-et client auth-hoz, server auth-hoz maradt a LE (köszi SzBlackY)
- továbbra sem sikerül php-ból használható root/client certet generálni, de XCA-val sikerült (köszi kila)
van tehát most egy működő megoldásom. maradék kérdések, problémák:
- hogyan tudok php-ből erre alkalmas self signed root certet és client certeket generálni?
- Chrome-ban, Brave-ben tökéletesen működik, Safariban nem, dobja az SSL kapcsolatot, talán a self signed cert miatt, nem túl bőbeszédű.
ha még ezekben tudtok segíteni, azt köszi.
1) openssl for dummies - csinalsz egy CA-t, megcsinalod a kliens certeket, alairod, odaadod a kliensnek. importalja, boldog.
2) elvileg ennek nem lenne hozza koze, mert TE a szerver oldalon csak annyit kersz, hogy "hoci, mutass egy cert- et." - erre a kliens megmondja a fingerprintjet meg h ki irta neki ala - ezt TE ellenorzod, hogy aki alairta neki abban megbizol -e (es milyen melysegben)
köszi a segítséget.
1. pontosan így járok el, a végeredmény mégsem jó. létrejön a CA cert és a privkey, de a kliens cert-ek létrehozásakor vagy a cert nem jó, vagy a privkey, vagy a kettő nem korrelál egymással. elég sokat olvastam tegnap a témában, elég különböző leírásokkal találkoztam, pl. https://www.php.net/manual/en/function.openssl-pkcs12-export.php:
de ez sem segített. úgy tűnik, ennyire azért nem triviális a folyamat.
2. számomra nem ez derült ki, hanem azt kérem szerveroldalon, hogy "hoci, mutass egy cert-et, amit azzal a cert-tel írtak alá, ami nekem itt meg van adva a konfigurációmban.". amíg ilyet nem tud felmutatni, nincs további kommunikáció a klienssel, csak BAD_SSL_AUTH_CERT_ERROR, és a backend (php jelen esetben) meg sem kapja a client cert paramétereit. a Safari issue-val amúgy tele a net, pl.:
https://support.secureauth.com/hc/en-us/articles/360035348611-Client-Ce…
https://www.jeffgeerling.com/blog/2018/fixing-safaris-cant-establish-se…
a client cert érvényessége nem hosszabb 13 hónapnál, nem ez a probléma.
Vagy nem jól írod, vagy nem jól csinálod. CA certet (és hozzá tartozó privát kulcsot) csak egyetlen egyszer kell (jellemzően kézzel) csinálni, és utána azt használod az összes "normál" cert aláírásához. Nem kell CA certet generálni újra és újra. Szerintem azt kellene csinálnod, hogy CSR-t generálsz a kliens részére, és aláíratod a már meglévő self-signed CA-ddal.
openssl_pkey_new() - új privát kulcs generálása a kliensnek
openssl_csr_new() - új CSR generálása, ehhez az előbbi pkey kell
openssl_csr_sign() - új cert előállítása a CSR-ből, ehhez az előző CSR kell, meg a CA cert-je és a CA privát kulcsa
Ha ez megvan, akkor az első lépésben készült pkey-t és az utolsó lépésben előállt certet kell a kliensnek átadnod (esetleg openssl_pkcs12_export()-tal előállítasz a kettőből egy állományt).
nem jól írtam akkor, mert pontosan így csinálom. CA cert-et csak egyszer, ezekkel a fv-ekkel, ebben a sorrendben. létre is jön a cert és a pkey. aztán amikor openssl_pkcs12_export()-tal létre akarok hozni egy kliens .p12-t, akkor az export hibával megáll, hogy a cert nem cert, vagy a pkey nem pkey, vagy a kettő nem passzol egymáshoz, aszerint hogy épp mit variálok a kódban kínomban. mutatom is:
a client CSR signnel kozod nincs a client privat keyhez, csak a CSRhez... ott a CAddal irod ala, nem sajat magaval - esetleg a cert usage attributumokat megnezheted meg h mit rak be alapbol (mihez fogja hasznalni a certet a kliens)
egy kivétellel sikerült mindent megoldanom, a tanulságokat itthagyom, hátha hasznos másnak is:
- a kliens tanúsítványok nem úgy jönnek létre, ahogy először próbáltam, hogy a CA cert-et exportálom ki PKCS12-be, hanem csinálok egy új tanúsítványt, amit a CA-val írok alá, és azt exportálom. (szóltam, hogy kezdő vagyok!)
- php-ban egy openssl cert-nek 4 féle formátuma lehet:
1. PEM enkódolt szöveg változóban
2. PEM enkódolt szöveg file-ban
3. php resource
4. php object instance (>php 8.0)
ezeket nem szerencsés keverni, és értelemszerűen mindet másképp kell beolvasni.
- SHA1 digest algoritmusra több böngésző hibaüzenettel eldobja a kapcsolatot, de csak a szerver logból derült ki, hogy túl gyenge így a titkosítás. SHA256 már elég.
- MacOS-en a telepített kliens tanúsítványt mindenképpen trusted-ra kell állítani, addig nem ajánlja fel a böngészőnek, hogy választhassa.
és itt el is érkeztünk a megoldatlan problémához: Safari nem hajlandó tanúsítványt választani, fel se ugrik az ablak. gyanús, hogy a self signed CA cert az oka. chromium alapú böngészőkben (Chrome, Brave) hibátlanul megy, mással még nem próbáltam. tudtok erre bármilyen megoldást? illetve ha az ügyfélnek van vásárolt tanúsítványa (pl. RapidSSL), akkor kapott hozzá CA cert-et is, ami megoldhatná ezt a problémát? vagy csak EV-hez és OV-hez, az alaphoz nem kap?
Safariban biztos, hogy mukodik a vasarolt cert maganak a webservernek es a self signed ca-val alairt kliens cert. Mindenfele trusted meg egyeb allitgatasa nelkul. Openssl command line generaltam a ca-t, a kliens keyt, a csr-t es szinten openssl segitsegevel irtam ala a csr-t a ca-val. Majd a vegeredmenyt p12-re konvertalva az egeszet behuztam a keychainbe. A safari felajanlja a certvalasztast es siman mukodik.
ez érdekes, mert nálam trusted-ra állítás nélkül egyik böngészőnek sem ajánlja fel ("meg egyéb állítgatása" nincs). meg a leírások is mind ezt állítják, hogy ez szükséges, pl.:
https://support.securly.com/hc/en-us/articles/206058318-How-to-install-…-
https://support.apple.com/hu-hu/guide/server/apd2474fbab/mac
https://docs.vmware.com/en/Horizon-FLEX/1.12/com.vmware.horizon.flex.ad…
úgyanúgy jártam el én is, ahogyan te (bár nem sok részletet írtál), az egyetlen különbség látszólag annyi, hogy én command line helyett php-ből generálok, de lévén ugyanazt az openssl lib-et használja mindkettő, nem kéne eltérő kimenetet produkálniuk.
a server auth cert-nek (SSLCertificateFile) onnantól, hogy SSLCACertificateFile-lal adom meg a client auth-hoz használandó CA cert-et, szerintem nincs köze, de nálam ez amúgy Let's Encrypt.
van tipped, mit kéne tennem, hogy működjön mindenféle trusted meg egyéb állítgatása nélkül, Safariban is? elég részletesen leírtam minden körülményt, de ha mégsem, pótolom.
MacOS Big Sur Version 11.4 (20F71), Safari Version 14.1.1 (16611.2.7.1.4), PHP Version 7.4.3, OpenSSL 1.1.1f 31 Mar 2020
Nalam a kliens tanusitvanyhoz tartozo root CA nincs benne a keychainben, csak a kliens tanusitvany es a hozza kapcsolodo kulcs. A kulcs is megvan nalad? Tehat a keychainben siman ki tudod "nyitni" es latud a certificate alatt a private keyt is? Nalam, mivel a CA nincs benne, igy az nem is trusted (emiatt irja is pirossal, hogy az XYZROOT nem trusted). Maganak a kliens certnek a "Trust" szekcion belul pedig a "When using this certificate" beallitasnal az "Use System Defaults" opcio van kivalasztva, az osszes tobbi alopcional pedg a "no value specified". A webserverem nginx, ahol sima server oldali SSL-re vonatkozo opciokon kivul, csak ezek vannak benn:
Nalam a kliens tanusitvanyhoz tartozo root CA nincs benne a keychainben, csak a kliens tanusitvany es a hozza kapcsolodo kulcs. A kulcs is megvan nalad? Tehat a keychainben siman ki tudod "nyitni" es latud a certificate alatt a private keyt is? Nalam, mivel a CA nincs benne, igy az nem is trusted (emiatt irja is pirossal, hogy az XYZROOT nem trusted). Maganak a kliens certnek a "Trust" szekcion belul pedig a "When using this certificate" beallitasnal az "Use System Defaults" opcio van kivalasztva, az osszes tobbi alopcional pedg a "no value specified". A webserverem nginx, ahol sima server oldali SSL-re vonatkozo opciokon kivul, csak ezek vannak benn:
a ca igy:
a kliens cert pedig igy:
Big Sur itt is (jelenleg mar 11.5/20G71, de pont igy megy 10.5 ota), a Safari pedig jelenleg 14.1.2 (de pont igy ment az 5.0-val is), az OpenSSL pedig macportsbol jott, jelenleg eppen 1.1.1k verzio. Most ezeket a dolgokat ujra kiprobaltam neked es minden ugyonigy mukodik.
köszi. nálam sincs a root CA a keychain-ben, csak a kliens tanúsítvány és a hozzá kapcsolódó kulcs. tehát ki tudom nyitni és látom, hozzáférést is tudok adni itt a Safari-nak, de az sem oldja meg a problémát (a többi böngésző megtalálja a kulcsot a keychain-ben, és kér hozzáférést, azokat sem kell itt külön hozzáadni).
nálam apache van:
arra gyanakszom, hogy valamelyik paraméter nem elég szigorú a Safarinak, csak erről semmilyen részletet nem árul el. elsőre most az tűnt fel, hogy a te kulcsod 4096 bites, az enyém 2048 bites. kipróbálom, hátha ez a gond.