From e520505e0dc3bf0deea07ef8402ddc36292b1f7b Mon Sep 17 00:00:00 2001 From: Lesterpig Date: Sat, 21 May 2016 16:43:03 +0200 Subject: [PATCH] [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 --- dfssc/api/client.pb.go | 57 +++++++----- dfssc/api/client.proto | 7 +- dfssc/sign/promises.go | 2 + dfssc/sign/protocol.go | 16 ++-- dfssc/sign/starter.go | 44 +++++---- dfssd/api/demonstrator.pb.go | 19 ++-- dfssp/api/platform.pb.go | 115 +++++++++++++++--------- dfssp/api/platform.proto | 9 +- dfssp/authority/rootCA.go | 14 +-- dfssp/authority/rootCA_test.go | 15 ++-- dfssp/authority/testdata/corrupted_ttps | 1 + dfssp/authority/testdata/ttps | 2 + dfssp/authority/ttp.go | 108 ++++++++++++++++++++++ dfssp/authority/ttp_test.go | 62 +++++++++++++ dfssp/cmd/init.go | 4 +- dfssp/cmd/root.go | 3 + dfssp/cmd/start.go | 1 + dfssp/cmd/ttp.go | 33 ++++++- dfssp/contract/create.go | 2 +- dfssp/contract/fetch.go | 2 +- dfssp/contract/file.go | 10 +-- dfssp/contract/file_test.go | 5 +- dfssp/server/server.go | 12 +++ dfsst/entities/check_request.go | 8 ++ dfsst/server/server.go | 4 + net/client.go | 2 +- net/fixtures/test.pb.go | 19 ++-- tests/sign_test.go | 78 +++++++++++----- tests/starters_test.go | 7 +- 29 files changed, 491 insertions(+), 170 deletions(-) create mode 100644 dfssp/authority/testdata/corrupted_ttps create mode 100644 dfssp/authority/testdata/ttps create mode 100644 dfssp/authority/ttp.go create mode 100644 dfssp/authority/ttp_test.go diff --git a/dfssc/api/client.pb.go b/dfssc/api/client.pb.go index ecc04ef..6eb40be 100644 --- a/dfssc/api/client.pb.go +++ b/dfssc/api/client.pb.go @@ -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, } diff --git a/dfssc/api/client.proto b/dfssc/api/client.proto index 79b5382..d2c4854 100644 --- a/dfssc/api/client.proto +++ b/dfssc/api/client.proto @@ -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 { diff --git a/dfssc/sign/promises.go b/dfssc/sign/promises.go index e5d3559..9144921 100644 --- a/dfssc/sign/promises.go +++ b/dfssc/sign/promises.go @@ -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 } diff --git a/dfssc/sign/protocol.go b/dfssc/sign/protocol.go index 3c7a52f..167ad23 100644 --- a/dfssc/sign/protocol.go +++ b/dfssc/sign/protocol.go @@ -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) } -} \ No newline at end of file +} diff --git a/dfssc/sign/starter.go b/dfssc/sign/starter.go index 49b2102..af22804 100644 --- a/dfssc/sign/starter.go +++ b/dfssc/sign/starter.go @@ -1,8 +1,6 @@ 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() diff --git a/dfssd/api/demonstrator.pb.go b/dfssd/api/demonstrator.pb.go index b67de87..bb771ef 100644 --- a/dfssd/api/demonstrator.pb.go +++ b/dfssd/api/demonstrator.pb.go @@ -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, } diff --git a/dfssp/api/platform.pb.go b/dfssp/api/platform.pb.go index 9742fe9..3e124bb 100644 --- a/dfssp/api/platform.pb.go +++ b/dfssp/api/platform.pb.go @@ -269,10 +269,12 @@ type LaunchSignature struct { KeyHash [][]byte `protobuf:"bytes,4,rep,name=keyHash,proto3" json:"keyHash,omitempty"` // / The signing sequence generated on-the-fly by the platform Sequence []uint32 `protobuf:"varint,5,rep,name=sequence" json:"sequence,omitempty"` + // / The ttp can be nil if no ttp is available for this signature + Ttp *LaunchSignature_TTP `protobuf:"bytes,6,opt,name=ttp" json:"ttp,omitempty"` // / 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 - Seal []byte `protobuf:"bytes,6,opt,name=seal,proto3" json:"seal,omitempty"` + Seal []byte `protobuf:"bytes,10,opt,name=seal,proto3" json:"seal,omitempty"` } func (m *LaunchSignature) Reset() { *m = LaunchSignature{} } @@ -287,6 +289,24 @@ func (m *LaunchSignature) GetErrorCode() *ErrorCode { return nil } +func (m *LaunchSignature) GetTtp() *LaunchSignature_TTP { + if m != nil { + return m.Ttp + } + return nil +} + +// / TTP is the ttp associated to this signature, that should be contacted in case of error +type LaunchSignature_TTP struct { + Addrport string `protobuf:"bytes,1,opt,name=addrport" json:"addrport,omitempty"` + Hash []byte `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (m *LaunchSignature_TTP) Reset() { *m = LaunchSignature_TTP{} } +func (m *LaunchSignature_TTP) String() string { return proto.CompactTextString(m) } +func (*LaunchSignature_TTP) ProtoMessage() {} +func (*LaunchSignature_TTP) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12, 0} } + func init() { proto.RegisterType((*RegisterRequest)(nil), "api.RegisterRequest") proto.RegisterType((*ErrorCode)(nil), "api.ErrorCode") @@ -301,6 +321,7 @@ func init() { proto.RegisterType((*User)(nil), "api.User") proto.RegisterType((*ReadySignRequest)(nil), "api.ReadySignRequest") proto.RegisterType((*LaunchSignature)(nil), "api.LaunchSignature") + proto.RegisterType((*LaunchSignature_TTP)(nil), "api.LaunchSignature.TTP") proto.RegisterEnum("api.ErrorCode_Code", ErrorCode_Code_name, ErrorCode_Code_value) } @@ -622,47 +643,53 @@ var _Platform_serviceDesc = grpc.ServiceDesc{ } var fileDescriptor0 = []byte{ - // 666 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x54, 0x5d, 0x6f, 0xda, 0x4a, - 0x10, 0xc5, 0xc1, 0xe1, 0x63, 0xc0, 0xc4, 0x5a, 0x88, 0xe2, 0x8b, 0x74, 0xa5, 0xdc, 0xd5, 0x7d, - 0x88, 0xee, 0x95, 0xa0, 0xa5, 0x0f, 0x95, 0xda, 0x97, 0x12, 0x4a, 0x93, 0x54, 0x6d, 0x1a, 0x19, - 0x48, 0x9f, 0x5d, 0x7b, 0x13, 0xdc, 0x60, 0xaf, 0xbb, 0xbb, 0x7e, 0xc8, 0xbf, 0xa8, 0xfa, 0x1f, - 0xfa, 0x37, 0xdb, 0xee, 0xae, 0x3f, 0x0a, 0x94, 0x56, 0xe1, 0x01, 0xb4, 0x3b, 0x33, 0x67, 0xce, - 0x9c, 0x3d, 0x03, 0xfc, 0x1d, 0xdc, 0x70, 0x3e, 0x54, 0x5f, 0xc9, 0xd0, 0x4b, 0xc2, 0x61, 0xb2, - 0xf2, 0xc4, 0x0d, 0x65, 0xd1, 0x20, 0x61, 0x54, 0x50, 0x54, 0x95, 0x77, 0xf8, 0x31, 0x1c, 0xb8, - 0xe4, 0x36, 0xe4, 0x82, 0x30, 0x97, 0x7c, 0x4a, 0x09, 0x17, 0xc8, 0x82, 0x7d, 0x12, 0x79, 0xe1, - 0xca, 0x31, 0x8e, 0x8d, 0x93, 0x26, 0x3a, 0x80, 0x3a, 0xcb, 0x22, 0xce, 0x9e, 0xba, 0xc0, 0x5f, - 0x0d, 0x68, 0x4e, 0x19, 0xa3, 0x6c, 0x42, 0x03, 0x82, 0xfe, 0x01, 0xd3, 0x97, 0xbf, 0x3a, 0xb9, - 0x33, 0xea, 0x0e, 0x24, 0xe8, 0xa0, 0x8c, 0x0e, 0x74, 0x8a, 0x44, 0x88, 0x08, 0xe7, 0xde, 0x2d, - 0xc9, 0x11, 0x02, 0x30, 0x75, 0xa0, 0x05, 0xf5, 0xd9, 0x62, 0x32, 0x99, 0xce, 0x66, 0x76, 0x05, - 0x01, 0xd4, 0x2e, 0x2e, 0xaf, 0xc7, 0xee, 0x99, 0x6d, 0xa8, 0xc0, 0xe9, 0xf8, 0xe5, 0x78, 0x31, - 0x3f, 0xb7, 0xf7, 0xd4, 0xe1, 0xfd, 0xd8, 0xbd, 0xbc, 0xb8, 0x3c, 0xb3, 0xab, 0xa8, 0xab, 0xb2, - 0xe6, 0x53, 0xd7, 0xb5, 0xbf, 0x17, 0x1f, 0x03, 0xf5, 0xa0, 0x3e, 0xbf, 0x78, 0x3b, 0x7d, 0xb7, - 0x98, 0xdb, 0xdf, 0xca, 0x5b, 0xfc, 0x3f, 0xb4, 0xc6, 0xa9, 0x58, 0xfe, 0x66, 0x2c, 0x79, 0x14, - 0xf4, 0x8e, 0xc4, 0x39, 0xa5, 0x7f, 0xa1, 0x53, 0xe8, 0x40, 0x82, 0x05, 0x27, 0x0c, 0x49, 0x42, - 0xfe, 0x2a, 0x24, 0xb1, 0x98, 0x10, 0x26, 0xb2, 0x22, 0x5c, 0x87, 0xfd, 0x69, 0x94, 0x88, 0x7b, - 0x7c, 0x0d, 0xdd, 0x2b, 0xca, 0xc5, 0x84, 0xc6, 0x82, 0x79, 0xbe, 0x28, 0x7a, 0xb4, 0xc1, 0x5c, - 0x7a, 0x7c, 0xa9, 0xb3, 0xdb, 0xc8, 0x86, 0xc6, 0x4d, 0xb8, 0x22, 0xb1, 0x17, 0xe5, 0x83, 0xa3, - 0x0e, 0xd4, 0x78, 0x78, 0x1b, 0x13, 0xe6, 0x54, 0x8f, 0xab, 0x99, 0xb6, 0x3e, 0x8d, 0x22, 0xd9, - 0xc4, 0x31, 0x75, 0x03, 0x0c, 0xe8, 0x8c, 0xec, 0x82, 0x4d, 0xd3, 0x30, 0xc8, 0x49, 0x3c, 0x87, - 0x46, 0x91, 0x20, 0xd5, 0x6f, 0x92, 0x42, 0x6c, 0x1d, 0x6e, 0x8d, 0x3a, 0x9b, 0x4f, 0xa0, 0x8a, - 0x3f, 0x72, 0x9a, 0xcd, 0xd9, 0xc6, 0xaf, 0xa0, 0xf7, 0x9a, 0x86, 0xf1, 0x4c, 0xb2, 0xf0, 0x44, - 0xca, 0x48, 0xd1, 0xa2, 0x07, 0x6d, 0x3f, 0x07, 0x5d, 0x94, 0xad, 0x54, 0x6d, 0x42, 0x59, 0xf6, - 0xf0, 0x96, 0x14, 0x64, 0x2f, 0x4c, 0x32, 0xe6, 0xd8, 0x03, 0x4b, 0xa9, 0x24, 0x89, 0xc4, 0xc4, - 0x17, 0x24, 0x78, 0x08, 0x93, 0xed, 0x1e, 0x99, 0x26, 0x47, 0x72, 0x38, 0xae, 0x15, 0x51, 0x35, - 0x4d, 0x5d, 0xa3, 0xa0, 0xf1, 0x0b, 0x30, 0xf5, 0x43, 0x48, 0x91, 0xee, 0xc8, 0xfd, 0xf9, 0x4f, - 0x5d, 0xcb, 0x97, 0xcc, 0x00, 0xd6, 0x68, 0x95, 0x84, 0x95, 0x9a, 0x16, 0x3e, 0x01, 0xdb, 0x25, - 0x5e, 0x70, 0xaf, 0xa6, 0xfd, 0xe3, 0xa0, 0xf8, 0x8b, 0x01, 0x07, 0x6f, 0xbc, 0x34, 0xf6, 0x97, - 0xa5, 0x32, 0x0f, 0x99, 0xe8, 0x10, 0x2c, 0x5e, 0xe4, 0xaf, 0x8d, 0x24, 0x7b, 0x04, 0xd4, 0x4f, - 0xd5, 0xbb, 0x6a, 0xda, 0x55, 0x4d, 0x7b, 0x6d, 0x0e, 0x53, 0x92, 0xd5, 0xfe, 0xe0, 0x8a, 0x55, - 0xec, 0x13, 0x67, 0x5f, 0xde, 0x58, 0x8a, 0x3e, 0x27, 0xde, 0xca, 0xa9, 0xa9, 0x82, 0xd1, 0xe7, - 0x2a, 0x34, 0xae, 0xf2, 0x9d, 0x45, 0x23, 0x68, 0x14, 0x06, 0x45, 0x3d, 0x4d, 0x63, 0x6b, 0x6f, - 0xfb, 0x5b, 0xe4, 0x70, 0x05, 0x0d, 0xc1, 0x54, 0x1b, 0x80, 0x6c, 0x1d, 0x59, 0x5b, 0x86, 0x7e, - 0x77, 0x03, 0x21, 0x73, 0xbc, 0x2c, 0xf8, 0x0f, 0x60, 0x11, 0xb3, 0xa2, 0x0d, 0x64, 0x80, 0xca, - 0xf0, 0x3b, 0xc0, 0x9f, 0x41, 0x7b, 0x7d, 0x05, 0x90, 0xa3, 0x33, 0x76, 0x6c, 0xc5, 0x8e, 0xda, - 0xa7, 0xd0, 0x5a, 0xb3, 0x39, 0x3a, 0xd2, 0x09, 0xbf, 0x1a, 0xbf, 0x6f, 0xe9, 0x40, 0x71, 0x2b, - 0x0b, 0x4f, 0xc1, 0xda, 0xb0, 0x2f, 0xfa, 0x4b, 0x67, 0xec, 0xb2, 0x74, 0x1f, 0x95, 0x56, 0x2a, - 0x5d, 0x8a, 0x2b, 0x8f, 0x0c, 0x49, 0xbc, 0x59, 0xba, 0x02, 0x1d, 0xe6, 0x42, 0x6c, 0xba, 0xa4, - 0x9f, 0x29, 0xbc, 0xe5, 0x08, 0x5c, 0xf9, 0x50, 0xd3, 0x7f, 0x9d, 0x4f, 0x7e, 0x04, 0x00, 0x00, - 0xff, 0xff, 0x9e, 0x01, 0x0b, 0x56, 0x5b, 0x05, 0x00, 0x00, + // 768 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x55, 0xdd, 0x6e, 0xd3, 0x4a, + 0x10, 0x4e, 0x62, 0x37, 0x3f, 0x93, 0x26, 0xb5, 0x36, 0x39, 0xe7, 0xf8, 0x44, 0xea, 0x51, 0xb5, + 0x3a, 0x12, 0x55, 0x85, 0x92, 0x2a, 0x08, 0x10, 0xdc, 0xa5, 0x21, 0x6a, 0x8b, 0x4a, 0xa9, 0x36, + 0x09, 0x48, 0x5c, 0x20, 0x19, 0x7b, 0xdb, 0x98, 0x26, 0xb6, 0xd9, 0xdd, 0x08, 0xf5, 0x8e, 0x47, + 0xe0, 0x61, 0x10, 0x8f, 0x07, 0xec, 0xae, 0x7f, 0xe2, 0x84, 0x08, 0xa9, 0xbd, 0x70, 0x77, 0x7e, + 0x76, 0xe6, 0x9b, 0x6f, 0x67, 0x26, 0xb0, 0xef, 0x5d, 0x73, 0xde, 0x53, 0x9f, 0xa8, 0xe7, 0x44, + 0x7e, 0x2f, 0x9a, 0x3b, 0xe2, 0x3a, 0x64, 0x8b, 0x6e, 0xc4, 0x42, 0x11, 0x22, 0x43, 0xea, 0xf0, + 0x00, 0xf6, 0x08, 0xbd, 0xf1, 0xb9, 0xa0, 0x8c, 0xd0, 0x4f, 0x4b, 0xca, 0x05, 0x6a, 0xc3, 0x0e, + 0x5d, 0x38, 0xfe, 0xdc, 0x2e, 0x1e, 0x14, 0x0f, 0x6b, 0x24, 0x16, 0x90, 0x0d, 0x15, 0x16, 0x3b, + 0xd8, 0x25, 0xad, 0x4f, 0x45, 0xfc, 0xad, 0x08, 0xb5, 0x11, 0x63, 0x21, 0x1b, 0x86, 0x1e, 0x45, + 0x0f, 0xc0, 0x74, 0xe5, 0x7f, 0x7d, 0xb9, 0xd9, 0x6f, 0x75, 0x65, 0x92, 0x6e, 0x66, 0xed, 0xaa, + 0x0f, 0xd1, 0x0e, 0x2a, 0xe0, 0x82, 0x72, 0xee, 0xdc, 0xd0, 0x34, 0x60, 0x22, 0x62, 0x0f, 0x4c, + 0x1d, 0xaa, 0x0e, 0x95, 0xf1, 0x74, 0x38, 0x1c, 0x8d, 0xc7, 0x56, 0x01, 0x01, 0x94, 0xcf, 0x2f, + 0xdf, 0x0c, 0xc8, 0xa9, 0x55, 0x54, 0x86, 0x93, 0xc1, 0x8b, 0xc1, 0x74, 0x72, 0x66, 0x95, 0x94, + 0xf0, 0x76, 0x40, 0x2e, 0xcf, 0x2f, 0x4f, 0x2d, 0x03, 0xb5, 0x94, 0xd7, 0x64, 0x44, 0x88, 0xf5, + 0x33, 0xfd, 0x2b, 0xca, 0x82, 0x2a, 0x93, 0xf3, 0x57, 0xa3, 0xd7, 0xd3, 0x89, 0xf5, 0x23, 0xd3, + 0xe2, 0x67, 0x50, 0x1f, 0x2c, 0xc5, 0xec, 0xcf, 0x55, 0x4b, 0xad, 0x08, 0x6f, 0x69, 0x90, 0x40, + 0x8c, 0x05, 0x7c, 0x0c, 0xcd, 0x94, 0x34, 0xea, 0x4d, 0x39, 0x65, 0xe8, 0x3f, 0x00, 0x77, 0xee, + 0xd3, 0x40, 0x0c, 0x29, 0x13, 0x49, 0x88, 0x9c, 0x06, 0x57, 0x60, 0x67, 0xb4, 0x88, 0xc4, 0x1d, + 0xfe, 0x0c, 0xad, 0xab, 0x90, 0x8b, 0x61, 0x18, 0x08, 0xe6, 0xb8, 0x22, 0xcd, 0x8e, 0xc0, 0x9c, + 0x39, 0x7c, 0xa6, 0x6f, 0xee, 0x12, 0x7d, 0x46, 0x1d, 0xa8, 0x5e, 0xfb, 0x73, 0x1a, 0x38, 0x8b, + 0x94, 0xa1, 0x4c, 0x46, 0x7f, 0x43, 0x99, 0xfb, 0x37, 0x01, 0x65, 0xb6, 0x71, 0x60, 0x48, 0x4b, + 0x22, 0x29, 0x52, 0xdd, 0x70, 0xb1, 0x90, 0x69, 0x6d, 0x33, 0x26, 0x35, 0x11, 0xf1, 0x21, 0xa0, + 0x53, 0xba, 0x2d, 0xef, 0x72, 0xe9, 0x7b, 0x09, 0x62, 0x7d, 0xc6, 0x17, 0x50, 0x4d, 0xdd, 0xd0, + 0x43, 0xa8, 0xd1, 0xf4, 0xf1, 0xb4, 0x53, 0xbd, 0xdf, 0x5c, 0x7f, 0x52, 0xb2, 0x72, 0x50, 0xd1, + 0x3e, 0xf2, 0x30, 0x26, 0x4b, 0x56, 0xa1, 0xce, 0xf8, 0x3d, 0xb4, 0x5f, 0x86, 0x7e, 0x30, 0x96, + 0xf8, 0x1c, 0xb1, 0x64, 0x34, 0xcd, 0x8c, 0x61, 0xd7, 0x4d, 0xb2, 0x4c, 0x57, 0x08, 0xd6, 0x74, + 0x2a, 0x5e, 0x14, 0xb2, 0xb8, 0xe1, 0x1a, 0x44, 0x9f, 0x51, 0x13, 0x4a, 0x7e, 0x94, 0x54, 0x2d, + 0x4f, 0xf8, 0x4b, 0x11, 0x1a, 0xea, 0x09, 0x24, 0xe4, 0x80, 0xba, 0x82, 0x7a, 0xf7, 0xc4, 0xbc, + 0x89, 0xa3, 0xb4, 0x05, 0xc7, 0xbe, 0x64, 0x89, 0x6b, 0xae, 0x55, 0xb0, 0x9a, 0x0e, 0xa6, 0x72, + 0x12, 0xad, 0xc6, 0xef, 0xc0, 0xd4, 0x4d, 0x20, 0xc9, 0xbf, 0xa5, 0x77, 0x67, 0xab, 0x77, 0x4c, + 0xc5, 0x55, 0x73, 0x95, 0xf2, 0xcd, 0xb5, 0x51, 0x4a, 0x56, 0xae, 0xb9, 0x2a, 0x17, 0x3f, 0x01, + 0x8b, 0x50, 0xc7, 0xbb, 0x53, 0xfc, 0xdd, 0x83, 0x3a, 0xfc, 0xbd, 0x04, 0x7b, 0x17, 0xce, 0x32, + 0x70, 0x67, 0x19, 0xf3, 0xf7, 0x24, 0xe6, 0x7f, 0x68, 0xf0, 0xf4, 0x6a, 0x8e, 0x99, 0x75, 0xa5, + 0xc2, 0xe2, 0x85, 0xee, 0x52, 0xb5, 0x98, 0x2e, 0xdc, 0xd0, 0x85, 0xaf, 0xe9, 0xf2, 0xbc, 0x98, + 0xb2, 0xd8, 0x1c, 0x2f, 0xb2, 0xc5, 0xb9, 0x2a, 0x2a, 0x70, 0xa9, 0xbd, 0x23, 0x4d, 0x0d, 0x92, + 0xc9, 0xe8, 0x08, 0x0c, 0x21, 0x22, 0xbb, 0xac, 0x71, 0xda, 0x1a, 0xe7, 0x46, 0x41, 0xdd, 0xc9, + 0xe4, 0x8a, 0x28, 0x27, 0xc5, 0x1c, 0xa7, 0xce, 0xdc, 0x86, 0xb8, 0xf1, 0xd4, 0xb9, 0xf3, 0x18, + 0x0c, 0x69, 0x57, 0x29, 0x1c, 0xcf, 0x63, 0x9a, 0xd8, 0x98, 0xa8, 0x4c, 0xce, 0xa6, 0xae, 0xb4, + 0x9a, 0xba, 0xfe, 0x57, 0x03, 0xaa, 0x57, 0xc9, 0xa2, 0x44, 0x7d, 0xa8, 0xa6, 0x83, 0x8e, 0xda, + 0x1a, 0xc2, 0xc6, 0xb2, 0xec, 0x6c, 0x10, 0x88, 0x0b, 0xa8, 0x07, 0xa6, 0xda, 0x2b, 0xc8, 0xd2, + 0x96, 0xdc, 0x8a, 0xe9, 0xb4, 0xd6, 0x22, 0xc4, 0x9b, 0x43, 0x5e, 0x38, 0x02, 0x98, 0x06, 0x2c, + 0x4d, 0x03, 0x71, 0x40, 0xb5, 0x2c, 0xb6, 0x04, 0x7f, 0x0e, 0xbb, 0xf9, 0xf5, 0x81, 0x62, 0x5e, + 0xb6, 0x6c, 0x94, 0x2d, 0x77, 0x9f, 0x42, 0x3d, 0xb7, 0x01, 0xd0, 0x3f, 0xda, 0xe1, 0xf7, 0x9d, + 0xd0, 0x69, 0x68, 0x43, 0xaa, 0x95, 0x17, 0x4f, 0xa0, 0xb1, 0x36, 0xc2, 0xe8, 0x5f, 0xed, 0xb1, + 0x6d, 0xac, 0x3b, 0x28, 0x1b, 0x8e, 0x6c, 0x20, 0x71, 0xe1, 0xb8, 0x28, 0x81, 0xd7, 0xb2, 0x3e, + 0x46, 0x7f, 0x25, 0x44, 0xac, 0xf7, 0x75, 0xa7, 0xbd, 0xed, 0x91, 0x71, 0xe1, 0x43, 0x59, 0xff, + 0x5e, 0x3d, 0xfa, 0x15, 0x00, 0x00, 0xff, 0xff, 0x31, 0x18, 0xb6, 0x50, 0xd0, 0x06, 0x00, 0x00, } diff --git a/dfssp/api/platform.proto b/dfssp/api/platform.proto index c4d92ef..210f63a 100644 --- a/dfssp/api/platform.proto +++ b/dfssp/api/platform.proto @@ -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; } diff --git a/dfssp/authority/rootCA.go b/dfssp/authority/rootCA.go index ca568df..406913f 100644 --- a/dfssp/authority/rootCA.go +++ b/dfssp/authority/rootCA.go @@ -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. diff --git a/dfssp/authority/rootCA_test.go b/dfssp/authority/rootCA_test.go index b97bc87..b22ba30 100644 --- a/dfssp/authority/rootCA_test.go +++ b/dfssp/authority/rootCA_test.go @@ -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 { diff --git a/dfssp/authority/testdata/corrupted_ttps b/dfssp/authority/testdata/corrupted_ttps new file mode 100644 index 0000000..318583d --- /dev/null +++ b/dfssp/authority/testdata/corrupted_ttps @@ -0,0 +1 @@ +wrongline diff --git a/dfssp/authority/testdata/ttps b/dfssp/authority/testdata/ttps new file mode 100644 index 0000000..594a8f6 --- /dev/null +++ b/dfssp/authority/testdata/ttps @@ -0,0 +1,2 @@ +1.2.3.4:9005 aabbcc +192.168.1.1:36500 0123456789 diff --git a/dfssp/authority/ttp.go b/dfssp/authority/ttp.go new file mode 100644 index 0000000..ead05fc --- /dev/null +++ b/dfssp/authority/ttp.go @@ -0,0 +1,108 @@ +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: +// +// [:\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) +} diff --git a/dfssp/authority/ttp_test.go b/dfssp/authority/ttp_test.go new file mode 100644 index 0000000..7f164d3 --- /dev/null +++ b/dfssp/authority/ttp_test.go @@ -0,0 +1,62 @@ +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) +} diff --git a/dfssp/cmd/init.go b/dfssp/cmd/init.go index 4d8379f..5079eeb 100644 --- a/dfssp/cmd/init.go +++ b/dfssp/cmd/init.go @@ -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") }, } diff --git a/dfssp/cmd/root.go b/dfssp/cmd/root.go index a17eb16..03cd567 100644 --- a/dfssp/cmd/root.go +++ b/dfssp/cmd/root.go @@ -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")) diff --git a/dfssp/cmd/start.go b/dfssp/cmd/start.go index a547091..f312946 100644 --- a/dfssp/cmd/start.go +++ b/dfssp/cmd/start.go @@ -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") diff --git a/dfssp/cmd/ttp.go b/dfssp/cmd/ttp.go index 0e38e00..64eb076 100644 --- a/dfssp/cmd/ttp.go +++ b/dfssp/cmd/ttp.go @@ -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) + } }, } diff --git a/dfssp/contract/create.go b/dfssp/contract/create.go index a050a57..e0d0eb1 100644 --- a/dfssp/contract/create.go +++ b/dfssp/contract/create.go @@ -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 diff --git a/dfssp/contract/fetch.go b/dfssp/contract/fetch.go index 81e9605..c13a484 100644 --- a/dfssp/contract/fetch.go +++ b/dfssp/contract/fetch.go @@ -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}, diff --git a/dfssp/contract/file.go b/dfssp/contract/file.go index 7fdebcc..63ed668 100644 --- a/dfssp/contract/file.go +++ b/dfssp/contract/file.go @@ -21,12 +21,6 @@ type SignerJSON struct { Hash string } -// TTPJSON is the structure used to store TTP information in JSON format -type TTPJSON struct { - IP string - Port uint -} - // JSON is the structure used to store contract information in JSON format type JSON struct { UUID string @@ -34,11 +28,10 @@ type JSON struct { Comment string File *FileJSON Signers []SignerJSON - TTP *TTPJSON } // GetJSON returns indented json from a contract and some ttp information (nil allowed) -func GetJSON(c *entities.Contract, ttp *TTPJSON) ([]byte, error) { +func GetJSON(c *entities.Contract) ([]byte, error) { data := JSON{ UUID: c.ID.Hex(), Date: &c.Date, @@ -49,7 +42,6 @@ func GetJSON(c *entities.Contract, ttp *TTPJSON) ([]byte, error) { Hosted: c.File.Hosted, }, Signers: make([]SignerJSON, len(c.Signers)), - TTP: ttp, } for i, s := range c.Signers { diff --git a/dfssp/contract/file_test.go b/dfssp/contract/file_test.go index 52948c9..465a66c 100644 --- a/dfssp/contract/file_test.go +++ b/dfssp/contract/file_test.go @@ -47,11 +47,10 @@ allow multiline and accents: éÉ`, "Email": "b", "Hash": "bb" } - ], - "TTP": null + ] }` - j, err := GetJSON(c, nil) + j, err := GetJSON(c) assert.Equal(t, nil, err) assert.Equal(t, expected, string(j)) diff --git a/dfssp/server/server.go b/dfssp/server/server.go index b47bad7..83d8fde 100644 --- a/dfssp/server/server.go +++ b/dfssp/server/server.go @@ -22,6 +22,7 @@ type platformServer struct { Pid *authority.PlatformID DB *mgdb.MongoManager Rooms *common.WaitingGroupMap + TTPs *authority.TTPHolder } // Register handler @@ -98,6 +99,7 @@ func (s *platformServer) ReadySign(ctx context.Context, in *api.ReadySignRequest signal := contract.ReadySign(s.DB, s.Rooms, &ctx, in) if signal.ErrorCode.Code == api.ErrorCode_SUCCESS { + signal.Ttp = s.TTPs.Get() // Assign a ttp to this signature, if any available sealedSignal := *signal sealedSignal.ErrorCode = nil sealedSignal.Seal = nil @@ -125,11 +127,21 @@ func GetServer() *grpc.Server { os.Exit(1) } + ttpholder, err := authority.NewTTPHolder(viper.GetString("ttps")) + if err != nil { + fmt.Println("An error occured during the ttp file load:", err) + } + + if ttpholder.Nb() == 0 { + fmt.Println("Warning: no TTP loaded. See `dfssp ttp --help`.") + } + server := net.NewServer(pid.RootCA, pid.Pkey, pid.RootCA) api.RegisterPlatformServer(server, &platformServer{ Pid: pid, DB: dbManager, Rooms: common.NewWaitingGroupMap(), + TTPs: ttpholder, }) return server } diff --git a/dfsst/entities/check_request.go b/dfsst/entities/check_request.go index dc1564d..a5105f0 100644 --- a/dfsst/entities/check_request.go +++ b/dfsst/entities/check_request.go @@ -143,11 +143,19 @@ func IsPlatformSealValid(promise *cAPI.Promise) bool { return false } + var ttp *pAPI.LaunchSignature_TTP + if promise.Context.TtpAddrPort != "" { + ttp = new(pAPI.LaunchSignature_TTP) + ttp.Addrport = promise.Context.TtpAddrPort + ttp.Hash = promise.Context.TtpHash + } + theoric := pAPI.LaunchSignature{ SignatureUuid: promise.Context.SignatureUUID, DocumentHash: promise.Context.ContractDocumentHash, KeyHash: promise.Context.Signers, Sequence: promise.Context.Sequence, + Ttp: ttp, } ok, _ := auth.VerifyStructure(AuthContainer.CA, theoric, promise.Context.Seal) diff --git a/dfsst/server/server.go b/dfsst/server/server.go index 7fee605..7b354b2 100644 --- a/dfsst/server/server.go +++ b/dfsst/server/server.go @@ -8,6 +8,7 @@ import ( cAPI "dfss/dfssc/api" "dfss/dfssc/security" + dAPI "dfss/dfssd/api" tAPI "dfss/dfsst/api" "dfss/dfsst/entities" "dfss/dfsst/resolve" @@ -29,10 +30,12 @@ type ttpServer struct { func (server *ttpServer) Alert(ctx context.Context, in *tAPI.AlertRequest) (*tAPI.TTPResponse, error) { valid, signatureUUID, signers, senderIndex := entities.IsRequestValid(ctx, in.Promises) if !valid { + dAPI.DLog("invalid request from " + net.GetCN(&ctx)) return nil, errors.New(InternalError) } valid = int(in.Index) >= len(in.Promises[0].Context.Sequence) if !valid { + dAPI.DLog("invalid sequence index from " + net.GetCN(&ctx)) return nil, errors.New(InternalError) } // Now we know that the request contains information correctly signed by the platform, @@ -46,6 +49,7 @@ func (server *ttpServer) Alert(ctx context.Context, in *tAPI.AlertRequest) (*tAP // We check if we have already sent an abort token to the sender of the request stop, message, err := server.handleAbortedSender(manager, senderIndex) if stop { + dAPI.DLog("already sent an abort token to " + net.GetCN(&ctx)) return message, err } diff --git a/net/client.go b/net/client.go index ad8316d..e3a0b6e 100644 --- a/net/client.go +++ b/net/client.go @@ -17,7 +17,7 @@ import ( ) // DefaultTimeout should be used when a non-critical timeout is used in the application. -var DefaultTimeout = 30 * time.Second +var DefaultTimeout = 5 * time.Second // Connect to a peer. // diff --git a/net/fixtures/test.pb.go b/net/fixtures/test.pb.go index f036fb5..2b7ee39 100644 --- a/net/fixtures/test.pb.go +++ b/net/fixtures/test.pb.go @@ -170,15 +170,16 @@ var _Test_serviceDesc = grpc.ServiceDesc{ } var fileDescriptor0 = []byte{ - // 158 bytes of a gzipped FileDescriptorProto + // 164 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x49, 0x49, 0x2b, 0x2e, 0xd6, 0xcf, 0x4b, 0x2d, 0xd1, 0x4f, 0xcb, 0xac, 0x28, 0x29, 0x2d, 0x4a, 0x2d, 0xd6, 0x2f, 0x49, - 0x2d, 0x2e, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x80, 0x09, 0x2a, 0x09, 0x72, 0x31, - 0x7b, 0xe4, 0x17, 0x08, 0x71, 0x71, 0x31, 0x65, 0xa6, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x2a, - 0x89, 0x71, 0xb1, 0x79, 0x16, 0x3b, 0x96, 0x96, 0x64, 0x08, 0xf1, 0x70, 0xb1, 0x24, 0x02, 0x69, - 0xb0, 0x38, 0x87, 0x12, 0x3b, 0x17, 0xab, 0x6b, 0x6e, 0x41, 0x49, 0xa5, 0x51, 0x34, 0x17, 0x4b, - 0x08, 0xd0, 0x2c, 0x21, 0x35, 0x2e, 0x96, 0x80, 0xcc, 0xbc, 0x74, 0x21, 0x5e, 0x3d, 0x98, 0x71, - 0x7a, 0x40, 0xb3, 0xa4, 0x50, 0xb9, 0x4a, 0x0c, 0x42, 0xda, 0x5c, 0x2c, 0x60, 0xe3, 0xf8, 0x11, - 0x12, 0x60, 0x83, 0xa4, 0x04, 0x10, 0x02, 0x10, 0x1b, 0x95, 0x18, 0x92, 0xd8, 0xc0, 0x2e, 0x34, - 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xe6, 0x7b, 0x0d, 0xb5, 0xc1, 0x00, 0x00, 0x00, + 0x2d, 0x2e, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x80, 0x09, 0x2a, 0x89, 0x72, 0x31, + 0x7b, 0xe4, 0x17, 0x08, 0xf1, 0x71, 0x31, 0x65, 0xa6, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x06, + 0x01, 0x59, 0x4a, 0x32, 0x5c, 0x6c, 0x9e, 0xc5, 0x8e, 0xa5, 0x25, 0x19, 0x42, 0x42, 0x5c, 0x2c, + 0x89, 0x40, 0x1a, 0x2c, 0xc7, 0x11, 0x04, 0x66, 0x2b, 0xb1, 0x73, 0xb1, 0xba, 0xe6, 0x16, 0x94, + 0x54, 0x1a, 0x45, 0x73, 0xb1, 0x84, 0x00, 0x4d, 0x15, 0x52, 0xe3, 0x62, 0x09, 0xc8, 0xcc, 0x4b, + 0x17, 0xe2, 0xd5, 0x83, 0x19, 0xac, 0x07, 0x34, 0x55, 0x0a, 0x95, 0xab, 0xc4, 0x20, 0xa4, 0xcd, + 0xc5, 0x02, 0x36, 0x94, 0x1f, 0x21, 0x01, 0x36, 0x48, 0x4a, 0x00, 0x21, 0x00, 0xb1, 0x57, 0x89, + 0x21, 0x89, 0x0d, 0xec, 0x56, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2a, 0xf2, 0x1b, 0xf6, + 0xcb, 0x00, 0x00, 0x00, } diff --git a/tests/sign_test.go b/tests/sign_test.go index af3bf2e..c0148da 100644 --- a/tests/sign_test.go +++ b/tests/sign_test.go @@ -14,18 +14,11 @@ import ( "github.com/stretchr/testify/assert" ) -// TestSignContract unroll the whole signature process. -// -// GOOD CASE -// - Start platform +// setupSignature prepares required servers and clients to sign a contract. +// - Start platform, ttp, demonstrator // - Register client1, client2 and client3 // - Create contract `contract.txt` -// - Sign it -// - Check if all proof files are present -// -// TODO BAD CASES - -func TestSignContract(t *testing.T) { +func setupSignature(t *testing.T) (stop func(), clients []*exec.Cmd, contractPath, contractFilePath string) { // Cleanup eraseDatabase() @@ -34,12 +27,10 @@ func TestSignContract(t *testing.T) { assert.Equal(t, nil, err) _, _, _, stop, ca, err := startPlatform(workingDir) assert.Equal(t, nil, err) - defer stop() time.Sleep(2 * time.Second) // Register clients - clients := make([]*exec.Cmd, 3) client1, err := createClient(workingDir, ca, 9091) assert.Equal(t, nil, err) err = registerAndAuth(client1, "client1@example.com", "password", "", true, true) @@ -56,7 +47,7 @@ func TestSignContract(t *testing.T) { // Create contract client1 = newClient(client1) setLastArg(client1, "new", true) - contractFilePath := filepath.Join("testdata", "contract.txt") + contractFilePath = filepath.Join("testdata", "contract.txt") client1.Stdin = strings.NewReader( "password\n" + contractFilePath + "\n" + @@ -71,9 +62,9 @@ func TestSignContract(t *testing.T) { // Get contract file contractEntity := getContract("contract.txt", 0) - contractData, err := contract.GetJSON(contractEntity, nil) + contractData, err := contract.GetJSON(contractEntity) assert.Equal(t, nil, err) - contractPath := filepath.Join(workingDir, "c.dfss") + contractPath = filepath.Join(workingDir, "c.dfss") err = ioutil.WriteFile(contractPath, contractData, os.ModePerm) assert.Equal(t, nil, err) @@ -85,11 +76,21 @@ func TestSignContract(t *testing.T) { _, err = wrongFileClient.Output() assert.NotNil(t, err) - // Sign! + clients = make([]*exec.Cmd, 3) clients[0] = newClient(client1) clients[1] = newClient(client2) clients[2] = newClient(client3) + return +} + +// TestSignContract unroll the whole signature process. +// In this test, everything should work fine without any ttp call. +func TestSignContract(t *testing.T) { + // Setup + stop, clients, contractPath, contractFilePath := setupSignature(t) + defer stop() + // Sign! closeChannel := make(chan []byte, 3) for i := 0; i < 3; i++ { setLastArg(clients[i], "sign", true) @@ -98,8 +99,8 @@ func TestSignContract(t *testing.T) { time.Sleep(time.Duration(i*2) * time.Second) c.Stdin = strings.NewReader(contractFilePath + "\npassword\nyes\n") c.Stderr = os.Stderr - output, err1 := c.Output() - if err1 != nil { + output, err := c.Output() + if err != nil { output = nil } closeChannel <- output @@ -118,6 +119,12 @@ func TestSignContract(t *testing.T) { } } + checkProofFile(t, 3) + time.Sleep(time.Second) +} + +// checkProofFile counts the number of proof file contained in the current directory, and compares it to the nb parameter. +func checkProofFile(t *testing.T, nb int) { // Ensure that all the files are present proofFile := regexp.MustCompile(`client[0-9]+@example.com.*\.proof`) files, _ := ioutil.ReadDir("./") @@ -126,11 +133,42 @@ func TestSignContract(t *testing.T) { for _, file := range files { if proofFile.Match([]byte(file.Name())) { matches++ - err = os.Remove("./" + file.Name()) + err := os.Remove("./" + file.Name()) assert.True(t, err == nil, "Cannot remove .proof matching file") } } - assert.True(t, matches == 3, "Missing proof file ?") + assert.Equal(t, nb, matches, "Invalid number of proof file(s)") +} + +// TestSignContractFailure tests the signature with a faulty client. +// In this test, everything should not work fine, because client1 shutdowns way too early. +func TestSignContractFailure(t *testing.T) { + // Setup + stop, clients, contractPath, contractFilePath := setupSignature(t) + defer stop() + + // Configure client3 to be faulty + setLastArg(clients[2], "--stopbefore", true) + setLastArg(clients[2], "1", false) + setLastArg(clients[2], "sign", false) + + // Sign! + closeChannel := make(chan []byte, 3) + for i := 0; i < 3; i++ { + setLastArg(clients[i], "sign", true) + setLastArg(clients[i], contractPath, false) + go func(c *exec.Cmd, i int) { + c.Stdin = strings.NewReader(contractFilePath + "\npassword\nyes\n") + output, _ := c.Output() + closeChannel <- output + }(clients[i], i) + } + + for i := 0; i < 3; i++ { + // TODO check stderr? + <-closeChannel + } + checkProofFile(t, 0) time.Sleep(time.Second) } diff --git a/tests/starters_test.go b/tests/starters_test.go index f7f8f8f..67f4e90 100644 --- a/tests/starters_test.go +++ b/tests/starters_test.go @@ -31,13 +31,14 @@ func startPlatform(tmpDir string) (platform, ttp, demo *exec.Cmd, stop func(), c // Init cmd := exec.Command(path, "--path", dir, "-v", "init") + ttpsPath := filepath.Join(dir, "ttps") err = cmd.Run() if err != nil { return } // Create TTP working directory - cmd = exec.Command(path, "--path", dir, "-v", "--cn", "ttp", "ttp") + cmd = exec.Command(path, "--path", dir, "--ttps", ttpsPath, "--addr", "localhost:9098", "ttp") err = cmd.Run() if err != nil { return @@ -50,13 +51,13 @@ func startPlatform(tmpDir string) (platform, ttp, demo *exec.Cmd, stop func(), c } // Start platform - platform = exec.Command(path, "--db", dbURI, "--path", dir, "-p", testPort, "-v", "start") + platform = exec.Command(path, "--db", dbURI, "--path", dir, "-p", testPort, "--ttps", ttpsPath, "-d", "localhost:9099", "-v", "start") platform.Stdout = os.Stdout platform.Stderr = os.Stderr err = platform.Start() // Start TTP - ttp = exec.Command(ttpPath, "--db", dbURI, "--port", "9098", "start") + ttp = exec.Command(ttpPath, "--db", dbURI, "--port", "9098", "-d", "localhost:9099", "-v", "start") ttp.Dir = filepath.Join(dir, "ttp") ttp.Stdout = os.Stdout ttp.Stderr = os.Stderr -- GitLab