From 7aa442d7df1e206902158c7e48371f1e53fdc692 Mon Sep 17 00:00:00 2001 From: Denis Arrivault Date: Tue, 31 Jan 2017 18:20:49 +0100 Subject: [PATCH] Adding RestSecure features --- .gitignore | 8 +- .gitlab-ci.yml | 50 +- .travis.yml | 11 + build.gradle | 12 +- src/main/java/controller/Application.java | 14 +- .../java/controller/CASingingRequest.java | 31 ++ src/main/java/controller/CryptCommander.java | 22 + src/main/java/controller/Items.java | 2 +- src/main/java/controller/Users.java | 30 +- .../api/certificate/CertificateGenerator.java | 60 +++ .../impl/certificate/X509V3Generator.java | 448 ++++++++++++++++++ .../java/crypt/utils/BigIntegerRandom.java | 3 - src/main/java/protocol/impl/sigma/Utils.java | 2 - src/main/java/rest/impl/JettyRestServer.java | 193 +++++++- src/main/js/html/index.html | 23 +- src/main/js/main-electron.js | 24 +- src/main/js/modules/app.js | 2 +- src/main/js/modules/users.js | 20 +- src/main/ressources/jetty-logging.properties | 5 + src/main/ressources/log4j2.xml | 17 + src/test/java/controller/ControllerTest.java | 144 ++++-- .../impl/certificate/X509V3GeneratorTest.java | 177 +++++++ src/test/java/util/TestUtils.java | 89 +++- src/test/java/util/TrustModifier.java | 86 ++++ 24 files changed, 1337 insertions(+), 136 deletions(-) create mode 100644 .travis.yml create mode 100644 src/main/java/controller/CASingingRequest.java create mode 100644 src/main/java/controller/CryptCommander.java create mode 100644 src/main/java/crypt/api/certificate/CertificateGenerator.java create mode 100644 src/main/java/crypt/impl/certificate/X509V3Generator.java create mode 100644 src/main/ressources/jetty-logging.properties create mode 100644 src/main/ressources/log4j2.xml create mode 100644 src/test/java/crypt/impl/certificate/X509V3GeneratorTest.java create mode 100644 src/test/java/util/TrustModifier.java diff --git a/.gitignore b/.gitignore index 2c2dbadf..a3475fc4 100644 --- a/.gitignore +++ b/.gitignore @@ -15,9 +15,11 @@ SXPManager.xml /bootstrap.xml /build/ .peer* -.db-8081/* +.db* src/main/javascript/client/SXP* -derby.system.home /logs/ -derby.log /simpleDb/ +src/main/js/SXP-linux-x64/ +src/main/js/node_modules/ +certConfig.conf +keystore.jks diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b7f695b9..43a17f4c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,19 +2,59 @@ stages: - build - test -test: +# caching per branch +# To avoid to dl gradle each time +cache: + key: "$CI_BUILD_REF_NAME" + paths: + - .gradle + - build + - config.properties + +# caching apt +# To avoid to dl everything each time +cache: + key: "apt-cache" + paths: + - apt-cache + +before_script: + - export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR + - apt-get update -yq && apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y openjdk-8-jdk git + +# Main build +build: + stage: build image: ubuntu:16.04 tags: - docker script: - - "apt-get update" - - "apt-get -y install openjdk-8-jdk" - ./gradlew assemble - - ./gradlew check + + + # Tests +tests: + stage: test + image: ubuntu:16.04 + tags: + - docker + dependencies: + - build + script: - ./gradlew test - - "cat build/reports/jacoco/test/html/index.html" + artifacts: + paths: + # Tests coverage report + - build/reports/jacoco/merge/html/index.html + # Unit test result + - build/reports/tests/test/index.html + expire_in: 8d + except: + - master + #selenium: +# stage: test # image: selenium/standalone-firefox # tags: # - docker diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..3aefa740 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: java + +before_install: + - sudo apt-get update -qq + - sudo apt-get install default-jdk + +script: ./gradlew test + +branches: + only: + - master diff --git a/build.gradle b/build.gradle index f3d62038..e24e491d 100644 --- a/build.gradle +++ b/build.gradle @@ -113,12 +113,15 @@ tasks.withType(Test) { } dependencies { + compile 'org.eclipse.jetty:jetty-webapp:9.3.13.M0' compile 'org.hibernate:hibernate-validator:5.2.4.Final' compile 'org.apache.logging.log4j:log4j-api:2.1' compile 'org.apache.logging.log4j:log4j-core:2.1' compile 'org.apache.logging.log4j:log4j-1.2-api:2.1' compile 'org.apache.logging.log4j:log4j-web:2.5' + compile 'org.eclipse.jetty:jetty-util:9.2' + compile 'org.apache.commons:commons-collections4:4.0' compile 'org.eclipse.jetty:jetty-server:9.2.3.v20140905' @@ -137,6 +140,7 @@ dependencies { compile 'org.jdom:jdom2:2.0.6' compile fileTree(dir: './libs', include: '*.jar') compile 'com.google.guava:guava:19.0' + compile 'org.shredzone.acme4j:acme4j-utils:0.8' compile 'com.fasterxml.jackson.core:jackson-databind:2.6.3' testCompile 'org.apache.commons:commons-lang3:3.1' testCompile fileTree(dir: './libs', include: 'loremipsum-1.0.jar') @@ -145,7 +149,10 @@ dependencies { testCompile group: 'org.json', name: 'json', version: '20160810' seleniumCompile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.0.1' } - +configurations.all { + exclude group: "log4j", module: "log4j" + } + [compileJava, compileTestJava]*.options.collect {options -> options.encoding = 'UTF-8'} @@ -167,4 +174,5 @@ task libs(type: Sync) { build.finalizedBy(libs) //Define jacoco report tasks -test.finalizedBy(jacocoTestReport) \ No newline at end of file +test.finalizedBy(jacocoTestReport) + diff --git a/src/main/java/controller/Application.java b/src/main/java/controller/Application.java index 119b560e..e6bf8585 100644 --- a/src/main/java/controller/Application.java +++ b/src/main/java/controller/Application.java @@ -9,6 +9,8 @@ import rest.factories.AuthentifierFactory; import rest.factories.RestServerFactory; +import crypt.impl.certificate.X509V3Generator; + /** * Main class * {@link Application} is a singleton @@ -19,24 +21,24 @@ public class Application { private static Application instance = null; private Peer peer; private Authentifier auth; - + public Application() { if(instance != null) { throw new RuntimeException("Application can be instanciate only once !"); } instance = this; } - + public static Application getInstance() { return instance; } - + public void run() { setPeer(PeerFactory.createDefaultAndStartPeer()); setAuth(AuthentifierFactory.createDefaultAuthentifier()); RestServerFactory.createAndStartDefaultRestServer(8080); //start the rest api } - + public void runForTests(int restPort) { Properties p = System.getProperties(); p.put("derby.system.home", "./.db-" + restPort + "/"); @@ -45,11 +47,11 @@ public void runForTests(int restPort) { setAuth(AuthentifierFactory.createDefaultAuthentifier()); RestServerFactory.createAndStartDefaultRestServer(restPort); } - + public static void main(String[] args) { new Application(); Application.getInstance().runForTests(8081); - + } public Peer getPeer() { diff --git a/src/main/java/controller/CASingingRequest.java b/src/main/java/controller/CASingingRequest.java new file mode 100644 index 00000000..61aeed0b --- /dev/null +++ b/src/main/java/controller/CASingingRequest.java @@ -0,0 +1,31 @@ +package controller; + +import javax.ws.rs.GET; //REST-related dependencies +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +import rest.api.ServletPath; + +@ServletPath("/.well-know/acme-challenge/*") +@Path("/") +public class CASingingRequest { + @GET + @Path("/{input}") + public String hash(@PathParam("input") String input) throws Exception + { + //Send the file for the CA. (let's encrypt) + File file = new File("." + input); + if( file.exists() ) + { + String res = new String(Files.readAllBytes(file.toPath())); + return res; + } + else + return "404 not found"; + } +} diff --git a/src/main/java/controller/CryptCommander.java b/src/main/java/controller/CryptCommander.java new file mode 100644 index 00000000..dcd5b898 --- /dev/null +++ b/src/main/java/controller/CryptCommander.java @@ -0,0 +1,22 @@ +package controller; + +import javax.ws.rs.GET; //REST-related dependencies +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import crypt.api.hashs.Hasher; //module to test dependencies +import crypt.factories.HasherFactory; +import rest.api.ServletPath; + +@ServletPath("/command/hash/*") //url path. PREFIX WITH COMMAND/ !!! +@Path("/") +public class CryptCommander { + @GET + @Path("/{input}") //a way to name the pieces of the query + public String hash(@PathParam("input") String input) { //this argument will be initialized with the piece of the query + Hasher hasher = HasherFactory.createDefaultHasher(); + return new String(hasher.getHash(input.getBytes())); + } +} diff --git a/src/main/java/controller/Items.java b/src/main/java/controller/Items.java index b8d8bf19..03315b7d 100644 --- a/src/main/java/controller/Items.java +++ b/src/main/java/controller/Items.java @@ -31,7 +31,7 @@ @ServletPath("/api/items/*") @Path("/") public class Items { - + @POST @Path("/") @Consumes(MediaType.APPLICATION_JSON) diff --git a/src/main/java/controller/Users.java b/src/main/java/controller/Users.java index 7577a993..204db25a 100644 --- a/src/main/java/controller/Users.java +++ b/src/main/java/controller/Users.java @@ -15,9 +15,6 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - import com.fasterxml.jackson.core.type.TypeReference; import controller.tools.JsonTools; @@ -35,14 +32,18 @@ @ServletPath("/api/users/*") @Path("/") public class Users { - private final static Logger log = LogManager.getLogger(Users.class); - @GET + //@GET + @POST @Path("/login") - @Produces(MediaType.APPLICATION_JSON) - public String login( + @Produces(MediaType.APPLICATION_JSON) + public String login(String jsonCredentials) { + String[] credentials = jsonCredentials.split("&"); + String login = credentials[0].split("=")[1]; + String password = credentials[1].split("=")[1]; +/* public String login( @QueryParam("login") String login, - @QueryParam("password") String password) { - log.debug(login + " | " + password); + @QueryParam("password") String password) {*/ + Authentifier auth = Application.getInstance().getAuth(); UserSyncManager em = new UserSyncManagerImpl(); User u = em.getUser(login, password); @@ -84,12 +85,17 @@ public String logout(@HeaderParam(Authentifier.PARAM_NAME) String token) { return null; } - @GET + //@GET + @POST @Path("/subscribe") @Produces(MediaType.APPLICATION_JSON) - public String subscribe( + public String subscribe(String jsonCredentials) { + String[] credentials = jsonCredentials.split("&"); + String login = credentials[0].split("=")[1]; + String password = credentials[1].split("=")[1]; + /*public String subscribe( @QueryParam("login") String login, - @QueryParam("password") String password) { + @QueryParam("password") String password) {*/ User u = new User(); u.setNick(login); diff --git a/src/main/java/crypt/api/certificate/CertificateGenerator.java b/src/main/java/crypt/api/certificate/CertificateGenerator.java new file mode 100644 index 00000000..1797135c --- /dev/null +++ b/src/main/java/crypt/api/certificate/CertificateGenerator.java @@ -0,0 +1,60 @@ +package crypt.api.certificate; + +import java.security.KeyPair; +import java.security.cert.Certificate; + +/** + * Use to create Certificate (objet and file (jks) + * @author Sébastien Pelletier + * + */ +public interface CertificateGenerator +{ + /** + * Get the keyPair used for the certificate. + * @author Sébastien Pelletier + */ + public KeyPair getKeysPair() throws Exception; + + /** + * Get the Keystore password + * @author Sébastien Pelletier + */ + public String getKsPassword() throws Exception; + + /** + * Set the configuration file. (containing certificate information). + * @param file Path to the configuration file. + * @author Sébastien Pelletier + */ + public void setConfigFile(String file) throws Exception; + + /** + * Initalization of datas from file. + * @author Sébastien Pelletier + */ + public void initDatas() throws Exception; + + /** + * Create the certificate and keys for it. + * @param Signature specifie what signature you want. + * @return Return the newly created certificate. + * @author Sébastien Pelletier, Antoine Boudermine + */ + public Certificate CreateCertificate(String signature) throws Exception; + + /** + * Create a certificate chain of one certificate. + * @author Sébastien Pelletier + */ + public Certificate[] CreateChainCertificate() throws Exception; + + /** + * Store the created certificate in the specified file (keystore). + * @param file_name The keystore file. + * #Author Pelletier Sébastien + */ + public void StoreInKeystore(String file_name) throws Exception; + + +} diff --git a/src/main/java/crypt/impl/certificate/X509V3Generator.java b/src/main/java/crypt/impl/certificate/X509V3Generator.java new file mode 100644 index 00000000..8fc2a215 --- /dev/null +++ b/src/main/java/crypt/impl/certificate/X509V3Generator.java @@ -0,0 +1,448 @@ +package crypt.impl.certificate; + +import java.net.URI; +import java.util.Arrays; + +import javax.swing.JOptionPane; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.shredzone.acme4j.challenge.Challenge; +import org.shredzone.acme4j.challenge.Dns01Challenge; +import org.shredzone.acme4j.challenge.Http01Challenge; +import org.shredzone.acme4j.exception.AcmeConflictException; +import org.shredzone.acme4j.exception.AcmeException; +import org.shredzone.acme4j.exception.AcmeUnauthorizedException; +import org.shredzone.acme4j.util.CSRBuilder; +import org.shredzone.acme4j.util.CertificateUtils; +import org.shredzone.acme4j.util.KeyPairUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.shredzone.acme4j.Session; +import org.shredzone.acme4j.Registration; +import org.shredzone.acme4j.RegistrationBuilder; +import org.shredzone.acme4j.Authorization; +import org.shredzone.acme4j.Status; + + + +import crypt.api.certificate.CertificateGenerator; + +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.KeyPairGenerator; +import java.security.KeyPair; +import java.security.Security; +import java.math.BigInteger; +import java.util.Date; + +import java.security.cert.Certificate; +import javax.security.auth.x500.X500Principal; +import java.security.cert.X509Certificate; +import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure; +import org.bouncycastle.x509.X509V3CertificateGenerator; +import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +import java.io.*; + + +public class X509V3Generator implements CertificateGenerator +{ + /** + * Use this methode to create an instance of X509V3Genertor. + * @param config_file Name of the file that will be used by the instance. + */ + static public X509V3Generator getInstance(String config_file) throws Exception + { + X509V3Generator cert_gen = new X509V3Generator(); + cert_gen.setConfigFile(config_file); + cert_gen.initDatas(); + return cert_gen; + } + ///////////////////////////// private ////////////////////////////////// + + private String config_file; //Configuration file (certificate datas). + private boolean flag = false; //To kown if a certifictae has already been created. + + private String keystore_password; //Password for the keystore. can use toCharArray() + private String ks_alias; + private KeyStore ks; //KeyStore that will contain the certificate. + private Certificate cert; //The certificate. + private KeyPair key_pair; //Generated keys for the certificate. + + //Certificate datas. + private BigInteger serial_number; + private String domain_name; //Server's IP. + //private Date begin; //Start validity date. + //private Date end; //End validity date. + private String sign_alg; //Algorithm used to sign. + + + ////////////////////////////// Public //////////////////////////////// + + //// Geters&Seters //// + + + /** + * {@inheritDoc} + */ + @Override + public KeyPair getKeysPair() throws RuntimeException + { + if( !this.flag ) + { + throw new RuntimeException("getKeyPair() used wihout certificate genererated"); + } + return key_pair; + } + + /** + * {@inheritDoc} + */ + @Override + public String getKsPassword() throws Exception + { + return keystore_password; + } + + /** + * {@inheritDoc} + */ + @Override + public void setConfigFile(String file) throws Exception + { + this.config_file = file; + } + + ///// Methodes ///// + + /** + * {@inheritDoc} + * file pattern : + * data=value + * data1=value1 + */ + @Override + public void initDatas() throws Exception + { + try + { + File file = new File(this.config_file); + + //Create file if it does not exists. + if( !file.exists() ) + { + createDefaultConfigFile(); + } + + InputStream input_stream = new FileInputStream(file); + InputStreamReader input_stream_reader = new InputStreamReader(input_stream); + BufferedReader buffered_reader = new BufferedReader(input_stream_reader); + String line; + + String name; //Configuration name. + String value; //Value to this name. + String[] temp; + + + while( (line = buffered_reader.readLine()) != null ) + { + if( !line.isEmpty() && !line.startsWith("#") && !line.startsWith(" ") ) //if not a comment or newline. + { + line = line.split("#")[0]; //Delete comments. + line = line.split(" ")[0]; //Delete useless spaces. + line = line.split("\t")[0]; //Delete useless tabs. + temp = line.split("="); + name = temp[0]; + value = temp[1]; + switch(name) + { + case "kspassword" : + this.keystore_password = value; + break; + case "ksalias": + this.ks_alias = value; + break; + case "serialnumber" : + this.serial_number = new BigInteger(value); + break; + case "signalgorithm": + this.sign_alg = value; + break; + case "domainname": + this.domain_name = value; + break; + default: + throw new RuntimeException("Bad configuration file : " + line); + } + //System.out.println(name + " = " + value); + } + } + + buffered_reader.close(); + } + catch( Exception e ) + { + throw e; + } + + } + + /** + * Create the default certificate configuration file. + * @param file_name Name of the file that will be created. + */ + public void createDefaultConfigFile() throws Exception + { + String content = ""; + content += "# This configuration file contains values for the certificate\n"; + content += "# used by this application. The certificate will be stored in\n"; + content += "# keystore.jks .\n\n"; + content += "kspassword=123456 #Password for the keystore.\n"; + content += "ksalias=SXP #Alias for the certificate in the keystore.\n"; + content += "serialnumber=0123456789 #Serial Number.\n"; + content += "signalgorithm=MD5WithRSA #Algorithm used for siging the certificate. (SHA256withRSA)\n"; + content += "domainname=localhost #IP / domain name of the serveur.\n"; + + File file = new File(this.config_file); + try + { + FileWriter file_writer = new FileWriter(file); + file_writer.write (content); + file_writer.close(); + } + catch (IOException exception) + { + throw new IOException("Error while creation of default configuration file : " + + this.config_file + "\n", exception); + } + } + + /** + * {@inheritDoc} + * Implemented Signature : "self-signed" + * "CA-signed" + */ + @Override + public Certificate CreateCertificate(String signature) throws Exception + { + if( signature == "self-signed" ) + { + if( !this.flag ) + { + //Provider custom + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + + //Keys (priv & public) generation. + KeyPairGenerator key_gen = KeyPairGenerator.getInstance("RSA"); + key_gen.initialize(1024); + KeyPair keys = key_gen.genKeyPair(); + this.key_pair = keys; + + //Création du certificat. + X509V3CertificateGenerator cert_gen = new X509V3CertificateGenerator(); + + X500Principal cn = new X500Principal("CN=" + domain_name ); + cert_gen.setSerialNumber(this.serial_number); + cert_gen.setIssuerDN(cn); + cert_gen.setNotBefore(new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000)); + cert_gen.setNotAfter(new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000)); + cert_gen.setSubjectDN(cn); + cert_gen.setPublicKey(keys.getPublic()); + cert_gen.setSignatureAlgorithm(this.sign_alg); + + //this.cert = cert_gen.generateX509Certificate(keys.getPrivate(), "BC"); //CA private key (autosigned) + this.cert = cert_gen.generate(keys.getPrivate(), "BC"); //CA private key (autosigned) + this.flag = true; + } + } + // else if( signature == "CA-signed" ) + // { + // //Provider custom + // + // Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + // + // //Keys (priv & public) generation. + // + // KeyPairGenerator key_gen = KeyPairGenerator.getInstance("RSA"); + // key_gen.initialize(2048); + // KeyPair keys = key_gen.genKeyPair(); + // this.key_pair = keys; + // + // // Create a session for Let's Encrypt + // + // Session session = new Session("acme://letsencrypt.org/staging", this.key_pair); + // + // // Register a new user + // + // Registration reg = null; + // try + // { + // reg = new RegistrationBuilder().create(session); + // } + // catch (AcmeConflictException ex) + // { + // reg = Registration.bind(session, ex.getLocation()); + // System.out.println("Let's Encrypt account does already exist"); + // } + // + // URI agreement = reg.getAgreement(); + // reg.modify().setAgreement(agreement).commit(); + // + // Authorization auth = null; + // try + // { + // auth = reg.authorizeDomain(domain_name); + // } + // catch (AcmeUnauthorizedException ex) + // { + // // Maybe there are new T&C to accept? + // reg.modify().setAgreement(agreement).commit(); + // // Then try again... + // auth = reg.authorizeDomain(domain_name); + // } + // + // Challenge challenge = httpChallenge(auth, domain_name); + // if (challenge == null) + // { + // System.exit(0); + // } + // System.out.println("challenge created"); + // challenge.trigger(); + // + // int attempts = 10; + // while (challenge.getStatus() != Status.VALID && attempts-- > 0) + // { + // System.out.println(attempts); + // if (challenge.getStatus() == Status.INVALID) + // { + // System.out.println("Challenge failed... Giving up."); + // System.exit(0); + // } + // try + // { + // Thread.sleep(3000L); + // } + // catch (InterruptedException ex) + // { + // System.out.println("interrupted"); + // } + // challenge.update(); + // } + // if (challenge.getStatus() != Status.VALID) + // { + // System.out.println("Failed to pass the challenge... Giving up."); + // System.exit(0); + // } + // System.out.println("challenge acepté"); + // // Generate a CSR for the domain + // CSRBuilder csrb = new CSRBuilder(); + // csrb.addDomains(domain_name);//peut etre une collection de string + // csrb.sign(key_pair); + // + // // Request a signed certificate + // org.shredzone.acme4j.Certificate certificate = reg.requestCertificate(csrb.getEncoded()); + // + // // Download the certificate chain + // X509Certificate[] chain = certificate.downloadChain(); + // this.cert = chain[0]; + // } + else + { + throw new RuntimeException("Unknown Signature process : " + signature); + } + + return this.cert; + } + + +// public Challenge httpChallenge(Authorization auth, String domain) throws AcmeException, IOException +// { +// +// // Find a single http-01 challenge +// Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE); +// if (challenge == null) +// { +// System.out.println("Found no http challenge, I don't know what to do..."); +// return null; +// } +// +// try +// { +// FileWriter file = new FileWriter(new File("." + challenge.getToken() )); +// file.write (challenge.getAuthorization()); +// file.close(); +// } +// catch(IOException exp ) +// { +// throw new IOException("error", exp); +// } +// +// // Output the challenge, wait for acknowledge... +// System.out.println("Please create a file in your web server's base directory."); +// System.out.println("It must be reachable at: http://" + domain_name + "/.well-known/acme-challenge/" + challenge.getToken()); +// System.out.println("File name: " + challenge.getToken()); +// System.out.println("Content: " + challenge.getAuthorization()); +// System.out.println("The file must not contain any leading or trailing whitespaces or line breaks!"); +// System.out.println("If you're ready, dismiss the dialog..."); +// +// return challenge; +// } + + /** + * {@inheritDoc} + */ + @Override + public Certificate[] CreateChainCertificate() throws Exception + { + if( !this.flag ) + this.CreateCertificate("self-signed"); + + Certificate[] cert_chain = new X509Certificate[1]; + cert_chain[0] = this.cert; + return cert_chain; + } + + /** + * Store the created certificate in the specified file (keystore). + * @param file_name The keystore file. + * #Author Pelletier Sébastien + */ + public void StoreInKeystore(String file_name) throws Exception + { + File file = new File(file_name); + if( file.exists() ) + { + System.out.println("Keystore already exist"); + return; + } + + char[] password = this.keystore_password.toCharArray(); + KeyStore.PasswordProtection protected_password = new KeyStore.PasswordProtection(password); + + //Keystore Creation + KeyStore ks = KeyStore.getInstance("jks"); + ks.load(null, password); //Loading from nothing (null) in order to create a new one. + + Certificate[] cert_chain = this.CreateChainCertificate(); + + ks.setEntry(this.ks_alias, + new KeyStore.PrivateKeyEntry(key_pair.getPrivate(), cert_chain), + new KeyStore.PasswordProtection(password)); + + //Storing the created key in the file. + java.io.FileOutputStream fos = null; + try + { + fos = new java.io.FileOutputStream(file_name); + ks.store(fos, password); + } + finally + { + if(fos != null) + fos.close(); + } + } +} + diff --git a/src/main/java/crypt/utils/BigIntegerRandom.java b/src/main/java/crypt/utils/BigIntegerRandom.java index 4df98a6e..8c886fcc 100644 --- a/src/main/java/crypt/utils/BigIntegerRandom.java +++ b/src/main/java/crypt/utils/BigIntegerRandom.java @@ -9,11 +9,8 @@ static public BigInteger rand (int bitLength, BigInteger p) { BigInteger s; s = new BigInteger(bitLength,random); - // CoverSXP correction while(s.compareTo(BigInteger.ONE) < 0 || s.compareTo(p) > 0) - //while(s.compareTo(BigInteger.ONE)<=0 && s.compareTo(p)>= 0) s = new BigInteger(bitLength,random); - return s; } } diff --git a/src/main/java/protocol/impl/sigma/Utils.java b/src/main/java/protocol/impl/sigma/Utils.java index 07a091ed..1757aeae 100644 --- a/src/main/java/protocol/impl/sigma/Utils.java +++ b/src/main/java/protocol/impl/sigma/Utils.java @@ -36,9 +36,7 @@ static public BigInteger rand (int bitLength, BigInteger p) { BigInteger s; s = new BigInteger(bitLength,random); - // CoverSXP correction while(s.compareTo(BigInteger.ONE) < 0 || s.compareTo(p) > 0) - //while(s.compareTo(BigInteger.ONE)<=0 && s.compareTo(p)>= 0) s = new BigInteger(bitLength,random); return s; diff --git a/src/main/java/rest/impl/JettyRestServer.java b/src/main/java/rest/impl/JettyRestServer.java index 5d2f875c..0537294c 100644 --- a/src/main/java/rest/impl/JettyRestServer.java +++ b/src/main/java/rest/impl/JettyRestServer.java @@ -1,51 +1,69 @@ package rest.impl; -import java.io.IOException; - import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.eclipse.jetty.http.HttpVersion; + +import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + import com.google.common.reflect.ClassPath; import rest.api.RestServer; import rest.api.ServletPath; +import crypt.impl.certificate.X509V3Generator; +import crypt.api.certificate.CertificateGenerator; public class JettyRestServer implements RestServer{ - + private final static Logger log = LogManager.getLogger(JettyRestServer.class); private ServletContextHandler context; private Server server; - + private CertificateGenerator cert_gen; + /** * {@inheritDoc} */ @Override public void initialize(String packageName) { context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.setContextPath("/"); - - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + context.setContextPath("/"); + + final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - try { + try { for (final ClassPath.ClassInfo info : ClassPath.from(loader).getTopLevelClasses()) { - if (info.getName().startsWith(packageName + ".")) { - final Class clazz = info.load(); - ServletPath path = clazz.getAnnotation(ServletPath.class); - if(path == null) { - continue; + if (info.getName().startsWith(packageName + ".")) { + final Class clazz = info.load(); + ServletPath path = clazz.getAnnotation(ServletPath.class); + if(path == null) { + continue; + } + ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, path.value()); + jerseyServlet.setInitOrder(0); + jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", clazz.getCanonicalName()); } - ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, path.value()); - jerseyServlet.setInitOrder(0); - jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", clazz.getCanonicalName()); - } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } - - /*for(Class c : entryPoints) { - + + /*for(Class c : entryPoints) { + ServletPath path = c.getAnnotation(ServletPath.class); if(path == null) { throw new RuntimeException("No servlet path annotation on class " + c.getCanonicalName()); @@ -61,10 +79,138 @@ public void initialize(String packageName) { */ @Override public void start(int port) throws Exception { - server = new Server(port); - server.setHandler(context); + + server = new Server(); + server.setHandler(context); + + String signe_type = "self-signed"; + + /*if( signe_type == "CA-signed" ) + { + //Launching a simple http on 80 port for challenge + //the CA serveur. + createAndSetConnector(80, "http"); //Launch in sudo bc of 80; + server.start(); + + TimeUnit.SECONDS.sleep(3); //Give some time to Jetty to be on. + + this.cert_gen = X509V3Generator.getInstance("certConfig.conf"); + this.cert_gen.CreateCertificate("CA-signed"); + this.cert_gen.StoreInKeystore("keystore.jks"); + + //Restarting the serveur with good certificate. + server.stop(); + createAndSetConnector(port, "https"); + //server.setHandler(context); + } + else if( signe_type == "self-signed" ) + {*/ + this.cert_gen = X509V3Generator.getInstance("certConfig.conf"); + this.cert_gen.CreateCertificate("self-signed"); + this.cert_gen.StoreInKeystore("keystore.jks"); + createAndSetConnector(port, "https"); + //} + server.start(); - server.join(); + server.join(); + } + + /** + * Create and link the proper connector to + * the jetty serveur. + * @param port Port the server will use for the given protocol. + * @param protocol Protocol used by the jetty serveur (currently available protocols : http, https). + */ + public void createAndSetConnector(int port, String protocol) throws Exception + { + + // Http config (base config) + HttpConfiguration http_config = new HttpConfiguration(); + http_config.setSecureScheme("https"); + http_config.setSecurePort(port); + http_config.setOutputBufferSize(38768); + javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier( + new javax.net.ssl.HostnameVerifier(){ + + public boolean verify(String hostname, + javax.net.ssl.SSLSession sslSession) { + if (hostname.equals("localhost")) { + return true; + } + return false; + } + }); + + /* switch (protocol) + { + case "http": + // Http Connector + ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(http_config) ); + http.setPort(port); + http.setIdleTimeout(30000); + + server.setConnectors(new Connector[] {http}); + break; + + case "https":*/ + // SSL Context factory for HTTPS + SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath("keystore.jks"); + sslContextFactory.setKeyStorePassword(this.cert_gen.getKsPassword()); + sslContextFactory.setKeyManagerPassword(this.cert_gen.getKsPassword()); + + // HTTPS Config + HttpConfiguration https_config = new HttpConfiguration(http_config); + SecureRequestCustomizer src = new SecureRequestCustomizer(); + src.setStsMaxAge(2000); + src.setStsIncludeSubDomains(true); + https_config.addCustomizer(src); + + // HTTPS Connector + ServerConnector https = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(https_config)); + https.setPort(port); + https.setIdleTimeout(500000); + log.debug("HTTPS context"); + server.setConnectors(new Connector[] {https}); + /* break; + + case "http&https": + // Http Connector + ServerConnector httpb = new ServerConnector(server, new HttpConnectionFactory(http_config) ); + httpb.setPort(port); + httpb.setIdleTimeout(30000); + + // SSL Context factory for HTTPS + SslContextFactory sslContextFactoryb = new SslContextFactory(); + sslContextFactoryb.setKeyStorePath("keystore.jks"); + sslContextFactoryb.setKeyStorePassword(this.cert_gen.getKsPassword()); + sslContextFactoryb.setKeyManagerPassword(this.cert_gen.getKsPassword()); + + // HTTPS Config + HttpConfiguration https_configb = new HttpConfiguration(http_config); + SecureRequestCustomizer srcb = new SecureRequestCustomizer(); + srcb.setStsMaxAge(2000); + srcb.setStsIncludeSubDomains(true); + https_configb.addCustomizer(srcb); + + // HTTPS Connector + ServerConnector httpsb = new ServerConnector(server, + new SslConnectionFactory(sslContextFactoryb, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(https_configb)); + httpsb.setPort(port+1); + httpsb.setIdleTimeout(500000); + + server.setConnectors(new Connector[] {httpb, httpsb}); + break; + + + default: + System.out.println("Wrong connector protocol for jetty."); + System.exit(1); + break; + }*/ } /** @@ -74,5 +220,4 @@ public void start(int port) throws Exception { public void stop() { server.destroy(); } - } diff --git a/src/main/js/html/index.html b/src/main/js/html/index.html index 02649163..20cf07f4 100644 --- a/src/main/js/html/index.html +++ b/src/main/js/html/index.html @@ -8,21 +8,22 @@ + - - + + - - - - - + + + + + - + - + @@ -43,10 +44,6 @@ - - - -