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: ...@@ -22,12 +22,13 @@ You just have to untar the archive and run the following binaries:
```bash ```bash
./dfssc help # Client ./dfssc help # Client
./dfssp help # Platform ./dfssp help # Platform
./dfsst help # TTP
./dfssd help # Demonstrator ./dfssd help # Demonstrator
``` ```
Here is a basic tutorial to setup a new DFSS environment. 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. 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`). 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: ...@@ -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 ./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. 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): Firstly, we have to configure several environment variables to set smtp server configuration (mails):
...@@ -55,6 +63,12 @@ Then: ...@@ -55,6 +63,12 @@ Then:
./dfssp start ./dfssp start
``` ```
You can also start the TTP:
```bash
./dfsst -cert ttp/cert.pem -key ttp/cert.pem start
```
### Setup clients ### Setup clients
Each client needs the `dfssp_rootCA.pem` file in order to connect to the platform in a secure way. 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 ...@@ -3,9 +3,11 @@ package authority
import ( import (
"crypto/rsa" "crypto/rsa"
"crypto/x509" "crypto/x509"
"dfss/auth"
"io/ioutil" "io/ioutil"
"os"
"path/filepath" "path/filepath"
"dfss/auth"
) )
const ( const (
...@@ -21,50 +23,52 @@ type PlatformID struct { ...@@ -21,50 +23,52 @@ type PlatformID struct {
RootCA *x509.Certificate RootCA *x509.Certificate
} }
// GenerateRootCA constructs a self-signed certificate, using a unique serial number randomly generated // Initialize creates and saves the platform's private key and root certificate to a PEM format.
func GenerateRootCA(days int, country, organization, unit, cn string, key *rsa.PrivateKey) ([]byte, error) { // If ca and rKey are not nil, they will be used as the root certificate and root private key instead of creating a ones.
serial := auth.GenerateUID() // 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 {
cert, err := auth.GetSelfSignedCertificate(days, serial, country, organization, unit, cn, key) // Generate the private key.
key, err := auth.GeneratePrivateKey(bits)
if err != nil { 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. if ca == nil {
// // Generate the root certificate, using the private key.
// The files are saved at the specified path. cert, err = auth.GetSelfSignedCertificate(days, auth.GenerateUID(), country, organization, unit, cn, key)
func Initialize(bits, days int, country, organization, unit, cn, path string) error { } else {
// Generating the private key. csr, _ := auth.GetCertificateRequest(country, organization, unit, cn, key)
key, err := auth.GeneratePrivateKey(bits) 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 { if err != nil {
return err return err
} }
// Generating the root certificate, using the private key. // Create missing folders, if needed
cert, err := GenerateRootCA(days, country, organization, unit, cn, key) err = os.MkdirAll(path, os.ModeDir|0700)
if err != nil { if err != nil {
return err 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) keyPem := auth.PrivateKeyToPEM(key)
keyPath := filepath.Join(path, PkeyFileName)
err = ioutil.WriteFile(keyPath, keyPem, 0600) err = ioutil.WriteFile(keyPath, keyPem, 0600)
if err != nil { if err != nil {
return err return err
} }
// Saving the root certificate. // Save the root certificate.
certPath := filepath.Join(path, RootCAFileName)
err = ioutil.WriteFile(certPath, cert, 0600) err = ioutil.WriteFile(certPath, cert, 0600)
if err != nil { if err != nil {
return err return err
} }
...@@ -81,28 +85,24 @@ func Start(path string) (*PlatformID, error) { ...@@ -81,28 +85,24 @@ func Start(path string) (*PlatformID, error) {
keyPath := filepath.Join(path, PkeyFileName) keyPath := filepath.Join(path, PkeyFileName)
certPath := filepath.Join(path, RootCAFileName) certPath := filepath.Join(path, RootCAFileName)
// Recovering the private rsa key from file. // Recover the private rsa key from file.
keyBytes, err := ioutil.ReadFile(keyPath) keyBytes, err := ioutil.ReadFile(keyPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
key, err := auth.PEMToPrivateKey(keyBytes) key, err := auth.PEMToPrivateKey(keyBytes)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Recovering the root certificate from file. // Recover the root certificate from file.
certBytes, err := ioutil.ReadFile(certPath) certBytes, err := ioutil.ReadFile(certPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
cert, err := auth.PEMToCertificate(certBytes) cert, err := auth.PEMToCertificate(certBytes)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -2,11 +2,13 @@ package authority ...@@ -2,11 +2,13 @@ package authority
import ( import (
"crypto/rsa" "crypto/rsa"
"dfss/auth"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"dfss/auth"
) )
var pkey *rsa.PrivateKey var pkey *rsa.PrivateKey
...@@ -17,11 +19,11 @@ func TestMain(m *testing.M) { ...@@ -17,11 +19,11 @@ func TestMain(m *testing.M) {
} }
func TestInitialize(t *testing.T) { func TestInitialize(t *testing.T) {
path := os.TempDir() path, _ := ioutil.TempDir("", "")
keyPath := filepath.Join(path, PkeyFileName) keyPath := filepath.Join(path, PkeyFileName)
certPath := filepath.Join(path, RootCAFileName) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -29,36 +31,54 @@ func TestInitialize(t *testing.T) { ...@@ -29,36 +31,54 @@ func TestInitialize(t *testing.T) {
if _, err = os.Stat(keyPath); os.IsNotExist(err) { if _, err = os.Stat(keyPath); os.IsNotExist(err) {
t.Fatal("Private key file couldn't be found") t.Fatal("Private key file couldn't be found")
} else {
_ = os.Remove(keyPath)
} }
if _, err = os.Stat(certPath); os.IsNotExist(err) { if _, err = os.Stat(certPath); os.IsNotExist(err) {
t.Fatal("Root certificate file couldn't be found") t.Fatal("Root certificate file couldn't be found")
} else {
_ = os.Remove(certPath)
} }
_ = os.RemoveAll(path)
} }
func ExampleInitialize() { func Example() {
path := os.TempDir() path, _ := ioutil.TempDir("", "")
keyPath := filepath.Join(path, PkeyFileName) keyPath := filepath.Join(path, PkeyFileName)
certPath := filepath.Join(path, RootCAFileName) 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 { if err != nil {
fmt.Println(err) fmt.Println(err)
return
} }
CheckFile(keyPath, "Private key") CheckFile(keyPath, "Private key")
CheckFile(certPath, "Certificate") 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: // Output:
// Private key file has been found // Private key file has been found
// Private key file has been deleted
// Certificate file has been found // 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) { func CheckFile(path, name string) {
...@@ -66,24 +86,14 @@ func CheckFile(path, name string) { ...@@ -66,24 +86,14 @@ func CheckFile(path, name string) {
fmt.Println(name + " file couldn't be found") fmt.Println(name + " file couldn't be found")
} else { } else {
fmt.Println(name + " file has been found") 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) { func TestStart(t *testing.T) {
path := os.TempDir() path, _ := ioutil.TempDir("", "")
keyPath := filepath.Join(path, PkeyFileName) _ = Initialize(1024, 365, "country", "organization", "unit", "cn", path, nil, nil)
certPath := filepath.Join(path, RootCAFileName)
_ = Initialize(1024, 365, "country", "organization", "unit", "cn", path)
pid, err := Start(path) pid, err := Start(path)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -91,6 +101,5 @@ func TestStart(t *testing.T) { ...@@ -91,6 +101,5 @@ func TestStart(t *testing.T) {
t.Fatal("Data was not recovered from saved files") t.Fatal("Data was not recovered from saved files")
} }
_ = os.Remove(keyPath) _ = os.RemoveAll(path)
_ = os.Remove(certPath)
} }
package main package main
import ( import (
"flag"
"fmt"
"os"
"path/filepath"
"runtime"
"dfss" "dfss"
dapi "dfss/dfssd/api" dapi "dfss/dfssd/api"
"dfss/dfssp/authority" "dfss/dfssp/authority"
"dfss/dfssp/server" "dfss/dfssp/server"
"dfss/net" "dfss/net"
"flag"
"fmt"
"os"
"runtime"
) )
var ( var (
...@@ -48,7 +50,9 @@ func init() { ...@@ -48,7 +50,9 @@ func init() {
fmt.Println("\nThe commands are:") fmt.Println("\nThe commands are:")
fmt.Println(" init [cn, country, keySize, org, path, unit, rootValidity]") 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(" 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(" start the platform after loading its private key and root certificate")
fmt.Println(" help print this help") fmt.Println(" help print this help")
fmt.Println(" version print dfss client version") fmt.Println(" version print dfss client version")
...@@ -69,19 +73,30 @@ func main() { ...@@ -69,19 +73,30 @@ func main() {
case "version": case "version":
fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH) fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH)
case "init": 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 { 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) 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": case "start":
srv := server.GetServer(path, dbURI, certValidity, verbose) srv := server.GetServer(path, dbURI, certValidity, verbose)
fmt.Println("Listening on " + address + ":" + port) fmt.Println("Listening on " + address + ":" + port)
dapi.DLog("Platform server started on " + address + ":" + port) dapi.DLog("Platform server started on " + address + ":" + port)
err := net.Listen(address+":"+port, srv) err := net.Listen(address+":"+port, srv)
if err != nil { if err != nil {
fmt.Println(err) fmt.Fprintln(os.Stderr, err)
} }
default: default:
flag.Usage() flag.Usage()
......
package main package main
import ( import (
"dfss"
dapi "dfss/dfssd/api"
"flag" "flag"
"fmt" "fmt"
"os"
"runtime" "runtime"
"dfss"
dapi "dfss/dfssd/api"
"dfss/dfsst/server"
"dfss/net"
) )
var ( var (
verbose, demo bool verbose, demo bool
port, address, dbURI string 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() { func init() {
flag.BoolVar(&verbose, "v", false, "Print verbose messages") 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.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(&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") 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() { ...@@ -31,8 +43,8 @@ func init() {
fmt.Println(" dfssp [flags] command") fmt.Println(" dfssp [flags] command")
fmt.Println("\nThe commands are:") fmt.Println("\nThe commands are:")
fmt.Println(" start [db, a, p]") fmt.Println(" start start the TTP service")
fmt.Println(" 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(" help print this help")
fmt.Println(" version print dfss protocol version") fmt.Println(" version print dfss protocol version")
...@@ -52,13 +64,16 @@ func main() { ...@@ -52,13 +64,16 @@ func main() {
case "version": case "version":
fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH) fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH)
case "start": case "start":
// srv := server.GetServer(dbURI, verbose) password := os.Getenv("DFSS_TTP_PASSWORD")
// fmt.Println("Listening on " + address + ":" + port) srv := server.GetServer(fca, fcert, fkey, password, dbURI, verbose)
// dapi.DLog("TTP server started on " + address + ":" + port)
// err := net.Listen(address+":"+port, srv) addrPort := address + ":" + port
// if err != nil { fmt.Println("Listening on " + addrPort)
// fmt.Println(err) dapi.DLog("TTP server started on " + addrPort)
// } err := net.Listen(addrPort, srv)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
default: default:
flag.Usage() flag.Usage()
} }
......
package server package server
import ( import (
"crypto/rsa"
"crypto/x509"
"dfss/auth"
"dfss/dfsst/api"
"dfss/mgdb"
"dfss/net"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath"
"dfss/dfssc/security"
"dfss/dfsst/api"
"dfss/mgdb"
"dfss/net"
"golang.org/x/net/context" "golang.org/x/net/context"
"google.golang.org/grpc" "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