Commit 2ec88d87 authored by Tobias Assmann's avatar Tobias Assmann
Browse files

#2 renaming stuff in SSA to match SAM, add config to SAM, start build CSR...

#2 renaming stuff in SSA to match SAM, add config to SAM, start build CSR stuff in SAM and use it in SSA
parent 79e21961
......@@ -111,7 +111,7 @@ services:
- ejbca
command: /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 --debug 0.0.0.0:9797
ports:
# - "127.0.0.1:28080:8080"
- "127.0.0.1:28080:8080"
#- "127.0.0.1:29990:9990"
- "127.0.0.1:9797:9797" # Java Debug Port
volumes:
......@@ -126,10 +126,12 @@ services:
container_name: "reqesidta_sam"
build:
context: ./sam
#ports:
# - "127.0.0.1:38080:8080"
ports:
- "127.0.0.1:38080:8080"
networks:
- reqesidta_net
reqesidta_net:
aliases:
- sam.docker.reqesidta.de
networks:
reqesidta_net:
......
......@@ -88,12 +88,22 @@
<groupId>io.thorntail</groupId>
<artifactId>cdi</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<!-- used for configuration implementation -->
<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
</dependency>
<!-- used for crypto -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.62</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency> -->
</dependencies>
......
package de.governikus.eumw.ssaserver.rest;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
@ApplicationScoped
@Path("/hello")
public class HelloWorldEndpoint {
@GET
@Produces("text/plain")
public Response doGet() {
return Response.ok("Hello from Thorntail!").build();
}
}
/****************************************************************************
* Copyright (C) 2019 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file may be used in accordance with the terms and conditions
* contained in a signed written agreement between you and ecsec GmbH.
*
***************************************************************************/
package reqesidta.sam.config;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import org.jboss.logging.Logger;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigBeanFactory;
import com.typesafe.config.ConfigFactory;
/**
*
* @author René Lottes
*/
@ApplicationScoped
public class ConfigLoader {
private static final Logger log = Logger.getLogger(ConfigLoader.class);
private final SAMConfig configBean;
public ConfigLoader() throws IOException, URISyntaxException, GeneralSecurityException {
// load config from $HOME/sam-server.conf and merge with bundled reference.conf
String homeDir = System.getProperty("user.home");
File path = new File(homeDir, "sam-server.conf");
// set property to load external file
if (path.exists()) {
log.debug("Loading config {} "+path.getAbsolutePath());
System.setProperty("config.url", path.toURI().toString());
}
ConfigFactory.invalidateCaches();
Config rawCfg = ConfigFactory.load();
this.configBean = ConfigBeanFactory.create(rawCfg.getConfig("sam-config"), SAMConfig.class);
}
@Produces
public SAMConfig getConfig() {
return this.configBean;
}
}
package reqesidta.sam.config;
/**
*
* @author tobias.assmann@ecsec.de
*
*/
public class SAMConfig {
private int sessionMaxAge;
private int sessionCheckAgeInterval;
private String localKeyFile;
private String localKeyPass;
public int getSessionMaxAge() {
return sessionMaxAge;
}
public void setSessionMaxAge(int sessionMaxAge) {
this.sessionMaxAge = sessionMaxAge;
}
public int getSessionCheckAgeInterval() {
return sessionCheckAgeInterval;
}
public void setSessionCheckAgeInterval(int sessionCheckAgeInterval) {
this.sessionCheckAgeInterval = sessionCheckAgeInterval;
}
public String getLocalKeyFile() {
return localKeyFile;
}
public void setLocalKeyFile(String localKeyFile) {
this.localKeyFile = localKeyFile;
}
public String getLocalKeyPass() {
return localKeyPass;
}
public void setLocalKeyPass(String localKeyPass) {
this.localKeyPass = localKeyPass;
}
}
package reqesidta.sam.csr.rest;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyStore;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
import org.jboss.logging.Logger;
import reqesidta.sam.config.SAMConfig;
import reqesidta.sam.csr.utils.CSRFactory;
import reqesidta.sam.session.Session;
import reqesidta.sam.session.SessionStore;
/**
* Webservice endpoint implementing the Issue/Sig interface
* @author tobias.assmann@ecsec.de
*
*/
@ApplicationScoped
@Path("/csr")
public class CSREndpoint {
private final static Logger log = Logger.getLogger(CSREndpoint.class);
@Inject private SessionStore sessionStore;
@Inject private SAMConfig config;
@GET
@Path("getcsr/{sessionId}")
public Response getCSR(@PathParam("sessionId") String sessionId) {
// Session session = getSessionOrThrowNotFound(sessionId);
Session session = sessionStore.getNewSession(); //TODO remove and make it real!!
CSRFactory csrFac = new CSRFactory();
// gen key pair for csr and save to session
KeyPair pair;
try {
pair = csrFac.genKeyPair();
session.set(Session.USER_KEY, pair);
} catch (GeneralSecurityException e) {
throw new InternalServerErrorException();
}
//
// KeyStore kst = KeyStore.getInstance("PKCS12");
// kst.load(stream, password);
// load mit FileInput Stream+password, dann key über alias laden
// TODO public kay aus pair mit id kram aus session -> CertificationRequestInfo
// TODO sign CRI mit private key aus config (wie ssa reference.conf -> string to pkcs12file und passphrase => ergibt keypair)
// TODO erstelle CSR und gebe zurück
return Response.ok("hey").build();
}
private Session getSessionOrThrowNotFound(String sessionId) {
Session session = sessionStore.getSession(sessionId)
.orElseThrow(() -> {
return new NotFoundException();
});
return session;
}
}
/****************************************************************************
* Copyright (C) 2019 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file may be used in accordance with the terms and conditions
* contained in a signed written agreement between you and ecsec GmbH.
*
***************************************************************************/
package reqesidta.sam.csr.utils;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
//import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
//import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.jboss.logging.Logger;
/**
*
* @author René Lottes, tobias.assmann@ecsec.de
*/
public class CSRFactory {
private final static Logger log = Logger.getLogger(CSRFactory.class);
public KeyPair genKeyPair() throws GeneralSecurityException {
KeyPair pair;
try {
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
KeyPairGenerator g = KeyPairGenerator.getInstance("EC", "BC");
g.initialize(ecSpec, new SecureRandom());
pair = g.generateKeyPair();
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException ex) {
log.error("Cannot generate keypair: ", ex);
throw ex;
}
return pair;
}
public byte[] genCertReqInfo(PublicKey pubKey,
String firstName,
String lastName,
String birthName,
String dayOfBirth) {
// ASN1Set asn1set
//
// CertificationRequestInfo csrInfo = new CertificationRequestInfo(
// new X500Name(rdns.toArray(new RDN[0])),
// SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()),
// null);
//
// return csrInfo.getEncoded(ASN1Encoding.DER); //TODO: DER or BER?
return null;
}
/*
public byte[] genCertReqInfo(PublicKey publicKey, String eduPersonPrincipleName, String normalizedCN, String dfnPrefixes) throws IOException {
String hashedPrincipleName = null;
try {
hashedPrincipleName = DatatypeConverter.printHexBinary(
MessageDigest.getInstance("SHA-256")
.digest(eduPersonPrincipleName.getBytes(StandardCharsets.UTF_8)));
} catch (NoSuchAlgorithmException ex) {
String msg = "Unable hash the eduPersonPrincipleName for the certificate mapping.";
log.error(msg, ex);
throw new RuntimeException(msg, ex); //TODO: handle exception
}
RDN[] dfnPrefixesRDN = new X500Name(dfnPrefixes).getRDNs();
List<RDN> rdns = new ArrayList<>(2);
rdns.addAll(List.of(dfnPrefixesRDN));
rdns.add(new RDN(BCStyle.CN, new DERPrintableString(normalizedCN)));
rdns.add(new RDN(BCStyle.UID, new DERPrintableString(hashedPrincipleName)));
CertificationRequestInfo csrInfo = new CertificationRequestInfo(
new X500Name(rdns.toArray(new RDN[0])),
SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()),
null);
return csrInfo.getEncoded(ASN1Encoding.DER); //TODO: DER or BER?
}
public byte[] buildCSR(byte[] certReqInfo, AlgorithmIdentifier algorithm, byte[] signature) throws IOException {
CertificationRequestInfo info = CertificationRequestInfo.getInstance(ASN1Sequence.fromByteArray(certReqInfo));
PKCS10CertificationRequest req = new PKCS10CertificationRequest(
new CertificationRequest(
info,
algorithm,
new DERBitString(signature)
)
);
return req.getEncoded();
}
public byte[] buildCSR(byte[] certReqInfo, String algorithm, byte[] signature) throws IOException {
return buildCSR(certReqInfo, mapAlgorithm(algorithm), signature);
}
private AlgorithmIdentifier mapAlgorithm(String algo) {
var algoMapper = new DefaultSignatureAlgorithmIdentifierFinder();
return algoMapper.find(algo);
}
*/
}
package de.governikus.eumw.ssaserver.rest;
package reqesidta.sam.rest;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
......
......@@ -25,6 +25,7 @@ public class Session {
public final static String INIT_SESSION_DATA = "init-session-data";
public final static String EAC2_DATA = "eac1-data";
public final static String EPHEMERAL_KEY = "ephemeral-key";
public final static String USER_KEY = "user-key";
Session(String ID) {
this.ID = ID;
......
sam-config {
sessionMaxAge: 60,
sessionCheckAgeInterval: 30,
localKeyFile: "pathtopcks12file",
localKeyAlias: "ALIAS of SAM CERT in pkcs12file"
localKeyPass: "passsphrase of pkcs12file",
}
\ No newline at end of file
......@@ -19,6 +19,7 @@ public class SSAConfig {
private int sessionCheckAgeInterval;
private String baseUrl;
private String eidUrl;
private String samUrl;
private CertificateAuthorityConfig caConfig;
public int getSessionMaxAge() {
......@@ -53,6 +54,14 @@ public class SSAConfig {
this.eidUrl = eidUrl;
}
public String getSamUrl() {
return this.samUrl;
}
public void setSamUrl(String samUrl) {
this.samUrl = samUrl;
}
public CertificateAuthorityConfig getCaConfig() {
return caConfig;
}
......
......@@ -20,6 +20,11 @@ import reqesidta.ssa.config.SSAConfig;
* @author Neil Crossley
*/
public class VetoExtension implements Extension {
/**
* Tell application server the config is not a bean.
* @param <T>
* @param pat
*/
public <T> void disableBeans(@Observes ProcessAnnotatedType<T> pat) {
if (SSAConfig.class.isAssignableFrom(pat.getAnnotatedType().getJavaClass())) {
......
......@@ -7,7 +7,7 @@
* contained in a signed written agreement between you and ecsec GmbH.
*
***************************************************************************/
package reqesidta.ssa.api;
package reqesidta.ssa.rest;
/**
*
......
......@@ -7,7 +7,7 @@
* contained in a signed written agreement between you and ecsec GmbH.
*
***************************************************************************/
package reqesidta.ssa.api;
package reqesidta.ssa.rest;
import java.util.List;
import javax.json.bind.annotation.JsonbProperty;
......
package reqesidta.ssa.api;
import java.util.Optional;
package reqesidta.ssa.rest;
import javax.inject.Inject;
import javax.ws.rs.GET;
......@@ -26,14 +24,14 @@ import reqesidta.ssa.session.Session;
import reqesidta.ssa.session.SessionStore;
/**
* WebService implementing TR-03130
* WebService endpoint implementing TR-03130
*
* @author Tobias Assmann
*/
@Path("/eid")
public class EidService {
public class EIDEndpoint {
private static final Logger log = LoggerFactory.getLogger(EidService.class);
private static final Logger log = LoggerFactory.getLogger(EIDEndpoint.class);
@Inject private SSAConfig config;
@Inject private SessionStore sessionStore;
......@@ -108,13 +106,13 @@ public class EidService {
* @param sessionId
* @return
*/
private Session readSession(String sessionId) {
Optional<Session> sessionOpt = sessionStore.getSession(sessionId);
if (!sessionOpt.isPresent()) {
throw new NotFoundException();
}
private Session readSession(String sessionId) throws NotFoundException {
Session session = sessionStore.getSession(sessionId)
.orElseThrow(() -> {
return new NotFoundException();
});
return sessionOpt.get();
return session;
}
}
......@@ -7,7 +7,7 @@
* contained in a signed written agreement between you and ecsec GmbH.
*
***************************************************************************/
package reqesidta.ssa.api;
package reqesidta.ssa.rest;
import javax.json.bind.annotation.JsonbProperty;
......
......@@ -7,7 +7,7 @@
* contained in a signed written agreement between you and ecsec GmbH.
*
***************************************************************************/
package reqesidta.ssa.api;
package reqesidta.ssa.rest;
import javax.json.bind.annotation.JsonbProperty;
......
......@@ -7,23 +7,15 @@
* contained in a signed written agreement between you and ecsec GmbH.
*
***************************************************************************/
package reqesidta.ssa.api;
package reqesidta.ssa.rest;
import java.util.Set;
import javax.ws.rs.core.Application;
/**
* Setupt the rest application, endpoints are added via annotations of classes in classpath.
*
* @author Neil Crossley, Tobias Assmann
*/
@javax.ws.rs.ApplicationPath("")
public class ApplicationConfig extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
resources.add(reqesidta.ssa.api.SsaService.class);
resources.add(reqesidta.ssa.api.EidService.class);
return resources;
}
public class RestApplication extends Application {
}
......@@ -7,7 +7,7 @@
* contained in a signed written agreement between you and ecsec GmbH.
*
***************************************************************************/
package reqesidta.ssa.api;
package reqesidta.ssa.rest;
import javax.inject.Inject;
import javax.json.bind.Jsonb;
......@@ -16,9 +16,13 @@ import javax.json.bind.JsonbConfig;
import javax.json.bind.config.BinaryDataStrategy;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
......@@ -30,21 +34,21 @@ import reqesidta.ssa.session.Session;
import reqesidta.ssa.session.SessionStore;
/**
* WebService implementing the SSA interface
* WebService endpoint implementing the SSA interface
*
* @author Neil Crossley, Tobias Assmann
*/
@Path("/ssa")
public class SsaService {
public class SSAEndpoint {
private static final Logger