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 { ...@@ -51,8 +51,13 @@ type Context struct {
ContractDocumentHash []byte `protobuf:"bytes,5,opt,name=contractDocumentHash,proto3" json:"contractDocumentHash,omitempty"` 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 // / 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"` 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 // / 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{} } func (m *Context) Reset() { *m = Context{} }
...@@ -262,27 +267,31 @@ var _Client_serviceDesc = grpc.ServiceDesc{ ...@@ -262,27 +267,31 @@ var _Client_serviceDesc = grpc.ServiceDesc{
} }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 348 bytes of a gzipped FileDescriptorProto // 404 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x91, 0xcf, 0x4e, 0xea, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x52, 0xdd, 0xca, 0xda, 0x40,
0x14, 0xc6, 0xe9, 0xe5, 0x4f, 0xe1, 0xdc, 0xc2, 0x25, 0x93, 0x6b, 0x32, 0x41, 0x49, 0x48, 0xe3, 0x10, 0xf5, 0x3f, 0x3a, 0x46, 0x29, 0x8b, 0x17, 0x21, 0xa5, 0x60, 0x83, 0x14, 0xe9, 0x45, 0x04,
0x82, 0x55, 0x49, 0x70, 0xe9, 0x12, 0x4c, 0x30, 0x6e, 0x4c, 0x94, 0x07, 0x18, 0xa7, 0x07, 0x9d, 0xfb, 0x04, 0x45, 0x0b, 0x96, 0x52, 0x90, 0xb4, 0x3e, 0xc0, 0x76, 0x33, 0xb6, 0x0b, 0x31, 0x9b,
0xa4, 0x74, 0xea, 0xcc, 0x60, 0xe0, 0x35, 0x7c, 0x02, 0x1f, 0xd5, 0xe9, 0xa9, 0x45, 0x16, 0x26, 0xee, 0xae, 0x45, 0x5f, 0xa3, 0xaf, 0xd3, 0x97, 0xeb, 0x66, 0x62, 0xfc, 0x94, 0xcf, 0x8b, 0xef,
0x6e, 0x9a, 0x9e, 0x6f, 0xbe, 0xf3, 0xf5, 0xf7, 0x75, 0xe0, 0x3c, 0xdd, 0x58, 0x3b, 0x2b, 0x1f, 0x26, 0xec, 0x39, 0x73, 0x76, 0xce, 0xec, 0xc9, 0xc0, 0xeb, 0x74, 0x6f, 0xcc, 0xa2, 0xfc, 0x88,
0x72, 0x26, 0x0a, 0x35, 0x93, 0x99, 0xc2, 0xdc, 0x25, 0x85, 0xd1, 0x4e, 0xb3, 0xa6, 0x57, 0x46, 0x05, 0x2f, 0xe4, 0x42, 0x64, 0x12, 0x73, 0x1b, 0x17, 0x5a, 0x59, 0xc5, 0xda, 0x8e, 0x09, 0xdf,
0xe3, 0xa3, 0xa3, 0x20, 0x47, 0x91, 0x09, 0xb7, 0xd1, 0x66, 0x5b, 0x79, 0xe2, 0x8f, 0x00, 0xc2, 0x5c, 0x15, 0x05, 0x29, 0x8a, 0x8c, 0xdb, 0xbd, 0xd2, 0x87, 0x4a, 0x13, 0xfd, 0x6b, 0x81, 0xb7,
0x85, 0xce, 0x1d, 0xee, 0x1d, 0xe3, 0x30, 0x34, 0x28, 0x55, 0x51, 0x46, 0xdc, 0xe1, 0x61, 0x25, 0x52, 0xb9, 0xc5, 0x93, 0x65, 0xef, 0xe1, 0x95, 0x46, 0x21, 0x8b, 0xb2, 0xc5, 0x17, 0x3c, 0x6f,
0xec, 0x0b, 0x0f, 0x26, 0xc1, 0x34, 0x62, 0x67, 0xd0, 0xb7, 0x98, 0xa7, 0x68, 0x6a, 0xf9, 0x0f, 0xb8, 0xf9, 0x15, 0x34, 0xa7, 0xcd, 0xb9, 0x9f, 0x3c, 0xe3, 0xd9, 0x0c, 0x46, 0x06, 0xf3, 0x14,
0xc9, 0x43, 0xe8, 0x5a, 0x7c, 0xdd, 0x61, 0x2e, 0x91, 0x37, 0x27, 0xcd, 0x69, 0x9f, 0xfd, 0x83, 0x75, 0x2d, 0x6c, 0x91, 0xf0, 0x9e, 0x64, 0x21, 0xf4, 0x0d, 0xfe, 0x3e, 0x62, 0x2e, 0x30, 0x68,
0xd0, 0xaa, 0xe7, 0x1c, 0x8d, 0xe5, 0x2d, 0x2f, 0x44, 0xec, 0x02, 0xfe, 0x4b, 0x1f, 0x6f, 0x84, 0x4f, 0xdb, 0xf3, 0x51, 0x72, 0xc5, 0x2c, 0x00, 0xcf, 0xc8, 0x9f, 0x39, 0x6a, 0x13, 0x74, 0x5c,
0x74, 0x4b, 0x2d, 0x77, 0x5b, 0x1f, 0x4d, 0x01, 0xed, 0x63, 0xae, 0xb7, 0x0b, 0xb7, 0x33, 0xb8, 0xc9, 0x4f, 0x6a, 0xc8, 0x96, 0x30, 0x11, 0x6e, 0x24, 0xcd, 0x85, 0x5d, 0x2b, 0x71, 0x3c, 0x38,
0x5e, 0xdf, 0x2e, 0x79, 0xc7, 0xcb, 0x3d, 0x16, 0x41, 0xcb, 0xa2, 0xc8, 0x78, 0x58, 0x9a, 0xe2, 0x5b, 0xb2, 0xe8, 0x92, 0xc5, 0xc3, 0x1a, 0xcd, 0xe3, 0xae, 0x73, 0x7b, 0xd4, 0xb8, 0xdb, 0x7d,
0x15, 0x84, 0xf7, 0x46, 0x6f, 0x95, 0x45, 0x36, 0x86, 0x50, 0x56, 0xb0, 0x04, 0xf6, 0x77, 0x1e, 0x5e, 0x07, 0x3d, 0x27, 0x1e, 0x24, 0xf7, 0x24, 0x9b, 0xc2, 0xd0, 0xda, 0xe2, 0x63, 0x9a, 0xea,
0x25, 0xbe, 0x53, 0x52, 0x17, 0xe8, 0x43, 0x5b, 0x79, 0xca, 0x3d, 0xe1, 0x11, 0x4c, 0x21, 0x0e, 0xad, 0xd2, 0x36, 0xf0, 0x48, 0x73, 0x4b, 0x95, 0x53, 0x39, 0x48, 0x76, 0x7d, 0xb2, 0xab, 0x21,
0x99, 0x16, 0xa9, 0xa7, 0x2b, 0x93, 0xae, 0xa1, 0xf7, 0x50, 0x7f, 0xee, 0xb7, 0xac, 0x93, 0x65, 0x63, 0xd0, 0x31, 0xc8, 0xb3, 0x00, 0x88, 0xa6, 0x73, 0xc4, 0xc1, 0xdb, 0x6a, 0x75, 0x90, 0x06,
0x2a, 0x1b, 0x73, 0x68, 0xaf, 0x30, 0xcb, 0x74, 0x79, 0xf2, 0xe6, 0x0b, 0x2a, 0x9d, 0xd3, 0x62, 0xd9, 0x3b, 0xf0, 0x44, 0x95, 0x23, 0x65, 0x36, 0x5c, 0xfa, 0xb1, 0x8b, 0x3b, 0xbe, 0x64, 0x9b,
0x6f, 0xfe, 0x1e, 0x40, 0x67, 0x41, 0x3f, 0x9e, 0x25, 0x10, 0x3d, 0x1a, 0x14, 0xae, 0x06, 0xae, 0xd4, 0x45, 0x36, 0x81, 0xae, 0x74, 0x11, 0x9d, 0x28, 0xb0, 0x51, 0x52, 0x81, 0xd2, 0xb6, 0xe0,
0x32, 0xbf, 0xa6, 0xd1, 0x80, 0xa6, 0x1b, 0x63, 0xb4, 0x59, 0xe8, 0x14, 0xe3, 0x06, 0x9b, 0xc3, 0xe7, 0x4c, 0xf1, 0xd4, 0xe5, 0x44, 0xb6, 0x17, 0x18, 0x7d, 0x85, 0xc1, 0xb7, 0xfa, 0x0d, 0x2f,
0x80, 0xfc, 0xdf, 0x58, 0x95, 0xe7, 0x38, 0xff, 0xb0, 0x73, 0x09, 0xdd, 0xa5, 0xb2, 0x52, 0x7b, 0x36, 0xb9, 0x69, 0xd7, 0xba, 0x6f, 0xf7, 0x16, 0xba, 0x1b, 0xcc, 0x32, 0x55, 0x4a, 0xfe, 0xb8,
0x08, 0x06, 0x74, 0x4a, 0x5c, 0xa3, 0x93, 0xf7, 0xb8, 0xf1, 0xd4, 0xa1, 0xfb, 0xbd, 0xfa, 0x0c, 0xb0, 0xa5, 0xca, 0xa9, 0xd5, 0x20, 0xa9, 0xe1, 0xf2, 0x6f, 0x13, 0x7a, 0x2b, 0xda, 0x23, 0x16,
0x00, 0x00, 0xff, 0xff, 0x64, 0x27, 0xd3, 0xc2, 0x22, 0x02, 0x00, 0x00, 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 { ...@@ -30,8 +30,13 @@ message Context {
bytes contractDocumentHash = 5; bytes contractDocumentHash = 5;
/// The unique signature attemp ID, as provided by the platform during the ready signal /// The unique signature attemp ID, as provided by the platform during the ready signal
string signatureUUID = 6; 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 /// The signed metadata seal, as provided by the platform during the ready signal
bytes seal = 7; bytes seal = 10;
} }
message Promise { message Promise {
......
...@@ -25,6 +25,8 @@ func (m *SignatureManager) createContext(from, to uint32) (*cAPI.Context, error) ...@@ -25,6 +25,8 @@ func (m *SignatureManager) createContext(from, to uint32) (*cAPI.Context, error)
Signers: m.keyHash, Signers: m.keyHash,
ContractDocumentHash: h, ContractDocumentHash: h,
SignatureUUID: m.uuid, SignatureUUID: m.uuid,
TtpAddrPort: m.ttpData.Addrport,
TtpHash: m.ttpData.Hash,
Seal: m.seal, Seal: m.seal,
}, nil }, nil
} }
......
...@@ -14,9 +14,9 @@ import ( ...@@ -14,9 +14,9 @@ import (
dAPI "dfss/dfssd/api" dAPI "dfss/dfssd/api"
tAPI "dfss/dfsst/api" tAPI "dfss/dfsst/api"
"dfss/net" "dfss/net"
"github.com/spf13/viper"
"golang.org/x/net/context" "golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/spf13/viper"
) )
// Sign performs all the message exchanges for the contract to be signed // Sign performs all the message exchanges for the contract to be signed
...@@ -49,8 +49,10 @@ func (m *SignatureManager) Sign() error { ...@@ -49,8 +49,10 @@ func (m *SignatureManager) Sign() error {
// Promess rounds // Promess rounds
// Follow the sequence until there is no next occurence of me // Follow the sequence until there is no next occurence of me
round := 0
for m.currentIndex >= 0 { for m.currentIndex >= 0 {
stopIfNeeded(m.currentIndex) round = round + 1
stopIfNeeded(round)
m.OnProgressUpdate(m.currentIndex, seqLen+1) m.OnProgressUpdate(m.currentIndex, seqLen+1)
time.Sleep(viper.GetDuration("slowdown")) time.Sleep(viper.GetDuration("slowdown"))
dAPI.DLog("starting round at index [" + fmt.Sprintf("%d", m.currentIndex) + "] with nextIndex=" + fmt.Sprintf("%d", nextIndex)) 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 ...@@ -132,7 +134,7 @@ func (m *SignatureManager) promiseRound(pendingSet, sendSet []common.SequenceCoo
return m.resolve() return m.resolve()
} }
case <-time.After(time.Minute): case <-time.After(net.DefaultTimeout):
return m.resolve() return m.resolve()
} }
} }
...@@ -235,16 +237,20 @@ func (m *SignatureManager) callForResolve() (*tAPI.TTPResponse, error) { ...@@ -235,16 +237,20 @@ func (m *SignatureManager) callForResolve() (*tAPI.TTPResponse, error) {
// resolve : calls for the resolution, and persists the contract if obtained. // resolve : calls for the resolution, and persists the contract if obtained.
func (m *SignatureManager) resolve() error { func (m *SignatureManager) resolve() error {
if m.ttp == nil { if m.ttp == nil {
dAPI.DLog("unable to contact TTP")
return errors.New("No connection to TTP, aborting!") return errors.New("No connection to TTP, aborting!")
} }
dAPI.DLog("contacting TTP")
response, err := m.callForResolve() response, err := m.callForResolve()
if err != nil { if err != nil {
return err return err
} }
if response.Abort { if response.Abort {
dAPI.DLog("contacted TTP, received abort token")
return nil return nil
} }
dAPI.DLog("contacted TTP, received signed contract")
return ioutil.WriteFile(m.mail+"-"+m.contract.UUID+".proof", response.Contract, 0600) return ioutil.WriteFile(m.mail+"-"+m.contract.UUID+".proof", response.Contract, 0600)
} }
...@@ -283,7 +289,7 @@ func stopIfNeeded(index int) { ...@@ -283,7 +289,7 @@ func stopIfNeeded(index int) {
return return
} }
if index == -1 && s == -1 || index+1 == s { if index == -1 && s == -1 || index == s {
os.Exit(0) os.Exit(0)
} }
} }
\ No newline at end of file
package sign package sign
import ( import (
"crypto/rsa"
"crypto/x509"
"errors" "errors"
"fmt" "fmt"
"strconv" "strconv"
...@@ -34,6 +32,7 @@ type SignatureManager struct { ...@@ -34,6 +32,7 @@ type SignatureManager struct {
platform pAPI.PlatformClient platform pAPI.PlatformClient
platformConn *grpc.ClientConn platformConn *grpc.ClientConn
ttp tAPI.TTPClient ttp tAPI.TTPClient
ttpData *pAPI.LaunchSignature_TTP
peersConn map[string]*grpc.ClientConn peersConn map[string]*grpc.ClientConn
peers map[string]*cAPI.ClientClient peers map[string]*cAPI.ClientClient
hashToID map[string]uint32 hashToID map[string]uint32
...@@ -98,12 +97,6 @@ func NewSignatureManager(passphrase string, c *contract.JSON) (*SignatureManager ...@@ -98,12 +97,6 @@ func NewSignatureManager(passphrase string, c *contract.JSON) (*SignatureManager
m.platform = pAPI.NewPlatformClient(connp) m.platform = pAPI.NewPlatformClient(connp)
m.platformConn = 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.peersConn = make(map[string]*grpc.ClientConn)
m.peers = make(map[string]*cAPI.ClientClient) m.peers = make(map[string]*cAPI.ClientClient)
for _, u := range c.Signers { for _, u := range c.Signers {
...@@ -119,17 +112,6 @@ func NewSignatureManager(passphrase string, c *contract.JSON) (*SignatureManager ...@@ -119,17 +112,6 @@ func NewSignatureManager(passphrase string, c *contract.JSON) (*SignatureManager
return m, nil 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. // 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 { func (m *SignatureManager) ConnectToPeers() error {
localIps, err := net.ExternalInterfaceAddr() localIps, err := net.ExternalInterfaceAddr()
...@@ -299,6 +281,9 @@ func (m *SignatureManager) SendReadySign() (signatureUUID string, err error) { ...@@ -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.sequence = launch.Sequence
m.uuid = launch.SignatureUuid m.uuid = launch.SignatureUuid
m.keyHash = launch.KeyHash m.keyHash = launch.KeyHash
...@@ -307,6 +292,27 @@ func (m *SignatureManager) SendReadySign() (signatureUUID string, err error) { ...@@ -307,6 +292,27 @@ func (m *SignatureManager) SendReadySign() (signatureUUID string, err error) {
return 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 // Initialize computes the values needed for the start of the signing
func (m *SignatureManager) Initialize() (int, error) { func (m *SignatureManager) Initialize() (int, error) {
myID, err := m.FindID() myID, err := m.FindID()
......
...@@ -135,15 +135,16 @@ var _Demonstrator_serviceDesc = grpc.ServiceDesc{ ...@@ -135,15 +135,16 @@ var _Demonstrator_serviceDesc = grpc.ServiceDesc{
} }
var fileDescriptor0 = []byte{ 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, 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, 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, 0x45, 0x89, 0x25, 0xf9, 0x45, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xcc, 0x40, 0x71, 0xa5,
0x4b, 0x2e, 0x66, 0x9f, 0xfc, 0x74, 0x21, 0x41, 0x2e, 0xce, 0x92, 0xcc, 0xdc, 0xd4, 0xe2, 0x92, 0x50, 0x2e, 0x66, 0x9f, 0xfc, 0x74, 0x21, 0x19, 0x2e, 0xce, 0x92, 0xcc, 0xdc, 0xd4, 0xe2, 0x92,
0xc4, 0xdc, 0x02, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x66, 0x21, 0x21, 0x2e, 0xae, 0xcc, 0x94, 0xd4, 0xc4, 0xdc, 0x02, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xe6, 0x20, 0x84, 0x80, 0x90, 0x1c, 0x17, 0x57,
0xbc, 0x92, 0xcc, 0xb4, 0xcc, 0xd4, 0x22, 0x09, 0x26, 0xa0, 0x18, 0xa7, 0x10, 0x37, 0x17, 0x73, 0x66, 0x4a, 0x6a, 0x5e, 0x49, 0x66, 0x5a, 0x66, 0x6a, 0x91, 0x04, 0x13, 0x50, 0x9a, 0x33, 0x08,
0x4e, 0x7e, 0xba, 0x04, 0x33, 0x88, 0xa3, 0xc4, 0xca, 0xc5, 0xec, 0x98, 0x9c, 0x6d, 0xa4, 0xcf, 0x49, 0x44, 0x48, 0x80, 0x8b, 0x39, 0x27, 0x3f, 0x5d, 0x82, 0x19, 0x2c, 0x01, 0x62, 0x2a, 0xb1,
0xc5, 0xe3, 0x82, 0x64, 0xb8, 0x90, 0x3c, 0x17, 0x7b, 0x70, 0x6a, 0x5e, 0x0a, 0xc8, 0x54, 0x0e, 0x72, 0x31, 0x3b, 0x26, 0x67, 0x1b, 0xe9, 0x73, 0xf1, 0xb8, 0x20, 0x59, 0x2c, 0x24, 0xcf, 0xc5,
0x3d, 0xa0, 0x15, 0x7a, 0x40, 0x96, 0x14, 0x84, 0x05, 0x54, 0xae, 0xc4, 0x90, 0xc4, 0x06, 0xb6, 0x1e, 0x9c, 0x9a, 0x97, 0x02, 0xb2, 0x91, 0x43, 0x0f, 0x68, 0xbd, 0x1e, 0x90, 0x25, 0x05, 0x61,
0xde, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x16, 0xf4, 0xd0, 0x37, 0xa3, 0x00, 0x00, 0x00, 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 { ...@@ -144,8 +144,15 @@ message LaunchSignature {
repeated bytes keyHash = 4; repeated bytes keyHash = 4;
/// The signing sequence generated on-the-fly by the platform /// The signing sequence generated on-the-fly by the platform
repeated uint32 sequence = 5; 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 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: /// The signature is computed using auth.SignStructure function:
/// PKCS1v15 + SHA512 hash of the string representation of the structure /// PKCS1v15 + SHA512 hash of the string representation of the structure
bytes seal = 6; bytes seal = 10;
} }
...@@ -22,12 +22,13 @@ type PlatformID struct { ...@@ -22,12 +22,13 @@ type PlatformID struct {
// Initialize creates and saves the platform's private key and root certificate to a PEM format. // 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. // 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. // 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. // Generate the private key.
key, err := auth.GeneratePrivateKey(v.GetInt("key_size")) key, err := auth.GeneratePrivateKey(v.GetInt("key_size"))
if err != nil { if err != nil {
return err return nil, err
} }
var cert []byte var cert []byte
...@@ -50,24 +51,25 @@ func Initialize(v *viper.Viper, ca *x509.Certificate, rKey *rsa.PrivateKey) erro ...@@ -50,24 +51,25 @@ func Initialize(v *viper.Viper, ca *x509.Certificate, rKey *rsa.PrivateKey) erro
} }
if err != nil { if err != nil {
return err return nil, err
} }
// Create missing folders, if needed // Create missing folders, if needed
err = os.MkdirAll(path, os.ModeDir|0700) err = os.MkdirAll(path, os.ModeDir|0700)
if err != nil { if err != nil {
return err return nil, err
} }
// Convert the private key to a PEM format, and save it. // Convert the private key to a PEM format, and save it.
keyPem := auth.PrivateKeyToPEM(key) keyPem := auth.PrivateKeyToPEM(key)
err = ioutil.WriteFile(keyPath, keyPem, 0600) err = ioutil.WriteFile(keyPath, keyPem, 0600)
if err != nil { if err != nil {
return err return nil, err
} }
// Save the root certificate. // 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. // Start fetches the platform's private rsa key and root certificate, and create a PlatformID accordingly.
......
...@@ -8,10 +8,9 @@ import ( ...@@ -8,10 +8,9 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/spf13/viper"
"dfss/auth" "dfss/auth"
"dfss/dfssc/common" "dfss/dfssc/common"
"github.com/spf13/viper"
) )
var ( var (
...@@ -36,9 +35,9 @@ func TestInitialize(t *testing.T) { ...@@ -36,9 +35,9 @@ func TestInitialize(t *testing.T) {
certPath := filepath.Join(path, RootCAFileName) certPath := filepath.Join(path, RootCAFileName)
v := common.MockViper("key_size", 1024, "validity", 365, "country", "country", "organization", "organization", "unit", "unit", "cn", "cn", "path", path) 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) t.Fatal(err)
} }
...@@ -60,8 +59,8 @@ func Example() { ...@@ -60,8 +59,8 @@ func Example() {
// Generate root certificate and key // Generate root certificate and key
v := common.MockViper("key_size", 1024, "validity", 365, "country", "UK", "organization", "DFSS", "unit", "unit", "cn", "ROOT", "path", path) v := common.MockViper("key_size", 1024, "validity", 365, "country", "UK", "organization", "DFSS", "unit", "unit", "cn", "ROOT", "path", path)
err := Initialize(v, nil, nil) hash, err := Initialize(v, nil, nil)
if err != nil { if err != nil || hash == nil {
fmt.Println(err) fmt.Println(err)
return return
} }
...@@ -79,7 +78,7 @@ func Example() { ...@@ -79,7 +78,7 @@ func Example() {
// Generate child certificate and key // Generate child certificate and key
childPath := filepath.Join(path, "child") childPath := filepath.Join(path, "child")
v = common.MockViper("key_size", 1024, "validity", 10, "country", "FR", "organization", "DFSS", "unit", "unit", "cn", "CHILD", "path", childPath) 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 { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
...@@ -107,7 +106,7 @@ func CheckFile(path, name string) { ...@@ -107,7 +106,7 @@ func CheckFile(path, name string) {
func TestStart(t *testing.T) { func TestStart(t *testing.T) {
path, _ := ioutil.TempDir("", "") path, _ := ioutil.TempDir("", "")
v := common.MockViper("key_size", 1024, "validity", 365, "country", "country", "organization", "organization", "unit", "unit", "cn", "cn", "path", path) 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) pid, err := Start(path)
if err != nil { 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)