Commit ec5af533 authored by Loïck Bonniot's avatar Loïck Bonniot

[t][p] Add TTP authentication and start cmd

parent f0c355d5
Pipeline #378 passed with stage
......@@ -22,12 +22,13 @@ You just have to untar the archive and run the following binaries:
```bash
./dfssc help # Client
./dfssp help # Platform
./dfsst help # TTP
./dfssd help # Demonstrator
```
Here is a basic tutorial to setup a new DFSS environment.
### Setup platform
### Setup platform and TTP (Trusted Third Party)
The first thing to do is to create the *root certificate of authentication* for the platform.
You can configure several parameters for that (check the `help` command of `dfssp`).
......@@ -38,6 +39,13 @@ For instance, if we are running the plaform on the `example.com` host:
./dfssp -cn example.com -country FR -rootValidity 3650 init
```
Then, it is possible to create TTP credentials from generated root credentials.
The generated files are stored in a subdirectory "ttp".
```bash
./dfssp -cn ttp.example.com -country FR -certValidity 365 ttp
```
You can then start the platform. Here we are considering a mongoDB database running on the same host.
Firstly, we have to configure several environment variables to set smtp server configuration (mails):
......@@ -55,6 +63,12 @@ Then:
./dfssp start
```
You can also start the TTP:
```bash
./dfsst -cert ttp/cert.pem -key ttp/cert.pem start
```
### Setup clients
Each client needs the `dfssp_rootCA.pem` file in order to connect to the platform in a secure way.
......
......@@ -3,9 +3,11 @@ package authority
import (
"crypto/rsa"
"crypto/x509"
"dfss/auth"
"io/ioutil"
"os"
"path/filepath"
"dfss/auth"
)
const (
......@@ -21,50 +23,52 @@ type PlatformID struct {
RootCA *x509.Certificate
}
// GenerateRootCA constructs a self-signed certificate, using a unique serial number randomly generated
func GenerateRootCA(days int, country, organization, unit, cn string, key *rsa.PrivateKey) ([]byte, error) {
serial := auth.GenerateUID()
cert, err := auth.GetSelfSignedCertificate(days, serial, country, organization, unit, cn, key)
// Initialize creates and saves the platform's private key and root certificate to a PEM format.
// If ca and rKey are not nil, they will be used as the root certificate and root private key instead of creating a ones.
// The files are saved at the specified path.
func Initialize(bits, days int, country, organization, unit, cn, path string, ca *x509.Certificate, rKey *rsa.PrivateKey) error {
// Generate the private key.
key, err := auth.GeneratePrivateKey(bits)
if err != nil {
return nil, err
return err
}
return cert, nil
}
var cert []byte
certPath := filepath.Join(path, RootCAFileName)
keyPath := filepath.Join(path, PkeyFileName)
// Initialize creates and saves the platform's private key and root certificate to a PEM format.
//
// The files are saved at the specified path.
func Initialize(bits, days int, country, organization, unit, cn, path string) error {
// Generating the private key.
key, err := auth.GeneratePrivateKey(bits)
if ca == nil {
// Generate the root certificate, using the private key.
cert, err = auth.GetSelfSignedCertificate(days, auth.GenerateUID(), country, organization, unit, cn, key)
} else {
csr, _ := auth.GetCertificateRequest(country, organization, unit, cn, key)
request, _ := auth.PEMToCertificateRequest(csr)
cert, err = auth.GetCertificate(days, auth.GenerateUID(), request, ca, rKey)
// Override default path values
certPath = filepath.Join(path, "cert.pem")
keyPath = filepath.Join(path, "key.pem")
}
if err != nil {
return err
}
// Generating the root certificate, using the private key.
cert, err := GenerateRootCA(days, country, organization, unit, cn, key)
// Create missing folders, if needed
err = os.MkdirAll(path, os.ModeDir|0700)
if err != nil {
return err
}
// Converting the private key to a PEM format, and saving it.
// Convert the private key to a PEM format, and save it.
keyPem := auth.PrivateKeyToPEM(key)
keyPath := filepath.Join(path, PkeyFileName)
err = ioutil.WriteFile(keyPath, keyPem, 0600)
if err != nil {
return err
}
// Saving the root certificate.
certPath := filepath.Join(path, RootCAFileName)
// Save the root certificate.
err = ioutil.WriteFile(certPath, cert, 0600)
if err != nil {
return err
}
......@@ -81,28 +85,24 @@ func Start(path string) (*PlatformID, error) {
keyPath := filepath.Join(path, PkeyFileName)
certPath := filepath.Join(path, RootCAFileName)
// Recovering the private rsa key from file.
// Recover the private rsa key from file.
keyBytes, err := ioutil.ReadFile(keyPath)
if err != nil {
return nil, err
}
key, err := auth.PEMToPrivateKey(keyBytes)
if err != nil {
return nil, err
}
// Recovering the root certificate from file.
// Recover the root certificate from file.
certBytes, err := ioutil.ReadFile(certPath)
if err != nil {
return nil, err
}
cert, err := auth.PEMToCertificate(certBytes)
if err != nil {
return nil, err
}
......
......@@ -2,11 +2,13 @@ package authority
import (
"crypto/rsa"
"dfss/auth"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"dfss/auth"
)
var pkey *rsa.PrivateKey
......@@ -17,11 +19,11 @@ func TestMain(m *testing.M) {
}
func TestInitialize(t *testing.T) {
path := os.TempDir()
path, _ := ioutil.TempDir("", "")
keyPath := filepath.Join(path, PkeyFileName)
certPath := filepath.Join(path, RootCAFileName)
err := Initialize(1024, 365, "country", "organization", "unit", "cn", path)
err := Initialize(1024, 365, "country", "organization", "unit", "cn", path, nil, nil)
if err != nil {
t.Fatal(err)
......@@ -29,36 +31,54 @@ func TestInitialize(t *testing.T) {
if _, err = os.Stat(keyPath); os.IsNotExist(err) {
t.Fatal("Private key file couldn't be found")
} else {
_ = os.Remove(keyPath)
}
if _, err = os.Stat(certPath); os.IsNotExist(err) {
t.Fatal("Root certificate file couldn't be found")
} else {
_ = os.Remove(certPath)
}
_ = os.RemoveAll(path)
}
func ExampleInitialize() {
path := os.TempDir()
func Example() {
path, _ := ioutil.TempDir("", "")
keyPath := filepath.Join(path, PkeyFileName)
certPath := filepath.Join(path, RootCAFileName)
err := Initialize(1024, 365, "country", "organization", "unit", "cn", path)
// Generate root certificate and key
err := Initialize(1024, 365, "UK", "DFSS", "unit", "ROOT", path, nil, nil)
if err != nil {
fmt.Println(err)
return
}
CheckFile(keyPath, "Private key")
CheckFile(certPath, "Certificate")
// Fetch files into memory
pid, err := Start(path)
if err != nil {
fmt.Println(err)
return
}
// Generate child certificate and key
childPath := filepath.Join(path, "child")
err = Initialize(1024, 10, "FR", "DFSS", "unit", "CHILD", childPath, pid.RootCA, pid.Pkey)
if err != nil {
fmt.Println(err)
return
}
CheckFile(filepath.Join(childPath, "key.pem"), "Child private key")
CheckFile(filepath.Join(childPath, "cert.pem"), "Child certificate")
_ = os.RemoveAll(path)
// Output:
// Private key file has been found
// Private key file has been deleted
// Certificate file has been found
// Certificate file has been deleted
// Child private key file has been found
// Child certificate file has been found
}
func CheckFile(path, name string) {
......@@ -66,24 +86,14 @@ func CheckFile(path, name string) {
fmt.Println(name + " file couldn't be found")
} else {
fmt.Println(name + " file has been found")
err = os.Remove(path)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(name + " file has been deleted")
}
}
}
func TestStart(t *testing.T) {
path := os.TempDir()
keyPath := filepath.Join(path, PkeyFileName)
certPath := filepath.Join(path, RootCAFileName)
_ = Initialize(1024, 365, "country", "organization", "unit", "cn", path)
path, _ := ioutil.TempDir("", "")
_ = Initialize(1024, 365, "country", "organization", "unit", "cn", path, nil, nil)
pid, err := Start(path)
if err != nil {
t.Fatal(err)
}
......@@ -91,6 +101,5 @@ func TestStart(t *testing.T) {
t.Fatal("Data was not recovered from saved files")
}
_ = os.Remove(keyPath)
_ = os.Remove(certPath)
_ = os.RemoveAll(path)
}
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"runtime"
"dfss"
dapi "dfss/dfssd/api"
"dfss/dfssp/authority"
"dfss/dfssp/server"
"dfss/net"
"flag"
"fmt"
"os"
"runtime"
)
var (
......@@ -48,7 +50,9 @@ func init() {
fmt.Println("\nThe commands are:")
fmt.Println(" init [cn, country, keySize, org, path, unit, rootValidity]")
fmt.Println(" create and save the platform's private key and root certificate")
fmt.Println(" start [path, db, a, p]")
fmt.Println(" ttp [cn, country, keySize, org, path, unit, certValidity]")
fmt.Println(" create and save the TTP's private key and certificate")
fmt.Println(" start [path, db, a, p, certValidity]")
fmt.Println(" start the platform after loading its private key and root certificate")
fmt.Println(" help print this help")
fmt.Println(" version print dfss client version")
......@@ -69,19 +73,30 @@ func main() {
case "version":
fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH)
case "init":
err := authority.Initialize(keySize, rootValidity, country, org, unit, cn, path)
err := authority.Initialize(keySize, rootValidity, country, org, unit, cn, path, nil, nil)
if err != nil {
fmt.Println("An error occured during the initialization operation:", err)
fmt.Fprintln(os.Stderr, "An error occured during the initialization operation:", err)
os.Exit(1)
}
dapi.DLog("Private key generated !")
dapi.DLog("Private key and root certificate generated")
case "ttp":
pid, err := authority.Start(path)
if err != nil {
fmt.Fprintln(os.Stderr, "Bad root CA or key; please use the `init` command before the `ttp` one.\n", err)
}
ttpPath := filepath.Join(path, "ttp")
err = authority.Initialize(keySize, certValidity, country, org, unit, cn, ttpPath, pid.RootCA, pid.Pkey)
if err != nil {
fmt.Fprintln(os.Stderr, "An error occured during TTP credentials generation:", err)
}
dapi.DLog("Private key and certificate generated for TTP")
case "start":
srv := server.GetServer(path, dbURI, certValidity, verbose)
fmt.Println("Listening on " + address + ":" + port)
dapi.DLog("Platform server started on " + address + ":" + port)
err := net.Listen(address+":"+port, srv)
if err != nil {
fmt.Println(err)
fmt.Fprintln(os.Stderr, err)
}
default:
flag.Usage()
......
package main
import (
"dfss"
dapi "dfss/dfssd/api"
"flag"
"fmt"
"os"
"runtime"
"dfss"
dapi "dfss/dfssd/api"
"dfss/dfsst/server"
"dfss/net"
)
var (
verbose, demo bool
port, address, dbURI string
verbose, demo bool
fca string // Path to the CA
fcert string // Path to the certificate
fkey string // Path to the private key
address string
dbURI string
port string
)
func init() {
flag.BoolVar(&verbose, "v", false, "Print verbose messages")
flag.StringVar(&fca, "ca", "ca.pem", "Path to the root certificate")
flag.StringVar(&fcert, "cert", "cert.pem", "Path to the user certificate")
flag.StringVar(&fkey, "key", "key.pem", "Path to the private key")
flag.BoolVar(&demo, "d", false, "Enable demonstrator")
flag.StringVar(&port, "p", "9010", "Default port listening")
flag.StringVar(&port, "p", "9020", "Default port listening")
flag.StringVar(&address, "a", "0.0.0.0", "Default address to bind for listening")
flag.StringVar(&dbURI, "db", "mongodb://localhost/dfss", "Name of the environment variable containing the server url in standard MongoDB format")
......@@ -31,8 +43,8 @@ func init() {
fmt.Println(" dfssp [flags] command")
fmt.Println("\nThe commands are:")
fmt.Println(" start [db, a, p]")
fmt.Println(" start the TTP service")
fmt.Println(" start start the TTP service")
fmt.Println(" fill the `DFSS_TTP_PASSWORD` environment variable if the private key is enciphered")
fmt.Println(" help print this help")
fmt.Println(" version print dfss protocol version")
......@@ -52,13 +64,16 @@ func main() {
case "version":
fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH)
case "start":
// srv := server.GetServer(dbURI, verbose)
// fmt.Println("Listening on " + address + ":" + port)
// dapi.DLog("TTP server started on " + address + ":" + port)
// err := net.Listen(address+":"+port, srv)
// if err != nil {
// fmt.Println(err)
// }
password := os.Getenv("DFSS_TTP_PASSWORD")
srv := server.GetServer(fca, fcert, fkey, password, dbURI, verbose)
addrPort := address + ":" + port
fmt.Println("Listening on " + addrPort)
dapi.DLog("TTP server started on " + addrPort)
err := net.Listen(addrPort, srv)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
default:
flag.Usage()
}
......
package server
import (
"crypto/rsa"
"crypto/x509"
"dfss/auth"
"dfss/dfsst/api"
"dfss/mgdb"
"dfss/net"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"dfss/dfssc/security"
"dfss/dfsst/api"
"dfss/mgdb"
"dfss/net"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
const (
// PkeyFileName is the private key file default name
PkeyFileName = "dfsst_pkey.pem"
// CertFileName is the certificate file default name
CertFileName = "dfsst_cert.pem"
// RootCAFileName is the root certificate file default name
RootCAFileName = "dfsst_rootca.pem"
)
type ttpServer struct {
PKey *rsa.PrivateKey
Cert *x509.Certificate
RootCA *x509.Certificate
DB *mgdb.MongoManager
CertDuration int
Verbose bool
DB *mgdb.MongoManager
Verbose bool
}
// Alert route for the TTP
......@@ -46,79 +28,25 @@ func (server *ttpServer) Recover(ctx context.Context, in *api.RecoverRequest) (*
}
// GetServer returns the gRPC server
func GetServer(keyPath, db string, certValidity int, verbose bool) *grpc.Server {
server, err := loadCredentials(keyPath)
func GetServer(fca, fcert, fkey, password, db string, verbose bool) *grpc.Server {
auth := security.NewAuthContainer(fca, fcert, fkey, "", password)
ca, cert, key, err := auth.LoadFiles()
if err != nil {
fmt.Fprintln(os.Stderr, "An error occured during the private key and certificates check:", err)
fmt.Fprintln(os.Stderr, "An error occured during the private key and certificates retrieval:", err)
os.Exit(1)
}
dbManager, err := mgdb.NewManager(db)
if err != nil {
fmt.Fprintln(os.Stderr, "An error occured during the connection to MongoDB:", err)
os.Exit(1)
os.Exit(2)
}
server.CertDuration = certValidity
server.Verbose = verbose
server.DB = dbManager
netServer := net.NewServer(server.Cert, server.PKey, server.RootCA)
server := &ttpServer{
Verbose: verbose,
DB: dbManager,
}
netServer := net.NewServer(cert, key, ca)
api.RegisterTTPServer(netServer, server)
return netServer
}
// Assert the private key and certificates are valid
func loadCredentials(path string) (*ttpServer, error) {
keyPath := filepath.Join(path, PkeyFileName)
certPath := filepath.Join(path, CertFileName)
rootCAPath := filepath.Join(path, RootCAFileName)
// Recovering the private rsa key from file.
keyBytes, err := ioutil.ReadFile(keyPath)
if err != nil {
return nil, err
}
key, err := auth.PEMToPrivateKey(keyBytes)
if err != nil {
return nil, err
}
// Recovering the certificate from file.
certBytes, err := ioutil.ReadFile(certPath)
if err != nil {
return nil, err
}
cert, err := auth.PEMToCertificate(certBytes)
if err != nil {
return nil, err
}
// Recovering the root certificate from file.
caBytes, err := ioutil.ReadFile(rootCAPath)
if err != nil {
return nil, err
}
ca, err := auth.PEMToCertificate(caBytes)
if err != nil {
return nil, err
}
res := &ttpServer{
PKey: key,
Cert: cert,
RootCA: ca,
}
return res, nil
}
......@@ -31,10 +31,11 @@ func TestNewContract(t *testing.T) {
// Start the platform
workingDir, err := ioutil.TempDir("", "dfss_")
assert.Equal(t, nil, err)
platform, ca, err := startPlatform(workingDir)
platform, ttp, ca, err := startPlatform(workingDir)
assert.Equal(t, nil, err)
defer func() {
_ = platform.Process.Kill()
_ = ttp.Process.Kill()
_ = os.RemoveAll(workingDir)
}()
......
......@@ -33,10 +33,11 @@ func TestRegisterAuth(t *testing.T) {
// Start the platform
workingDir, err := ioutil.TempDir("", "dfss_")
assert.Equal(t, nil, err)
platform, ca, err := startPlatform(workingDir)
platform, ttp, ca, err := startPlatform(workingDir)
assert.Equal(t, nil, err)
defer func() {
_ = platform.Process.Kill()
_ = ttp.Process.Kill()
_ = os.RemoveAll(workingDir)
}()
......
......@@ -21,10 +21,11 @@ func TestSignContract(t *testing.T) {
// Start the platform
workingDir, err := ioutil.TempDir("", "dfss_")
assert.Equal(t, nil, err)
platform, ca, err := startPlatform(workingDir)
platform, ttp, ca, err := startPlatform(workingDir)
assert.Equal(t, nil, err)
defer func() {
_ = platform.Process.Kill()
_ = ttp.Process.Kill()
_ = os.RemoveAll(workingDir)
}()
......
......@@ -16,36 +16,52 @@ const testPort = "9090"
var currentClient = 0
// startPlatform creates root certificate for the platform and starts the platform.
func startPlatform(tmpDir string) (*exec.Cmd, []byte, error) {
// startPlatform creates root certificate for the platform and the TTP, and starts both modules
func startPlatform(tmpDir string) (platform, ttp *exec.Cmd, ca []byte, err error) {
path := filepath.Join(os.Getenv("GOPATH"), "bin", "dfssp")
ttpPath := filepath.Join(os.Getenv("GOPATH"), "bin", "dfsst")
// Create temporary directory for platform
dir, err := ioutil.TempDir(tmpDir, "p_")
if err != nil {
return nil, nil, err
return
}
// Init
cmd := exec.Command(path, "-path", dir, "-v", "init")
err = cmd.Run()
if err != nil {
return nil, nil, err
return
}
// Get root certificate
ca, err := ioutil.ReadFile(filepath.Join(dir, "dfssp_rootCA.pem"))
// Create TTP working directory
cmd = exec.Command(path, "-path", dir, "-v", "-cn", "ttp", "ttp")
err = cmd.Run()
if err != nil {
return nil, nil, err
return
}
// Start
cmd = exec.Command(path, "-db", dbURI, "-path", dir, "-p", testPort, "-v", "start")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Start()
// Get root certificate
ca, err = ioutil.ReadFile(filepath.Join(dir, "dfssp_rootCA.pem"))
if err != nil {
return
}
return cmd, ca, err
// Start platform
platform = exec.Command(path, "-db", dbURI, "-path", dir, "-p", testPort, "-v", "start")
platform.Stdout = os.Stdout
platform.Stderr = os.Stderr
err = platform.Start()
// Start TTP
ttp = exec.Command(ttpPath, "-db", dbURI, "-p", "9098", "start")
ttp.Dir = filepath.Join(dir, "ttp")
ttp.Stdout = os.Stdout
ttp.Stderr = os.Stderr
_ = ioutil.WriteFile(filepath.Join(ttp.Dir, "ca.pem"), ca, 0600)
err = ttp.Start()
return
}
// createClient creates a new working directory for a client, creating ca.pem.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment