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

[c][t][p] Integrate TTP in signature workflow

This huge commit adds the following features:

- Change default timeout to 5 sec (to be updated soon)
- Don't send TTP information in contract file, but during start signal
- Platform: load and save TTP data from a local file
  New flags: --addr and --ttps
- Platform ttp command: automatically save ttp data in the local file
  (addr and certificate hash are the only values needed by the platform
  and the clients)
- Update integration tests to integrate TTP
parent 7db9f833
Pipeline #1952 passed with stage
......@@ -51,8 +51,13 @@ type Context struct {
ContractDocumentHash []byte `protobuf:"bytes,5,opt,name=contractDocumentHash,proto3" json:"contractDocumentHash,omitempty"`
// / The unique signature attemp ID, as provided by the platform during the ready signal
SignatureUUID string `protobuf:"bytes,6,opt,name=signatureUUID" json:"signatureUUID,omitempty"`
// / The TTP address provided by the platform, to use in case of issue during signature.
// / Empty if no TTP used.
TtpAddrPort string `protobuf:"bytes,7,opt,name=ttpAddrPort" json:"ttpAddrPort,omitempty"`
// / The TTP certificate SHA-512 hash
TtpHash []byte `protobuf:"bytes,8,opt,name=ttpHash,proto3" json:"ttpHash,omitempty"`
// / The signed metadata seal, as provided by the platform during the ready signal
Seal []byte `protobuf:"bytes,7,opt,name=seal,proto3" json:"seal,omitempty"`
Seal []byte `protobuf:"bytes,10,opt,name=seal,proto3" json:"seal,omitempty"`
}
func (m *Context) Reset() { *m = Context{} }
......@@ -262,27 +267,31 @@ var _Client_serviceDesc = grpc.ServiceDesc{
}
var fileDescriptor0 = []byte{
// 348 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x91, 0xcf, 0x4e, 0xea, 0x40,
0x14, 0xc6, 0xe9, 0xe5, 0x4f, 0xe1, 0xdc, 0xc2, 0x25, 0x93, 0x6b, 0x32, 0x41, 0x49, 0x48, 0xe3,
0x82, 0x55, 0x49, 0x70, 0xe9, 0x12, 0x4c, 0x30, 0x6e, 0x4c, 0x94, 0x07, 0x18, 0xa7, 0x07, 0x9d,
0xa4, 0x74, 0xea, 0xcc, 0x60, 0xe0, 0x35, 0x7c, 0x02, 0x1f, 0xd5, 0xe9, 0xa9, 0x45, 0x16, 0x26,
0x6e, 0x9a, 0x9e, 0x6f, 0xbe, 0xf3, 0xf5, 0xf7, 0x75, 0xe0, 0x3c, 0xdd, 0x58, 0x3b, 0x2b, 0x1f,
0x72, 0x26, 0x0a, 0x35, 0x93, 0x99, 0xc2, 0xdc, 0x25, 0x85, 0xd1, 0x4e, 0xb3, 0xa6, 0x57, 0x46,
0xe3, 0xa3, 0xa3, 0x20, 0x47, 0x91, 0x09, 0xb7, 0xd1, 0x66, 0x5b, 0x79, 0xe2, 0x8f, 0x00, 0xc2,
0x85, 0xce, 0x1d, 0xee, 0x1d, 0xe3, 0x30, 0x34, 0x28, 0x55, 0x51, 0x46, 0xdc, 0xe1, 0x61, 0x25,
0xec, 0x0b, 0x0f, 0x26, 0xc1, 0x34, 0x62, 0x67, 0xd0, 0xb7, 0x98, 0xa7, 0x68, 0x6a, 0xf9, 0x0f,
0xc9, 0x43, 0xe8, 0x5a, 0x7c, 0xdd, 0x61, 0x2e, 0x91, 0x37, 0x27, 0xcd, 0x69, 0x9f, 0xfd, 0x83,
0xd0, 0xaa, 0xe7, 0x1c, 0x8d, 0xe5, 0x2d, 0x2f, 0x44, 0xec, 0x02, 0xfe, 0x4b, 0x1f, 0x6f, 0x84,
0x74, 0x4b, 0x2d, 0x77, 0x5b, 0x1f, 0x4d, 0x01, 0xed, 0x63, 0xae, 0xb7, 0x0b, 0xb7, 0x33, 0xb8,
0x5e, 0xdf, 0x2e, 0x79, 0xc7, 0xcb, 0x3d, 0x16, 0x41, 0xcb, 0xa2, 0xc8, 0x78, 0x58, 0x9a, 0xe2,
0x15, 0x84, 0xf7, 0x46, 0x6f, 0x95, 0x45, 0x36, 0x86, 0x50, 0x56, 0xb0, 0x04, 0xf6, 0x77, 0x1e,
0x25, 0xbe, 0x53, 0x52, 0x17, 0xe8, 0x43, 0x5b, 0x79, 0xca, 0x3d, 0xe1, 0x11, 0x4c, 0x21, 0x0e,
0x99, 0x16, 0xa9, 0xa7, 0x2b, 0x93, 0xae, 0xa1, 0xf7, 0x50, 0x7f, 0xee, 0xb7, 0xac, 0x93, 0x65,
0x2a, 0x1b, 0x73, 0x68, 0xaf, 0x30, 0xcb, 0x74, 0x79, 0xf2, 0xe6, 0x0b, 0x2a, 0x9d, 0xd3, 0x62,
0x6f, 0xfe, 0x1e, 0x40, 0x67, 0x41, 0x3f, 0x9e, 0x25, 0x10, 0x3d, 0x1a, 0x14, 0xae, 0x06, 0xae,
0x32, 0xbf, 0xa6, 0xd1, 0x80, 0xa6, 0x1b, 0x63, 0xb4, 0x59, 0xe8, 0x14, 0xe3, 0x06, 0x9b, 0xc3,
0x80, 0xfc, 0xdf, 0x58, 0x95, 0xe7, 0x38, 0xff, 0xb0, 0x73, 0x09, 0xdd, 0xa5, 0xb2, 0x52, 0x7b,
0x08, 0x06, 0x74, 0x4a, 0x5c, 0xa3, 0x93, 0xf7, 0xb8, 0xf1, 0xd4, 0xa1, 0xfb, 0xbd, 0xfa, 0x0c,
0x00, 0x00, 0xff, 0xff, 0x64, 0x27, 0xd3, 0xc2, 0x22, 0x02, 0x00, 0x00,
// 404 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x52, 0xdd, 0xca, 0xda, 0x40,
0x10, 0xf5, 0x3f, 0x3a, 0x46, 0x29, 0x8b, 0x17, 0x21, 0xa5, 0x60, 0x83, 0x14, 0xe9, 0x45, 0x04,
0xfb, 0x04, 0x45, 0x0b, 0x96, 0x52, 0x90, 0xb4, 0x3e, 0xc0, 0x76, 0x33, 0xb6, 0x0b, 0x31, 0x9b,
0xee, 0xae, 0x45, 0x5f, 0xa3, 0xaf, 0xd3, 0x97, 0xeb, 0x66, 0x62, 0xfc, 0x94, 0xcf, 0x8b, 0xef,
0x26, 0xec, 0x39, 0x73, 0x76, 0xce, 0xec, 0xc9, 0xc0, 0xeb, 0x74, 0x6f, 0xcc, 0xa2, 0xfc, 0x88,
0x05, 0x2f, 0xe4, 0x42, 0x64, 0x12, 0x73, 0x1b, 0x17, 0x5a, 0x59, 0xc5, 0xda, 0x8e, 0x09, 0xdf,
0x5c, 0x15, 0x05, 0x29, 0x8a, 0x8c, 0xdb, 0xbd, 0xd2, 0x87, 0x4a, 0x13, 0xfd, 0x6b, 0x81, 0xb7,
0x52, 0xb9, 0xc5, 0x93, 0x65, 0xef, 0xe1, 0x95, 0x46, 0x21, 0x8b, 0xb2, 0xc5, 0x17, 0x3c, 0x6f,
0xb8, 0xf9, 0x15, 0x34, 0xa7, 0xcd, 0xb9, 0x9f, 0x3c, 0xe3, 0xd9, 0x0c, 0x46, 0x06, 0xf3, 0x14,
0x75, 0x2d, 0x6c, 0x91, 0xf0, 0x9e, 0x64, 0x21, 0xf4, 0x0d, 0xfe, 0x3e, 0x62, 0x2e, 0x30, 0x68,
0x4f, 0xdb, 0xf3, 0x51, 0x72, 0xc5, 0x2c, 0x00, 0xcf, 0xc8, 0x9f, 0x39, 0x6a, 0x13, 0x74, 0x5c,
0xc9, 0x4f, 0x6a, 0xc8, 0x96, 0x30, 0x11, 0x6e, 0x24, 0xcd, 0x85, 0x5d, 0x2b, 0x71, 0x3c, 0x38,
0x5b, 0xb2, 0xe8, 0x92, 0xc5, 0xc3, 0x1a, 0xcd, 0xe3, 0xae, 0x73, 0x7b, 0xd4, 0xb8, 0xdb, 0x7d,
0x5e, 0x07, 0x3d, 0x27, 0x1e, 0x24, 0xf7, 0x24, 0x9b, 0xc2, 0xd0, 0xda, 0xe2, 0x63, 0x9a, 0xea,
0xad, 0xd2, 0x36, 0xf0, 0x48, 0x73, 0x4b, 0x95, 0x53, 0x39, 0x48, 0x76, 0x7d, 0xb2, 0xab, 0x21,
0x63, 0xd0, 0x31, 0xc8, 0xb3, 0x00, 0x88, 0xa6, 0x73, 0xc4, 0xc1, 0xdb, 0x6a, 0x75, 0x90, 0x06,
0xd9, 0x3b, 0xf0, 0x44, 0x95, 0x23, 0x65, 0x36, 0x5c, 0xfa, 0xb1, 0x8b, 0x3b, 0xbe, 0x64, 0x9b,
0xd4, 0x45, 0x36, 0x81, 0xae, 0x74, 0x11, 0x9d, 0x28, 0xb0, 0x51, 0x52, 0x81, 0xd2, 0xb6, 0xe0,
0xe7, 0x4c, 0xf1, 0xd4, 0xe5, 0x44, 0xb6, 0x17, 0x18, 0x7d, 0x85, 0xc1, 0xb7, 0xfa, 0x0d, 0x2f,
0x36, 0xb9, 0x69, 0xd7, 0xba, 0x6f, 0xf7, 0x16, 0xba, 0x1b, 0xcc, 0x32, 0x55, 0x4a, 0xfe, 0xb8,
0xb0, 0xa5, 0xca, 0xa9, 0xd5, 0x20, 0xa9, 0xe1, 0xf2, 0x6f, 0x13, 0x7a, 0x2b, 0xda, 0x23, 0x16,
0x83, 0xff, 0x5d, 0x23, 0xb7, 0xf5, 0x23, 0x2b, 0xbb, 0x0b, 0x0a, 0xc7, 0x84, 0x3e, 0x69, 0xad,
0xf4, 0x4a, 0xa5, 0x18, 0x35, 0xdc, 0x9f, 0x1b, 0x93, 0xfe, 0x69, 0xe2, 0x4a, 0x73, 0xc5, 0x0f,
0xee, 0xcc, 0xa0, 0xbf, 0x96, 0x46, 0x28, 0x67, 0xcf, 0x80, 0xaa, 0x34, 0x60, 0x78, 0x73, 0x8e,
0x1a, 0x3f, 0x7a, 0xb4, 0xae, 0x1f, 0xfe, 0x07, 0x00, 0x00, 0xff, 0xff, 0x63, 0xf5, 0x69, 0x69,
0xf1, 0x02, 0x00, 0x00,
}
......@@ -30,8 +30,13 @@ message Context {
bytes contractDocumentHash = 5;
/// The unique signature attemp ID, as provided by the platform during the ready signal
string signatureUUID = 6;
/// The TTP address provided by the platform, to use in case of issue during signature.
/// Empty if no TTP used.
string ttpAddrPort = 7;
/// The TTP certificate SHA-512 hash
bytes ttpHash = 8;
/// The signed metadata seal, as provided by the platform during the ready signal
bytes seal = 7;
bytes seal = 10;
}
message Promise {
......
......@@ -25,6 +25,8 @@ func (m *SignatureManager) createContext(from, to uint32) (*cAPI.Context, error)
Signers: m.keyHash,
ContractDocumentHash: h,
SignatureUUID: m.uuid,
TtpAddrPort: m.ttpData.Addrport,
TtpHash: m.ttpData.Hash,
Seal: m.seal,
}, nil
}
......
......@@ -14,9 +14,9 @@ import (
dAPI "dfss/dfssd/api"
tAPI "dfss/dfsst/api"
"dfss/net"
"github.com/spf13/viper"
"golang.org/x/net/context"
"google.golang.org/grpc"
"github.com/spf13/viper"
)
// Sign performs all the message exchanges for the contract to be signed
......@@ -49,8 +49,10 @@ func (m *SignatureManager) Sign() error {
// Promess rounds
// Follow the sequence until there is no next occurence of me
round := 0
for m.currentIndex >= 0 {
stopIfNeeded(m.currentIndex)
round = round + 1
stopIfNeeded(round)
m.OnProgressUpdate(m.currentIndex, seqLen+1)
time.Sleep(viper.GetDuration("slowdown"))
dAPI.DLog("starting round at index [" + fmt.Sprintf("%d", m.currentIndex) + "] with nextIndex=" + fmt.Sprintf("%d", nextIndex))
......@@ -132,7 +134,7 @@ func (m *SignatureManager) promiseRound(pendingSet, sendSet []common.SequenceCoo
return m.resolve()
}
case <-time.After(time.Minute):
case <-time.After(net.DefaultTimeout):
return m.resolve()
}
}
......@@ -235,16 +237,20 @@ func (m *SignatureManager) callForResolve() (*tAPI.TTPResponse, error) {
// resolve : calls for the resolution, and persists the contract if obtained.
func (m *SignatureManager) resolve() error {
if m.ttp == nil {
dAPI.DLog("unable to contact TTP")
return errors.New("No connection to TTP, aborting!")
}
dAPI.DLog("contacting TTP")
response, err := m.callForResolve()
if err != nil {
return err
}
if response.Abort {
dAPI.DLog("contacted TTP, received abort token")
return nil
}
dAPI.DLog("contacted TTP, received signed contract")
return ioutil.WriteFile(m.mail+"-"+m.contract.UUID+".proof", response.Contract, 0600)
}
......@@ -283,7 +289,7 @@ func stopIfNeeded(index int) {
return
}
if index == -1 && s == -1 || index+1 == s {
if index == -1 && s == -1 || index == s {
os.Exit(0)
}
}
package sign
import (
"crypto/rsa"
"crypto/x509"
"errors"
"fmt"
"strconv"
......@@ -34,6 +32,7 @@ type SignatureManager struct {
platform pAPI.PlatformClient
platformConn *grpc.ClientConn
ttp tAPI.TTPClient
ttpData *pAPI.LaunchSignature_TTP
peersConn map[string]*grpc.ClientConn
peers map[string]*cAPI.ClientClient
hashToID map[string]uint32
......@@ -98,12 +97,6 @@ func NewSignatureManager(passphrase string, c *contract.JSON) (*SignatureManager
m.platform = pAPI.NewPlatformClient(connp)
m.platformConn = connp
// connect to the ttp
connt, err := m.connectToTTP(m.auth.Cert, m.auth.Key, m.auth.CA)
if err == nil {
m.ttp = tAPI.NewTTPClient(connt)
}
m.peersConn = make(map[string]*grpc.ClientConn)
m.peers = make(map[string]*cAPI.ClientClient)
for _, u := range c.Signers {
......@@ -119,17 +112,6 @@ func NewSignatureManager(passphrase string, c *contract.JSON) (*SignatureManager
return m, nil
}
// connectToTTP : tries to open a connection with the ttp specified in the contract.
// If there was no specified ttp, returns an error.
// Otherwise, returns the connection, or an error if something else occured.
func (m *SignatureManager) connectToTTP(cert *x509.Certificate, key *rsa.PrivateKey, ca *x509.Certificate) (*grpc.ClientConn, error) {
if m.contract.TTP == nil {
return nil, errors.New("No specified ttp in contract")
}
addrPort := m.contract.TTP.IP + ":" + string(m.contract.TTP.Port)
return net.Connect(addrPort, cert, key, ca, nil)
}
// ConnectToPeers tries to fetch the list of users for this contract, and tries to establish a connection to each peer.
func (m *SignatureManager) ConnectToPeers() error {
localIps, err := net.ExternalInterfaceAddr()
......@@ -299,6 +281,9 @@ func (m *SignatureManager) SendReadySign() (signatureUUID string, err error) {
}
}
// Connect to TTP, if any
err = m.connectToTTP(launch.Ttp)
m.sequence = launch.Sequence
m.uuid = launch.SignatureUuid
m.keyHash = launch.KeyHash
......@@ -307,6 +292,27 @@ func (m *SignatureManager) SendReadySign() (signatureUUID string, err error) {
return
}
// connectToTTP : tries to open a connection with the ttp specified in the contract.
func (m *SignatureManager) connectToTTP(ttp *pAPI.LaunchSignature_TTP) error {
if ttp == nil {
m.ttpData = &pAPI.LaunchSignature_TTP{
Addrport: "",
Hash: []byte{},
}
return nil
}
// TODO check that the connection spots missing TTP and returns an error quickly enough
conn, err := net.Connect(ttp.Addrport, m.auth.Cert, m.auth.Key, m.auth.CA, ttp.Hash)
if err != nil {
return err
}
m.ttpData = ttp
m.ttp = tAPI.NewTTPClient(conn)
return nil
}
// Initialize computes the values needed for the start of the signing
func (m *SignatureManager) Initialize() (int, error) {
myID, err := m.FindID()
......
......@@ -135,15 +135,16 @@ var _Demonstrator_serviceDesc = grpc.ServiceDesc{
}
var fileDescriptor0 = []byte{
// 159 bytes of a gzipped FileDescriptorProto
// 167 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x4c, 0x49, 0x2b, 0x2e,
0xd6, 0x07, 0x11, 0x29, 0xfa, 0x89, 0x05, 0x99, 0xfa, 0x29, 0xa9, 0xb9, 0xf9, 0x79, 0xc5, 0x25,
0x45, 0x89, 0x25, 0xf9, 0x45, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xcc, 0x40, 0x71, 0x25,
0x4b, 0x2e, 0x66, 0x9f, 0xfc, 0x74, 0x21, 0x41, 0x2e, 0xce, 0x92, 0xcc, 0xdc, 0xd4, 0xe2, 0x92,
0xc4, 0xdc, 0x02, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x66, 0x21, 0x21, 0x2e, 0xae, 0xcc, 0x94, 0xd4,
0xbc, 0x92, 0xcc, 0xb4, 0xcc, 0xd4, 0x22, 0x09, 0x26, 0xa0, 0x18, 0xa7, 0x10, 0x37, 0x17, 0x73,
0x4e, 0x7e, 0xba, 0x04, 0x33, 0x88, 0xa3, 0xc4, 0xca, 0xc5, 0xec, 0x98, 0x9c, 0x6d, 0xa4, 0xcf,
0xc5, 0xe3, 0x82, 0x64, 0xb8, 0x90, 0x3c, 0x17, 0x7b, 0x70, 0x6a, 0x5e, 0x0a, 0xc8, 0x54, 0x0e,
0x3d, 0xa0, 0x15, 0x7a, 0x40, 0x96, 0x14, 0x84, 0x05, 0x54, 0xae, 0xc4, 0x90, 0xc4, 0x06, 0xb6,
0xde, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x16, 0xf4, 0xd0, 0x37, 0xa3, 0x00, 0x00, 0x00,
0x45, 0x89, 0x25, 0xf9, 0x45, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xcc, 0x40, 0x71, 0xa5,
0x50, 0x2e, 0x66, 0x9f, 0xfc, 0x74, 0x21, 0x19, 0x2e, 0xce, 0x92, 0xcc, 0xdc, 0xd4, 0xe2, 0x92,
0xc4, 0xdc, 0x02, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xe6, 0x20, 0x84, 0x80, 0x90, 0x1c, 0x17, 0x57,
0x66, 0x4a, 0x6a, 0x5e, 0x49, 0x66, 0x5a, 0x66, 0x6a, 0x91, 0x04, 0x13, 0x50, 0x9a, 0x33, 0x08,
0x49, 0x44, 0x48, 0x80, 0x8b, 0x39, 0x27, 0x3f, 0x5d, 0x82, 0x19, 0x2c, 0x01, 0x62, 0x2a, 0xb1,
0x72, 0x31, 0x3b, 0x26, 0x67, 0x1b, 0xe9, 0x73, 0xf1, 0xb8, 0x20, 0x59, 0x2c, 0x24, 0xcf, 0xc5,
0x1e, 0x9c, 0x9a, 0x97, 0x02, 0xb2, 0x91, 0x43, 0x0f, 0x68, 0xbd, 0x1e, 0x90, 0x25, 0x05, 0x61,
0x01, 0x95, 0x2b, 0x31, 0x24, 0xb1, 0x81, 0x9d, 0x66, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xc3,
0xc3, 0x86, 0x7b, 0xbf, 0x00, 0x00, 0x00,
}
This diff is collapsed.
......@@ -144,8 +144,15 @@ message LaunchSignature {
repeated bytes keyHash = 4;
/// The signing sequence generated on-the-fly by the platform
repeated uint32 sequence = 5;
/// TTP is the ttp associated to this signature, that should be contacted in case of error
message TTP {
string addrport = 1;
bytes hash = 2;
}
/// The ttp can be nil if no ttp is available for this signature
TTP ttp = 6;
/// The cryptographic object of the signature of this structure (seal and errorCode excepted) by the platform, for data certification.
/// The signature is computed using auth.SignStructure function:
/// PKCS1v15 + SHA512 hash of the string representation of the structure
bytes seal = 6;
bytes seal = 10;
}
......@@ -22,12 +22,13 @@ type PlatformID struct {
// 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 by viper.
func Initialize(v *viper.Viper, ca *x509.Certificate, rKey *rsa.PrivateKey) error {
// The returned `hash` is the SHA-512 hash of the generated certificate.
func Initialize(v *viper.Viper, ca *x509.Certificate, rKey *rsa.PrivateKey) (hash []byte, err error) {
// Generate the private key.
key, err := auth.GeneratePrivateKey(v.GetInt("key_size"))
if err != nil {
return err
return nil, err
}
var cert []byte
......@@ -50,24 +51,25 @@ func Initialize(v *viper.Viper, ca *x509.Certificate, rKey *rsa.PrivateKey) erro
}
if err != nil {
return err
return nil, err
}
// Create missing folders, if needed
err = os.MkdirAll(path, os.ModeDir|0700)
if err != nil {
return err
return nil, err
}
// Convert the private key to a PEM format, and save it.
keyPem := auth.PrivateKeyToPEM(key)
err = ioutil.WriteFile(keyPath, keyPem, 0600)
if err != nil {
return err
return nil, err
}
// Save the root certificate.
return ioutil.WriteFile(certPath, cert, 0600)
rawCert, _ := auth.PEMToCertificate(cert) // TODO optimize this...
return auth.GetCertificateHash(rawCert), ioutil.WriteFile(certPath, cert, 0600)
}
// Start fetches the platform's private rsa key and root certificate, and create a PlatformID accordingly.
......
......@@ -8,10 +8,9 @@ import (
"path/filepath"
"testing"
"github.com/spf13/viper"
"dfss/auth"
"dfss/dfssc/common"
"github.com/spf13/viper"
)
var (
......@@ -36,9 +35,9 @@ func TestInitialize(t *testing.T) {
certPath := filepath.Join(path, RootCAFileName)
v := common.MockViper("key_size", 1024, "validity", 365, "country", "country", "organization", "organization", "unit", "unit", "cn", "cn", "path", path)
err := Initialize(v, nil, nil)
hash, err := Initialize(v, nil, nil)
if err != nil {
if err != nil || hash == nil {
t.Fatal(err)
}
......@@ -60,8 +59,8 @@ func Example() {
// Generate root certificate and key
v := common.MockViper("key_size", 1024, "validity", 365, "country", "UK", "organization", "DFSS", "unit", "unit", "cn", "ROOT", "path", path)
err := Initialize(v, nil, nil)
if err != nil {
hash, err := Initialize(v, nil, nil)
if err != nil || hash == nil {
fmt.Println(err)
return
}
......@@ -79,7 +78,7 @@ func Example() {
// Generate child certificate and key
childPath := filepath.Join(path, "child")
v = common.MockViper("key_size", 1024, "validity", 10, "country", "FR", "organization", "DFSS", "unit", "unit", "cn", "CHILD", "path", childPath)
err = Initialize(v, pid.RootCA, pid.Pkey)
_, err = Initialize(v, pid.RootCA, pid.Pkey)
if err != nil {
fmt.Println(err)
return
......@@ -107,7 +106,7 @@ func CheckFile(path, name string) {
func TestStart(t *testing.T) {
path, _ := ioutil.TempDir("", "")
v := common.MockViper("key_size", 1024, "validity", 365, "country", "country", "organization", "organization", "unit", "unit", "cn", "cn", "path", path)
_ = Initialize(v, nil, nil)
_, _ = Initialize(v, nil, nil)
pid, err := Start(path)
if err != nil {
......
1.2.3.4:9005 aabbcc
192.168.1.1:36500 0123456789
package authority
import (
"encoding/hex"
"errors"
"io/ioutil"
"strconv"
"strings"
"sync"
"dfss/dfssp/api"
)
// TTPHolder stores available TTPs (trusted third parties)
type TTPHolder struct {
ttps []*api.LaunchSignature_TTP
next int
mutex *sync.Mutex
}
// NewTTPHolder loads available TTPs from the specified file.
// The format of this file should be as-is:
//
// <addr ttp 1>[:<port ttp 1] <SHA-512 hash of the ttp certificate (hex format)>\n
// ...
//
// Example: see testdata/ttps.
// If an error occurs during the retrieval of the file, an empty TTPHolder will be provided.
// If the file is corrupted (wrong format), and error will be thrown.
func NewTTPHolder(filename string) (*TTPHolder, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
data = []byte{}
}
lines := strings.Split(string(data), "\n")
ttps := make([]*api.LaunchSignature_TTP, len(lines)-1) // -1 to ignore last string (empty)
for i := 0; i < len(lines)-1; i++ {
line := lines[i]
words := strings.Split(line, " ")
if len(words) < 2 {
return nil, errors.New("corrupted ttp file: not enough words at line " + strconv.Itoa(i))
}
hash, err := hex.DecodeString(words[1])
if err != nil {
return nil, errors.New("corrupted ttp file: invalid hash at line " + strconv.Itoa(i))
}
ttps[i] = &api.LaunchSignature_TTP{
Addrport: words[0],
Hash: hash,
}
}
holder := &TTPHolder{
ttps: ttps,
next: 0,
mutex: &sync.Mutex{},
}
return holder, nil
}
// Nb returns the number of loaded TTP in this holder.
func (h *TTPHolder) Nb() int {
return len(h.ttps)
}
// Get returns a TTP from the TTP holder.
// It is thread-safe, and base on a round-robin system.
//
// If the TTPHolder is empty, returns nil.
func (h *TTPHolder) Get() *api.LaunchSignature_TTP {
if h.Nb() == 0 {
return nil
}
h.mutex.Lock()
defer h.mutex.Unlock()
if len(h.ttps) == h.next {
h.next = 0
}
ttp := h.ttps[h.next]
h.next++
return ttp
}
// Add adds the provided TTP to the TTP holder.
// It is thread-safe.
func (h *TTPHolder) Add(addrport string, hash []byte) {
h.mutex.Lock()
defer h.mutex.Unlock()
h.ttps = append(h.ttps, &api.LaunchSignature_TTP{
Addrport: addrport,
Hash: hash,
})
}
// Save saves the TTP holder in a file, respecting the same format as presented in the loader.
func (h *TTPHolder) Save(filename string) error {
data := ""
for _, ttp := range h.ttps {
data += ttp.Addrport + " " + hex.EncodeToString(ttp.Hash) + "\n"
}
return ioutil.WriteFile(filename, []byte(data), 0600)
}
package authority
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestTTPHolderNewFile(t *testing.T) {
// Load from a missing file
holder, err := NewTTPHolder("holder")
assert.NotNil(t, holder)
assert.Nil(t, err)
ttp := holder.Get()
assert.Nil(t, ttp)
assert.Equal(t, 0, holder.Nb())
holder.Add("1.2.3.4", []byte{0x01, 0xff})
holder.Add("localhost:9000", []byte{0xaa})
assert.Equal(t, 2, holder.Nb())
err = holder.Save("holder")
assert.Nil(t, err)
res, _ := ioutil.ReadFile("holder")
assert.Equal(t, "1.2.3.4 01ff\nlocalhost:9000 aa\n", fmt.Sprintf("%s", res))
_ = os.Remove("holder")
}
func TestTTPHolderRetrieveFile(t *testing.T) {
holder, err := NewTTPHolder(filepath.Join("testdata", "ttps"))
assert.NotNil(t, holder)
assert.Nil(t, err)
assert.Equal(t, 2, holder.Nb())
ttp := holder.Get()
assert.NotNil(t, ttp)
assert.Equal(t, "1.2.3.4:9005", ttp.Addrport)
assert.Equal(t, "aabbcc", fmt.Sprintf("%x", ttp.Hash))
ttp = holder.Get()
assert.NotNil(t, ttp)
assert.Equal(t, "192.168.1.1:36500", ttp.Addrport)
assert.Equal(t, "0123456789", fmt.Sprintf("%x", ttp.Hash))
ttp = holder.Get()
assert.NotNil(t, ttp)
assert.Equal(t, "1.2.3.4:9005", ttp.Addrport)
assert.Equal(t, "aabbcc", fmt.Sprintf("%x", ttp.Hash))
}
func TestTTPHolderRetrieveCorruptedFile(t *testing.T) {
holder, err := NewTTPHolder(filepath.Join("testdata", "corrupted_ttps"))
assert.Nil(t, holder)
assert.NotNil(t, err)
}
......@@ -5,7 +5,6 @@ import (
"os"
"dfss/dfssc/common"
dapi "dfss/dfssd/api"
"dfss/dfssp/authority"
"github.com/spf13/cobra"
"github.com/spf13/viper"
......@@ -23,11 +22,10 @@ var initCmd = &cobra.Command{
_ = viper.BindPFlag("unit", cmd.Flags().Lookup("unit"))
_ = viper.BindPFlag("key_size", cmd.Flags().Lookup("key"))
err := authority.Initialize(common.SubViper("key_size", "validity", "country", "organization", "unit", "cn", "path"), nil, nil)
_, err := authority.Initialize(common.SubViper("key_size", "validity", "country", "organization", "unit", "cn", "path"), nil, nil)
if err != nil {
fmt.Fprintln(os.Stderr, "An error occured during the initialization operation:", err)
os.Exit(1)
}
dapi.DLog("Private key and root certificate generated")
},
}
......@@ -46,11 +46,14 @@ func init() {
ttpCmd.Flags().String("org", "DFSS", "organization for the ttp certificate")
ttpCmd.Flags().String("unit", "INSA Rennes", "organizational unit for the ttp certificate")
ttpCmd.Flags().IntP("key", "k", 2048, "encoding size for the private key of the ttp")
ttpCmd.Flags().StringP("ttps", "t", "ttps", "file containing available TTPs list")
ttpCmd.Flags().StringP("addr", "a", "localhost:9098", "address of the ttp to be transmitted to signers")
startCmd.Flags().IntP("validity", "c", 365, "validity duration for the child certificates (days)")
startCmd.Flags().StringP("address", "a", "0.0.0.0", "address to bind for listening")
startCmd.Flags().StringP("port", "p", "9000", "port to bind for listening")
startCmd.Flags().String("db", "mongodb://localhost/dfss", "server url in standard MongoDB format for accessing database")
startCmd.Flags().StringP("ttps", "t", "", "file containing available TTPs list, disabled by default")
// Bind viper to flags
_ = viper.BindPFlag("verbose", RootCmd.PersistentFlags().Lookup("verbose"))
......
......@@ -20,6 +20,7 @@ var startCmd = &cobra.Command{
_ = viper.BindPFlag("address", cmd.Flags().Lookup("address"))
_ = viper.BindPFlag("port", cmd.Flags().Lookup("port"))
_ = viper.BindPFlag("validity", cmd.Flags().Lookup("validity"))
_ = viper.BindPFlag("ttps", cmd.Flags().Lookup("ttps"))
address := viper.GetString("address")
port := viper.GetString("port")
......
......@@ -6,7 +6,6 @@ import (
"path/filepath"
"dfss/dfssc/common"
dapi "dfss/dfssd/api"
"dfss/dfssp/authority"
"github.com/spf13/cobra"
"github.com/spf13/viper"
......@@ -15,6 +14,19 @@ import (
var ttpCmd = &cobra.Command{
Use: "ttp",
Short: "create and save the TTP's private key and certificate",
Long: `This command creates a new private key and a related certificate for a Trusted Third Party (TTP).
You must run the init command before this one in order to compute root certificate.
TTP credentials are saved in the ttp folder. You may want to move this folder in another secure place.
In order to provide one TTP per signature, a list must be stored for the platform.
This list is generated and updated with the ttp command, along with the future TTP address and port.
If no list is provided, no TTP will be proposed to signers, and they won't be able to use the resolution protocol.
You can customize the list location and the TTP address with "-t" and "-a" flags.
For example, to setup a TTP that will run on ttp.example.com:3000
dfssp ttp -t ttp.example.com:3000 -a storefile.data
You can setup as many TTPs as you want, but beware certificate and private key are erased between each call of this command.`,
Run: func(cmd *cobra.Command, args []string) {
_ = viper.BindPFlag("cn", cmd.Flags().Lookup("cn"))
......@@ -23,6 +35,8 @@ var ttpCmd = &cobra.Command{
_ = viper.BindPFlag("organization", cmd.Flags().Lookup("org"))
_ = viper.BindPFlag("unit", cmd.Flags().Lookup("unit"))
_ = viper.BindPFlag("key_size", cmd.Flags().Lookup("key"))
_ = viper.BindPFlag("ttps", cmd.Flags().Lookup("ttps"))
_ = viper.BindPFlag("ttp_addr", cmd.Flags().Lookup("addr"))
path := viper.GetString("path")
......@@ -34,11 +48,24 @@ var ttpCmd = &cobra.Command{
ttpPath := filepath.Join(path, "ttp")
v := common.SubViper("key_size", "validity", "country", "organization", "unit", "cn")
v.Set("path", ttpPath)
err = authority.Initialize(v, pid.RootCA, pid.Pkey)
hash, err := authority.Initialize(v, pid.RootCA, pid.Pkey)
if err != nil {
fmt.Fprintln(os.Stderr, "An error occured during TTP credentials generation:", err)
os.Exit(1)
}
dapi.DLog("Private key and certificate generated for TTP")
// Add this ttp to the ttp holder
holder, err := authority.NewTTPHolder(viper.GetString("ttps"))
if err != nil {
fmt.Fprintln(os.Stderr, "An error occured during TTP list load:", err)
os.Exit(1)
}
holder.Add(viper.GetString("ttp_addr"), hash)
err = holder.Save(viper.GetString("ttps"))
if err != nil {
fmt.Fprintln(os.Stderr, "An error occured during TTP list save:", err)
os.Exit(1)
}
},
}
......@@ -152,7 +152,7 @@ func (c *Builder) SendNewContractMail() {
return
}
file, err := GetJSON(c.Contract, nil)
file, err := GetJSON(c.Contract)
if err != nil {
log.Println(err)
return
......
......@@ -23,7 +23,7 @@ func Fetch(db *mgdb.MongoManager, contractUUID string, clientHash []byte) *api.C
}
}
data, err := GetJSON(contract, nil)
data, err := GetJSON(contract)
if err != nil {
return &api.Contract{
ErrorCode: &api.ErrorCode{Code: api.ErrorCode_INTERR},
......
......@@ -21,12 +21,6 @@ type SignerJSON struct {