Il programma HTTPsServer è molto simile al precedente HTTPServer, fatta eccezzione per il fatto che risulta in grado di instaurare, con il Browser Client, una connessione sicura secondo il protocollo SSL v.3 .

HTTPsServer.java:

import java.net.*;
import java.io.*;
import java.util.*;
import java.lang.*;
import java.util.*;

import java.security.*;
import java.security.cert.X509Certificate;

import iaik.security.ssl.*;
import iaik.asn1.structures.Name;

import com.entrust.security.provider.*;
import com.entrust.toolkit.*;
import com.entrust.util.*;
import com.entrust.x509.directory.*;

public class HTTPsServer {
static final String NAME = "HTTPsServer";
static final String VERSION = "1.0";
ServerSConfiguration configs = new ServerSConfiguration();
LoggerS loggers = new LoggerS();

/* MAIN */

// Crea un istanza di HTTPServer e richiama il metodo Run della stessa
  public static void main(String args[]) {

HTTPsServer server = new HTTPsServer();
if(args.length > 0) server.processCommandLine(args);
server.run();
  }

   public HTTPsServer() {

super();   }

// Valutazione dei parametri passati nella linea di comando
  public void processCommandLine(String[] args) {

for(int i=0;i < args.length;++i) { if(args[i].equals("-CONFIG")) { if(i+1 < args.length) configs.processConfigurationFile(args[i+1]); else System.out.println("Configuration file argument is missing.");
break;
}
}
String logFile = configs.getLogFile();
if(logFile!="") loggers = new LoggerS(logFile,configs.echoToConsole());
  }

/* Visualizzazione versione del Server */
  public void displayVersionInfo(){

System.out.println("HTTPsServer version "+VERSION);   }

// Si inizializzano l'Entrust Toolkit e il JCE,
// si controlla attraverso l'Entrust Manager se il proprio certificato è ancora valido e in
// caso affermativo si effettua il logon, si impostano gli algoritmi crittografici e le chiavi
// dopo di che si crea un nuovo ServerSocket, si assegna il socket alla variabile server,
// si esegue un ciclo infinito nel quale si rimane in attesa dell'arrivo di una connessione,//
si crea un'istanza socket per gestirla

  public void run() {

BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

displayVersionInfo(); // Versione del Server
configs.display();// Caratteristiche del Server

// Inizializzazione ciphers.
com.entrust.util.Util.initCiphers();

EntrustProfile entrustProfile = new EntrustProfile();

entrustProfile.setPKIXVersion(EntrustProfile.PKIXforEntrust3);

try {

String filename="WebAndrea.epf";
String password="SnorkMuffin";

entrustProfile.logon( new FileInputStream(filename), new StringBuffer(password));

if ( entrustProfile.randomSeedRequired() ) { System.out.println( "The profile " + filename + " requires a valid random seed.\nUse the ProfileRandomSeed program to add a seed to your profile." );
System.exit( 1 );
}
} catch (Exception e) { e.printStackTrace();
System.out.println("Logon failed.");
}

System.out.println("EntrustProfile done.");

SSLServerContext sslServerContext = new SSLServerContext();

// Si accettano solo questi ciphers forti
CipherSuite [] suites = {

CipherSuite.SSL_RSA_WITH_3DES_EDE_CBC_SHA,
CipherSuite.SSL_RSA_WITH_RC4_SHA,
CipherSuite.SSL_RSA_WITH_RC4_MD5
};

sslServerContext.setEnabledCipherSuites( suites );

try {

System.out.println("Enter the IP address of the directory: ");

String addressDir = stdIn.readLine();

JNDIDirectory directory = new JNDIDirectory( addressDir, 389);
directory.connect();

ETKCertificateVerifier verifier =
new ETKCertificateVerifier( directory, entrustProfile );

sslServerContext.setTrustDecider(verifier);

} catch (Exception ex) { ex.printStackTrace(); }

System.out.println("ETKCertificateVerifier done.");

try {

// Set up del certificato RSA.
X509Certificate[] certchain=new X509Certificate[2];
certchain[0]= entrustProfile.getEncryptionCertificate();
certchain[1]= entrustProfile.getCaCertificate();
sslServerContext.setRSACertificate(certchain,entrustProfile.getDecryptionKey());

// Si genera un coppia di chiavi RSA temporanea.
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512,Util.secureRandom());
sslServerContext.setRSATempKeyPair(kpg.generateKeyPair());
// Si abilitano le suite cipher valide.
CipherSuite[] enabledCS = serverContext.updateCipherSuites();

} catch (Exception ex) { System.out.println("Unable to set RSA server certificate.");
System.out.println("RSA cipher-suites can not be used.");
}

byte[] types = { ClientTrustDecider.rsa_sign, };
Name[] cas=null;

cas = new Name[1];

cas[0]=Util.getSubject(entrustProfile.getCaCertificate());
sslServerContext.setRequireClientCertificate(types,cas);

try {

SSLServerSocket server = new SSLServerSocket(configs.getServerPort(), sslServerContext);
SSLSocket clients = null;
int localPort = server.getLocalPort();
loggers.datedLog(NAME+" is listening on port "+localPort+".");
do { // Si attende la connesione di un client clients = (SSLSocket) server.accept();
// Ricevuta la richiesta si apre per il servizio un nuovo ServerThread che estende la classe Thread
(new HTTPsServerThread(clients,configs,loggers)).start();
} while(true);
} catch(IOException ex) { loggers.datedLog("Unable to listen on "+configs.getServerPort()+".");
System.exit(0);
}
  }
}

class HTTPsServerThread extends Thread {
SSLSocket clients;
ServerSConfiguration configs;
LoggerS loggers;

   public HTTPsServerThread(SSLSocket clients,ServerSConfiguration configs, LoggerS loggers) {

this.clients = (SSLSocket) clients;
this.configs = configs;
this.loggers = loggers;
  }

// Corpo del Thread

  public void run() {

try { // Descrive il tipo di connessione instaurato con il cliente describeConnection(clients);
// Si creano oggetti delle classi HTTPOutputStream e HTTPInputStream per comunicare col Client. I flussi sono memorizzati in buffer per mogliorare le prestazioni di I/O
HTTPsOutputStream outStream = new HTTPsOutputStream(new BufferedOutputStream(clients.getOutputStream()));
HTTPsInputStream inStream = new HTTPsInputStream(clients.getInputStream());
// Cattura le richieste HTTP di input
HTTPsRequest request = inStream.getRequest();
request.logs(loggers);
if(request.isGetRequest()) { String response = request.prepareResponse();
String ext = request.getExtName((ServerSConfiguration) configs);
// Se il file trasmesso è un archivio ".jar", comunica al Browser di non trattenerlo poiché nella Cache ha validità per 0 sec.
if (ext.equals("jar")) response +="Expire : 0 \n";
outStream.println(response);
outStream.println();
loggers.datedLog("Send msg: "+ response);
processGetRequest(request,outStream);
}
loggers.datedLog("Request completed. Closing connection.");
}catch(IOException ex) { loggers.datedLog("IOException occured when processing request."); }
try { clients.close(); }catch(IOException ex) { loggers.datedLog("IOException occured when closing SSLSocket."); }
  }

  void describeConnection(SSLSocket clients) {

String destName = clients.getInetAddress().getHostName();
String destAddr = clients.getInetAddress().getHostAddress();
int destPort = clients.getPort();
loggers.datedLog("Accepted connection to "+destName+" ("
+destAddr+")"+" on port "+destPort+".");
  }

  void processGetRequest(HTTPsRequest request,HTTPsOutputStream outStream) throws IOException {

String fileName = request.getFileName(configs);
File file = new File(fileName);
if(file.exists()) { String fullPath = file.getCanonicalPath();
if(inServerRoot(fullPath)) { int len = (int) file.length();
sendFile(outStream,file);
}else loggers.datedLog("File is not in server root.");
}else loggers.datedLog("File "+file.getCanonicalPath()+" does not exist.");
  }

   public boolean inServerRoot(String fileName) {

String serverRoot = configs.getServerRoot();
int fileLength = fileName.length();
int rootLength = serverRoot.length();
if(fileLength < rootLength) return false;
if(serverRoot.equals(fileName.substring(0,rootLength))) return true;
return false;
  }

  void sendFile(HTTPsOutputStream out,File file) {

try { DataInputStream in = new DataInputStream(new FileInputStream(file));
int len = (int) file.length();
byte buffer[] = new byte[len];
in.readFully(buffer);
in.close();
for(int i=0;i < len;++i) out.write(buffer[i]);
out.flush();
out.close();
loggers.datedLog("File sent: "+file.getCanonicalPath());
loggers.logs("Number of bytes: "+len);
}catch(Exception ex) { loggers.datedLog("Error retrieving "+file); }
  }
}

class HTTPsInputStream extends FilterInputStream {
  public HTTPsInputStream(InputStream in) {

super(in);   }

  public String readLine() throws IOException {

StringBuffer result=new StringBuffer();
boolean finished = false;
boolean cr = false;
do { int ch = -1;
ch = read();
if(ch==-1) return result.toString();
result.append((char) ch);
if(cr && ch==10){ result.setLength(result.length()-2);
return result.toString();
}
if(ch==13) cr = true;
else cr=false;
} while (!finished);
return result.toString();
  }

  public HTTPsRequest getRequest() throws IOException {

HTTPsRequest request = new HTTPsRequest();
String line;
do { line = readLine();
if(line.length() > 0) request.addLine(line);
else break;
}while(true);
return request;
  }
}

class HTTPsOutputStream extends FilterOutputStream {
  public HTTPsOutputStream(OutputStream out) {

super(out);   }

  public void println() throws IOException {

write(13);
write(10);
  }

  public void println(String s) throws IOException {

for(int i=0;i < s.length();++i) write(s.charAt(i));
println();
  }
}

class HTTPsRequest {
  Vector lines = new Vector();

  public HTTPsRequest() {
  }

  public void addLine(String line) {

lines.addElement(line);   }

  boolean isGetRequest() {

if(lines.size() > 0) { String firstLine = (String) lines.elementAt(0);
if(firstLine.length() > 0) if(firstLine.substring(0,3).equalsIgnoreCase("GET"))
return true;
}
return false;
  }

  String getFileName(ServerSConfiguration configs) {

if(lines.size() > 0) { String firstLine = (String) lines.elementAt(0);
String fileName = firstLine.substring(firstLine.indexOf(" ")+1);
int n = fileName.indexOf(" ");
if(n!=-1) fileName = fileName.substring(0,n);
try { if(fileName.charAt(0) == '/') fileName = fileName.substring(1); } catch(StringIndexOutOfBoundsException ex) {}
if(fileName.equals("")) fileName = configs.getDefaultFile();
if(fileName.charAt(fileName.length()-1)=='/') fileName+=configs.getDefaultFile(); return configs.getServerRoot()+fileName;
}else return "";
  }

  String getExtName(ServerSConfiguration configs) {

if(lines.size() > 0) { String firstLine = (String) lines.elementAt(0);
String extName = firstLine.substring(firstLine.indexOf(" ")+1);
int n = extName.indexOf(" ");
if(n!=-1) extName = extName.substring(0,n);
try { if(extName.charAt(0) == '/') extName = extName.substring(1); } catch(StringIndexOutOfBoundsException ex) {}
if(extName.equals("")) extName = configs.getDefaultFile();
if(extName.charAt(extName.length()-1)=='/') extName+=configs.getDefaultFile(); n = extName.indexOf(".")+1;
extName = extName.substring(n,extName.length());
return extName;
}else return "";
  }

  String prepareResponse() {

String lineOut="HTTP/";
for (int i=0;i < lines.size();++i) { if (i==0) { String line = (String) lines.elementAt(0);
int n = line.indexOf("1");
line=line.substring(n,line.length());
lineOut+=line;
}
}
// Ritorna lo Stato del Server
lineOut+=" 200 \n";
// Ritorna di altri eventuali parametri
lineOut+="Cache-Control : no-cache \n";
lineOut+="Cache-Control : private \n";
return lineOut;
  }

  void logs(LoggerS loggers) {

loggers.datedLog("Received the following request:");
for(int i=0;i < lines.size();++i) loggers.logs((String) lines.elementAt(i)); }
  }

// Questa classe si occupa della configurazione del Server Web

class ServerSConfiguration {
static final char CONFIG_COMMENT_CHAR = '#';
int serverPort = 443;
String serverRoot = "C:\\Inetpub\\WwwRoot\\";
String defaultFile = "Default.html";
String logFile = "";
boolean echoLogToConsole = true;

   public ServerSConfiguration() {
  }

  public char getCommentChar() {

return CONFIG_COMMENT_CHAR;   }

  public int getServerPort() {

return serverPort;   }

  public String getServerRoot() {

return serverRoot;   }

  public String getDefaultFile() {

return defaultFile;   }

  public String getLogFile() {

return logFile;   }

  public boolean echoToConsole() {

return echoLogToConsole;   }

  public void display() {

System.out.println(" serverPort: "+serverPort);
System.out.println(" serverRoot: "+serverRoot);
System.out.println(" defaultFile: "+defaultFile);
System.out.println(" logFile: "+logFile);
System.out.println(" echoLogToConsole: "+echoLogToConsole);
  }

  public void processConfigurationFile(String fname) {

try { File file = new File(fname);
if(file.exists()) { BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line=reader.readLine())!=null) processConfigurationLine(line); reader.close();
}
}catch(Exception ex) { System.out.println("Unable to process configuration file."); }
  }

  public void processConfigurationLine(String line) throws NumberFormatException {

line = removeLeadingWhiteSpace(line);
if(line.length()==0) return;
int n;
int n1 = line.indexOf(' ');
int n2 = line.indexOf('\t');
if(n1 == -1) n = n2;
else if(n2 == -1) n = n1;
else if(n1 < n2) n = n1;
else n = n2;
if(n==-1 || n==line.length()-1) return;
String param = line.substring(0,n);
String value = line.substring(n+1);
if(param.equals("serverPort")) serverPort = (new Integer(value)).intValue(); else if(param.equals("serverRoot")){ serverRoot = value;
if(!serverRoot.equals("")){ char ch = serverRoot.charAt(serverRoot.length()-1);
if(ch!='/' && ch!='\\') serverRoot+="/";
}
}else if(param.equals("defaultFile")) defaultFile = value; else if(param.equals("logFile")) logFile = value; else if(param.equals("echoLogToConsole")) echoLogToConsole = (new Boolean(value)).booleanValue();
  }

  String removeLeadingWhiteSpace(String line) {

boolean finished = false;
do { if(line.length()==0) return "";
char ch = line.charAt(0);
if(ch==CONFIG_COMMENT_CHAR) return "";
if(ch!=' ' && ch!='\t') return line;
line=line.substring(1);
} while (!finished);
return "";
  }

}

// Questa classe si occupa della registrazione delle operazioni effettuate. // La registrazione può essere effettuata su console o su file.

class LoggerS {
public String logFile;
public boolean echoLogToConsole = true;
public BufferedWriter writer = null;

  public LoggerS() {
  }

  public LoggerS(String fname, boolean echo) {

logFile = fname;
echoLogToConsole = echo;
try { writer = new BufferedWriter(new FileWriter(fname,true)); }catch(IOException ex){}
  }

  void logMsg(String msg) {

if(writer!=null) { try { writer.write(msg);
writer.newLine();
writer.flush();
}catch(IOException ex){}
}
if(echoLogToConsole) System.out.println(msg);
  }

   public synchronized void logs(String msg) {

logMsg(" "+msg);    }

  public synchronized void datedLog(String msg) {

logMsg((new Date()).toString()+" "+msg);   }
}

b6.gif - 3872 Bytes