Budapesti Műszaki és Gazdaságtudományi Egyetem Rendszerfejlesztés Java környezetben JSSE Készítette: Erdei Márk 1
Bevezetés JSSE (Java Secure Socket Extension) 1.2, 1.3-as Java-ban opcionális csomag, 1.4-től a J2SE platform része titkos, biztonságos összeköttetést tesz lehetővé (confidentiality, integrity, autheticity) az SSL, TLS és PKI szabványok felhasználásával az API-n kívül ingyenes megvalósítást is tartalmaz (nincs szükség harmadik fél által készített implementációra) (pl. RSA-tól licenc-szelt, egyébként fizetős technológiákat) illeszkedik a meglevő APIkhoz (java.net, java.security,...), nincs redundáns implementáció A javax.net, javax.net.ssl és a javax.security.cert csomagokban található 2
SSL TLS (1) A TCP és az alkalmazási réteg között helyezkedik el Vég-vég titkosítás A Netscape 1994-ben fejlesztette ki az SSL-t (Secure Sockets Layer), az IETF átvette és TLS-re (Transport Layer Security) nevezte át Célja: hitelesítés / authenticity (ki van a túloldalon) bizalmasság / confidentiality (harmadik fél hallja a kommunikációt) integritás védelem / integrity (ha harmadik fél módosítja az átküldött adatot, akkor az kimutatható legyen) a hitelesítés és a titkosítás (bizalmasság) opcionális nem biztosít letagadhatatlanságot, de megoldható (digitális aláírás) 3
SSL TLS (2) Az SSL a három fő szolgáltatását az alábbi technológiákkal valósítja meg: hitelesítés PKI (Public Key Infrastructure) (CA, CA root) titkosítás titkos kulccsal (session key), amit kulcs-csere protokollal beszél meg a két fél integritás védelem digitális aláírással (message digest lekódolva a titkos kulccsal) (ha nem mindenki tanulta, röviden összefoglalni) 4
PKI Minden fél rendelkezik egy titkos és egy publikus kulccsal, amit egy CA (Certificate Authority) ad ki számára. A publikus kulccsal azonosítja magát a kommunikáló fél. A publikus kulcs mellé más adatokat is felvéve, azokat együtt aláírja a CA a titkos kulcsával, ez a Certificate. A CA garantálja, hogy a tanúsítvány a konkrét természetes vagy jogi személyhez tartozik. A CA-kat magasabb szintű CA-k hitelesítik, legfelül áll a CA root. Egy Certificate csak a teljes hitelesítési lánccal (egészen a CA root-ig) érvényes A CA root-ok halmaza minden felhasználónál megvan (pl. VeriSign) 5
Certificate Egy X.509 Certificate (ITU standard) tartalma: Issuer : a tanúsítványt kiadó CA Period of validity : meddig érvényes a tanúsítvány Subject : a kommunikáló fél, akihez a tanusítvány tartozik Subject s public key : a tanúsítvány birtokosának publikus kulcsa Signature : a tanúsítványról készült digitális aláírás (hash aláírva a CA titkos kulcsával) 6
Az SSL handshake fázisai cipher suite megbeszélése (cipher suite: a felhasznált kriptográfiai protokollok együttese) a mindkét oldalon rendelkezésre álló cipher suite-ok közül a legerősebbet választják ki authentikáció (csak szerver, kliens és szerver vagy egyik sem) certificate felhasználásával session key egyeztetése (kulccsere protokollal) titkos kommunikáció csomagonként integritás védelem (MAC) 7
Cipher suites Teljes szintű szolgáltatás (CIA): SSL_RSA_WITH_RC4_128_MD5 SSL_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_AES_128_CBC_SHA... Titkosítás nélkül: SSL_RSA_WITH_NULL_MD5 SSL_RSA_WITH_NULL_SHA... Hitelesítés nélkül SSL_DH_anon_WITH_RC4_128_MD5 TLS_DH_anon_WITH_AES_128_CBC_SHA SSL_DH_anon_WITH_3DES_EDE_CBC_SHA 8
KeyManagerFactory Architektúra TrustManagerFactory titkos kulcsok kezelése KeyManager a kapcsolat paramétereit reprezentálja SSLContext TrustManager publikus kulcsok, és hitelesítési láncok ellenőrzése SSLSocketFactory SSLServerSocketFactory SSLServerSocket accept SSLSocket SSLSocket SSLSession 9
Kapcsolat felépítése (1) Ahogy az SSL handshake leírásánál látható volt, a két fél elsőként a cipher suite-ot beszéli meg. Az SSLSocket-nél állítható be, az a suite-készlet, amit az SSL felhasználhat a handshake során. A getsupportedciphersuites() metódussal kérhető le, hogy az implementáció mely suite-okat támogatja. A setenabledciphersuites() metódussal állítható be, hogy milyen cipher suiteokat engedélyezünk. Legegyszerűbb eset: anonymous connection nincs szükség tanúsítványokra nem kell beállítani sem a KeyStore-t, sem a TrustStore-t van titkosítás és integritásvédelem, viszont nincs hitelesítés 10
Példa: anonymous connecion (szerver) SSLServerSocket serversocket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(SERVER_PORT); serversocket.setenabledciphersuites( new String[] {"SSL_DH_anon_WITH_RC4_128_MD5"}); // az anonymous alapértelmezetten nem engedélyezett!!! SSLSocket s = (SSLSocket) serversocket.accept(); BufferedReader in = new BufferedReader( new InputStreamReader(s.getInputStream())); PrintWriter out = new PrintWriter(s.getOutputStream()); out.println("hello itt a szerver!"); out.flush(); System.out.println("\nCurrent cipher suite:"+s.getsession().getciphersuite()); System.out.println("Current protocol:"+s.getsession().getprotocol()); System.out.println("\nA kliens uzenete:"+in.readline()); serversocket.close(); 11
Példa: anonymous connecion (kliens) SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(InetAddress.getLocalHost(), SERVER_PORT); server.setenabledciphersuites( new String[] {"SSL_DH_anon_WITH_RC4_128_MD5"}); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream()); out.println("hello itt a kliens!"); out.flush(); System.out.println("\nA szerver uzenete:"+in.readline()); serversocket.close(); 12
Kapcsolat felépítése (2) Bonyolultabb eset: hitelesített szerver a kliens megvizsgálja a szerver tanúsítványát, hogy biztos legyen benne, valóban vele kommunikál a szerver nem azonosítja a klienst van titkosítás és integritásvédelem, de csak a szerver kilétében lehetünk biztosak ehhez már kezelnünk kell a tanúsítványokat, és a titkos kulcsokat 13
KeyStore Titkos kulcsok és tanúsítványok tárolására egyaránt alkalmas objektum A tanúsítványokhoz bárki hozzáférhet, a titkos kulcsok jelszóval védettek A JSSE két féle KeyStore implementációt tartalmaz: JKS: Java KeyStore, a JSSE saját kulcstárolási formátuma írni és olvasni is tudja PKCS#12: az RSA Data Security Inc. által kidolgozott kulcs és tanúsítványtárolási formátum (PKCS: Public Key Criptography Standards) csak olvasni tudja CA-k általában ilyen formátumban adják ki a tanúsítványokat (lehet még PKCS#7, de abból készíthető PKCS#12) 14
KeyManager, TrustManager A KeyManager a titkos kulcsokat kezeli. A TrustManager a másik féltől kapott tanúsítvány hitelességét ellenőrzi. A JSSE-ben PKI X.509 elvű implementáció áll rendelkezésre, de az API lehetővé teszi más implementációk kezelését is. Elsőnek a megfelelő factory osztályt kell létrehozni, a statikus getinstance() metódussal, ahol meg kell adni a felhasznált kulcskezelő algoritmust (a default implementáció esetén ez SunX509 ) Mindkét esetben inicializálni kell a factory-kat egy KeyStore-ral, amiben a felhasznált titkos kulcsok, ill. azon CA root-ok tanúsítványai vannak, akikben megbízunk Végül a getkeymanagers() és a gettrustmanagers() metódusokkal kérhetjük el a kulcsokhoz / tanúsítványokhoz tartozó manager példányokat 15
SSL Context Szükség van egy SSLContext létrehozására, ami az egész folyamatot koordinálja. Az SSLContext statikus getinstance() metódusával hozhatunk létre egy példányt, ahol meg kell adni a használandó protokollt (SSL vagy TLS, melyik verzió) Az SSLContext példányát inicializálni kell a konkrét összeköttetésnek megfelelően Mi(k) az én titkos kulcsom (kulcsaim) (KeyManager(-ek)) Kit (kiket) fogadok el a kapcsolat túloldalán (TrustManager(-ek)) Továbbá megadható egy SecureRandom véletlenszámgenerátor, de ha null-t adunk át, akkor a default lesz (megfelel) Az SSLContext-től lekérhetők a SSLSocketFactory és az SSLServerSocketFactory példányok, innentől... 16
Példa: server authentication connection (szerver) SSLContext c = SSLContext.getInstance("SSLv3"); KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream("test-cert.pfx"),KEYSTORE_PASSWORD); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks,keystore_password); c.init(kmf.getkeymanagers(),null,null); // a szerver titkos kulcsa SSLServerSocket serversocket = (SSLServerSocket) c.getserversocketfactory().createserversocket(server_port); serversocket.setenabledciphersuites(new String[] {"SSL_RSA_WITH_RC4_128_MD5"}); SSLSocket s = (SSLSocket) serversocket.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); PrintWriter out = new PrintWriter(s.getOutputStream()); out.println("hello itt a szerver!"); out.flush(); System.out.println("A kliens uzenete:"+in.readline()); 17
Példa: server authentication connection (kliens) SSLContext c = SSLContext.getInstance("SSLv3"); KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream("test-cert.pfx"),KEYSTORE_PASSWORD); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks); c.init(null,tmf.gettrustmanagers(),null); SSLSocket socket = (SSLSocket) c.getsocketfactory().createsocket(inetaddress.getlocalhost(), SERVER_PORT); socket.setenabledciphersuites(new String[] {"SSL_RSA_WITH_RC4_128_MD5"}); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream()); out.println("hello itt a kliens!"); out.flush(); System.out.println("A szerver uzenete:"+in.readline()); 18
Kapcsolat felépítése (3) Legbonyolultabb eset: hitelesített szerver, hitelesített kliens a kliens megvizsgálja a szerver tanúsítványát, hogy biztos legyen benne, valóban vele kommunikál a szerver megvizsgálja a kliens tanúsítványát, hogy biztos legyen benne, valóban vele kommunikál van titkosítás és integritásvédelem, a szerver és a kliens kilétében lehetünk biztosak kezelnünk kell a tanúsítványokat, és a titkos kulcsokat teljes, szimmetrikus biztonság nagy biztonságot igénylő rendszereknél a kliens azonosítását a szerver szerepet játszó SSLSocket setneedclientauth(true)metódussal lehet kérni 19
Példa: both authenticated connection (szerver) SSLContext c = SSLContext.getInstance("SSLv3"); KeyStore ks1 = KeyStore.getInstance("PKCS12"); ks1.load(new FileInputStream("test-cert.pfx"),KEYSTORE_PASSWORD); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks1,keystore_password); KeyStore ks2 = KeyStore.getInstance("PKCS12"); ks2.load(new FileInputStream("test-cert2.pfx"),KEYSTORE_PASSWORD); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks2); c.init(kmf.getkeymanagers(),tmf.gettrustmanagers(),null); SSLServerSocket serversocket = (SSLServerSocket) c.getserversocketfactory().createserversocket(server_port); serversocket.setenabledciphersuites(new String[] {"SSL_RSA_WITH_RC4_128_MD5"}); serversocket.setneedclientauth(true); // setwantclientauth -> only request! SSLSocket s = (SSLSocket) serversocket.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); PrintWriter out = new PrintWriter(s.getOutputStream()); out.println("hello itt a szerver!"); out.flush(); System.out.println("A kliens uzenete:"+in.readline()); 20
Példa: both authenticated connection (kliens) SSLContext c = SSLContext.getInstance("SSLv3"); KeyStore ks1 = KeyStore.getInstance("PKCS12"); ks1.load(new FileInputStream("test-cert2.pfx"),KEYSTORE_PASSWORD); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks1,keystore_password); KeyStore ks2 = KeyStore.getInstance("PKCS12"); ks2.load(new FileInputStream("test-cert.pfx"),KEYSTORE_PASSWORD); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks2); c.init(kmf.getkeymanagers(),tmf.gettrustmanagers(),null); SSLSocket socket = (SSLSocket) c.getsocketfactory().createsocket(inetaddress.getlocalhost(),server_port); socket.setenabledciphersuites(new String[] {"SSL_RSA_WITH_RC4_128_MD5"}); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream()); out.println("hello itt a kliens!"); out.flush(); System.out.println("A szerver uzenete:"+in.readline()); 21
Tanúsítványok előállítása (keytool) (1) Tanúsítványok, titkos kulcsok létrehozhatók és kezelhetők a J2SE-ben található keytool eszközzel. Pl. tanúsítvány adatainak kilistázása keytool list v keystore ksfile storepass passwd Ha a keytoollal hozunk létre tanúsítványt vagy titkos kulcsot, akkor az JKS típusú keystore-ba kerül. CA-któl igényelhető teszt tanúsítvány kifejezetten fejlesztési / tesztelési célra (pl. MávInformatika, NetLock, VeriSign). A CA-k a teszt tanúsítványt és a hozzá tartozó titkos kulcsot általában PKCS#12 (esetleg PKCS#7) keystore formátumban adják. Ezt a keytool csak olvasni tudja (csak a PKCS#12-őt). 22
Tanúsítványok előállítása (keytool) (2) A CA-któl kapott (PKCS#12) fájlok vagy.p12 vagy.pfx kiterjesztésűek. A Java csak a.pfx fájlokat tudja kezelni. A.p12 fájlok pl. webbrowser segítségével átkonvertálhatók.pfx formátumúvá (be kell importálni, majd exportálni) A CA-k keystore-okat adnak ki, amik tartalmazzák a tanúsítványt és a titkos kulcsot is. Ebből kinyerhető csak a tanúsítvány is. Ez egy.cer fájlba menthető. 23
System property alapú működés (1) A KeyManagerFactory és a TrustManagerFactory nem csak programból tölthető fel, hanem megadhatók System property-kel azok a keystore fájlok, amiket a KeyManagerFactory-k és TrustManagerFactory-k betöltenek. Ha ezek a property-k sincsenek beállítva, akkor a default útvonalon keresi a keystore-okat. TrustStore megadása: javax.net.ssl.truststore System property-vel. A jelszót a javax.net.ssl.truststorepassword property-vel lehet megadni. Ha nincs megadva TrustStore vagy a megadott file nem létezik, akkor a <javahome>/lib/security/jssecacerts default TrustStore kerül felhasználásra. 24
System property alapú működés (2) Ha az imént megadott file sem létezik, akkor pedig a <java-home>/lib/security/cacerts fájlt próbálja meg betölteni a JSSE. Ha nem tud betölteni TrustStore-t, akkor csak anonymous kommunikáció lehetséges. A TrustStore-hoz hasonlóan, a KeyStore betöltéséhez is az alábbi paraméterek szükségesek: javax.net.ssl.keystore javax.net.ssl.keystorepassword Ha ezek nincsenek beállítva, akkor a KeyStoreFactory a default KeyStore-t hozza létre, ami üres. (Értelemszerűen, default KeyStore-fájlok nem létezhetnek.) 25
System property alapú működés (3) Hasonlóképpen a KeyStore és TrustStore fájlok tárolási formátuma is System property-vel adható meg: javax.net.ssl.keystoretype javax.net.ssl.truststoretype Ezek lehetnek JKS vagy PKCS12 értékűek (case insensitive) SunJSSE (default) implementáció használata esetén. 26
Factory design pattern előnye Az SSLSocket a java.net.socket leszármazottja, tehát minden program ami Socket alapon működik tud működni SSLSocket alapon is. A hálózati kommunikáción alapuló programokat úgy kell megtervezni, hogy a socket példányaikat ne saját maguk hozzák létre, hanem egy factory osztályból kapják. A socket-ek fajtája a factory osztály lecserélésével változtatható, a programra nincs semmilyen hatással. A hagyományos socket-ek lecserélhetők pl. tömörítést végző, vagy titkosított socket-ekre. Ezen kívül a felparaméterezés is egy helyen változtatható (pl. keep alive, stb.) 27
Példa: secure RMI connection (1) Az RMI-t is a factory design pattern szem előtt tartásával tervezték. Az RMI, a felhasznált socketeket egy factory osztálytól kapja a hagyományos socket-ek lecserélhetők SSLSocket-ekre, így a távoli metódushívás is titkossá, biztonságossá tehető. Mint ismeretes RMI szerver objektum a java.rmi.server.unicastremoteobject-ből való leszármaztatással hozható létre. A UnicastRemoteObject konstruktorában megadható a port, ahol várja a hívásokat (eddig csak ezt a konstruktort használtuk). Van egy másik konstruktora is, ahol átveszi a server socket és a socket factory osztályokat is. Itt kell átadnunk olyan implementációt, ami SSLSocket-eket hoz létre és paraméterez fel. 28
Példa: secure RMI connection (2) RMI socket factory-k megvalósításához a RMIServerSocketFactory RMIClientSocketFactory interfészeket kell megvalósítani. Az előbbi csak egy ServerSocket createserversocket(int port) metódust, Az utóbbi, csak egy Socket createsocket(string host, int port) metódust tartalmaz. Tehát csak ezeket kell úgy elkészíteni, hogy SSLServerSocket és SSLSocket objektumokat adjanak vissza. 29