Skip to content
Snippets Groups Projects
Unverified Commit c28f0099 authored by Bob Callaway's avatar Bob Callaway Committed by GitHub
Browse files

Add Log ID to LogEntry field (#294)


* Add Log ID to LogEntry field

Since the signed entry timestamp (SET) will be able to prove insertion into the log, adding the log ID (aka public key SHA256 hash) makes it easier to know which log the entry came from. 

Signed-off-by: default avatarBob Callaway <bob.callaway@gmail.com>
parent 603b4a8f
No related branches found
No related tags found
No related merge requests found
...@@ -40,10 +40,12 @@ type getCmdOutput struct { ...@@ -40,10 +40,12 @@ type getCmdOutput struct {
LogIndex int LogIndex int
IntegratedTime int64 IntegratedTime int64
UUID string UUID string
LogID string
} }
func (g *getCmdOutput) String() string { func (g *getCmdOutput) String() string {
s := fmt.Sprintf("Index: %d\n", g.LogIndex) s := fmt.Sprintf("LogID: %v\n", g.LogID)
s += fmt.Sprintf("Index: %d\n", g.LogIndex)
dt := time.Unix(g.IntegratedTime, 0).UTC().Format(time.RFC3339) dt := time.Unix(g.IntegratedTime, 0).UTC().Format(time.RFC3339)
s += fmt.Sprintf("IntegratedTime: %s\n", dt) s += fmt.Sprintf("IntegratedTime: %s\n", dt)
s += fmt.Sprintf("UUID: %s\n", g.UUID) s += fmt.Sprintf("UUID: %s\n", g.UUID)
...@@ -130,8 +132,9 @@ func parseEntry(uuid string, e models.LogEntryAnon) (interface{}, error) { ...@@ -130,8 +132,9 @@ func parseEntry(uuid string, e models.LogEntryAnon) (interface{}, error) {
obj := getCmdOutput{ obj := getCmdOutput{
Body: eimpl, Body: eimpl,
UUID: uuid, UUID: uuid,
IntegratedTime: e.IntegratedTime, IntegratedTime: *e.IntegratedTime,
LogIndex: int(*e.LogIndex), LogIndex: int(*e.LogIndex),
LogID: *e.LogID,
} }
return &obj, nil return &obj, nil
......
...@@ -291,6 +291,10 @@ definitions: ...@@ -291,6 +291,10 @@ definitions:
additionalProperties: additionalProperties:
type: object type: object
properties: properties:
logID:
type: string
pattern: '^[0-9a-fA-F]{64}$'
description: This is the SHA256 hash of the DER-encoded public key for the log at the time the entry was included in the log
logIndex: logIndex:
type: integer type: integer
minimum: 0 minimum: 0
...@@ -311,10 +315,12 @@ definitions: ...@@ -311,10 +315,12 @@ definitions:
# 1. Remove the Verification object from the JSON Document # 1. Remove the Verification object from the JSON Document
# 2. Canonicalize the remaining JSON document by following RFC 8785 rules # 2. Canonicalize the remaining JSON document by following RFC 8785 rules
# 3. Verify the canonicalized payload and signedEntryTimestamp against rekor's public key # 3. Verify the canonicalized payload and signedEntryTimestamp against rekor's public key
description: Signature over the logIndex, body and integratedTime. description: Signature over the logID, logIndex, body and integratedTime.
required: required:
- "logID"
- "logIndex" - "logIndex"
- "body" - "body"
- "integratedTime"
SearchIndex: SearchIndex:
type: object type: object
......
...@@ -17,7 +17,9 @@ package api ...@@ -17,7 +17,9 @@ package api
import ( import (
"context" "context"
"crypto/sha256"
"crypto/x509" "crypto/x509"
"encoding/hex"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"time" "time"
...@@ -47,12 +49,12 @@ func dial(ctx context.Context, rpcServer string) (*grpc.ClientConn, error) { ...@@ -47,12 +49,12 @@ func dial(ctx context.Context, rpcServer string) (*grpc.ClientConn, error) {
} }
type API struct { type API struct {
logClient trillian.TrillianLogClient logClient trillian.TrillianLogClient
logID int64 logID int64
// PEM encoded public key pubkey string // PEM encoded public key
pubkey string pubkeyHash string // SHA256 hash of DER-encoded public key
signer signature.Signer signer signature.Signer
verifier *client.LogVerifier verifier *client.LogVerifier
} }
func NewAPI() (*API, error) { func NewAPI() (*API, error) {
...@@ -95,6 +97,12 @@ func NewAPI() (*API, error) { ...@@ -95,6 +97,12 @@ func NewAPI() (*API, error) {
if err != nil { if err != nil {
return nil, errors.Wrap(err, "marshalling public key") return nil, errors.Wrap(err, "marshalling public key")
} }
hasher := sha256.New()
if _, err = hasher.Write(b); err != nil {
return nil, errors.Wrap(err, "computing hash of public key")
}
pubkeyHashBytes := hasher.Sum(nil)
pubkey := pem.EncodeToMemory(&pem.Block{ pubkey := pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY", Type: "PUBLIC KEY",
Bytes: b, Bytes: b,
...@@ -106,11 +114,12 @@ func NewAPI() (*API, error) { ...@@ -106,11 +114,12 @@ func NewAPI() (*API, error) {
} }
return &API{ return &API{
logClient: logClient, logClient: logClient,
logID: tLogID, logID: tLogID,
pubkey: string(pubkey), pubkey: string(pubkey),
signer: signer, pubkeyHash: hex.EncodeToString(pubkeyHashBytes),
verifier: verifier, signer: signer,
verifier: verifier,
}, nil }, nil
} }
......
...@@ -62,9 +62,10 @@ func logEntryFromLeaf(tc TrillianClient, leaf *trillian.LogLeaf, signedLogRoot * ...@@ -62,9 +62,10 @@ func logEntryFromLeaf(tc TrillianClient, leaf *trillian.LogLeaf, signedLogRoot *
logEntry := models.LogEntry{ logEntry := models.LogEntry{
hex.EncodeToString(leaf.MerkleLeafHash): models.LogEntryAnon{ hex.EncodeToString(leaf.MerkleLeafHash): models.LogEntryAnon{
LogID: swag.String(api.pubkeyHash),
LogIndex: &leaf.LeafIndex, LogIndex: &leaf.LeafIndex,
Body: leaf.LeafValue, Body: leaf.LeafValue,
IntegratedTime: leaf.IntegrateTimestamp.AsTime().Unix(), IntegratedTime: swag.Int64(leaf.IntegrateTimestamp.AsTime().Unix()),
Verification: &models.LogEntryAnonVerification{ Verification: &models.LogEntryAnonVerification{
InclusionProof: &inclusionProof, InclusionProof: &inclusionProof,
}, },
...@@ -143,9 +144,10 @@ func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Respo ...@@ -143,9 +144,10 @@ func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Respo
uuid := hex.EncodeToString(queuedLeaf.GetMerkleLeafHash()) uuid := hex.EncodeToString(queuedLeaf.GetMerkleLeafHash())
logEntryAnon := models.LogEntryAnon{ logEntryAnon := models.LogEntryAnon{
LogID: swag.String(api.pubkeyHash),
LogIndex: swag.Int64(queuedLeaf.LeafIndex), LogIndex: swag.Int64(queuedLeaf.LeafIndex),
Body: queuedLeaf.GetLeafValue(), Body: queuedLeaf.GetLeafValue(),
IntegratedTime: queuedLeaf.IntegrateTimestamp.AsTime().Unix(), IntegratedTime: swag.Int64(queuedLeaf.IntegrateTimestamp.AsTime().Unix()),
} }
if viper.GetBool("enable_retrieve_api") { if viper.GetBool("enable_retrieve_api") {
......
...@@ -88,7 +88,13 @@ type LogEntryAnon struct { ...@@ -88,7 +88,13 @@ type LogEntryAnon struct {
Body interface{} `json:"body"` Body interface{} `json:"body"`
// integrated time // integrated time
IntegratedTime int64 `json:"integratedTime,omitempty"` // Required: true
IntegratedTime *int64 `json:"integratedTime"`
// This is the SHA256 hash of the DER-encoded public key for the log at the time the entry was included in the log
// Required: true
// Pattern: ^[0-9a-fA-F]{64}$
LogID *string `json:"logID"`
// log index // log index
// Required: true // Required: true
...@@ -107,6 +113,14 @@ func (m *LogEntryAnon) Validate(formats strfmt.Registry) error { ...@@ -107,6 +113,14 @@ func (m *LogEntryAnon) Validate(formats strfmt.Registry) error {
res = append(res, err) res = append(res, err)
} }
if err := m.validateIntegratedTime(formats); err != nil {
res = append(res, err)
}
if err := m.validateLogID(formats); err != nil {
res = append(res, err)
}
if err := m.validateLogIndex(formats); err != nil { if err := m.validateLogIndex(formats); err != nil {
res = append(res, err) res = append(res, err)
} }
...@@ -130,6 +144,28 @@ func (m *LogEntryAnon) validateBody(formats strfmt.Registry) error { ...@@ -130,6 +144,28 @@ func (m *LogEntryAnon) validateBody(formats strfmt.Registry) error {
return nil return nil
} }
func (m *LogEntryAnon) validateIntegratedTime(formats strfmt.Registry) error {
if err := validate.Required("integratedTime", "body", m.IntegratedTime); err != nil {
return err
}
return nil
}
func (m *LogEntryAnon) validateLogID(formats strfmt.Registry) error {
if err := validate.Required("logID", "body", m.LogID); err != nil {
return err
}
if err := validate.Pattern("logID", "body", *m.LogID, `^[0-9a-fA-F]{64}$`); err != nil {
return err
}
return nil
}
func (m *LogEntryAnon) validateLogIndex(formats strfmt.Registry) error { func (m *LogEntryAnon) validateLogIndex(formats strfmt.Registry) error {
if err := validate.Required("logIndex", "body", m.LogIndex); err != nil { if err := validate.Required("logIndex", "body", m.LogIndex); err != nil {
...@@ -214,7 +250,7 @@ type LogEntryAnonVerification struct { ...@@ -214,7 +250,7 @@ type LogEntryAnonVerification struct {
// inclusion proof // inclusion proof
InclusionProof *InclusionProof `json:"inclusionProof,omitempty"` InclusionProof *InclusionProof `json:"inclusionProof,omitempty"`
// Signature over the logIndex, body and integratedTime. // Signature over the logID, logIndex, body and integratedTime.
// Format: byte // Format: byte
SignedEntryTimestamp strfmt.Base64 `json:"signedEntryTimestamp,omitempty"` SignedEntryTimestamp strfmt.Base64 `json:"signedEntryTimestamp,omitempty"`
} }
......
...@@ -400,8 +400,10 @@ func init() { ...@@ -400,8 +400,10 @@ func init() {
"additionalProperties": { "additionalProperties": {
"type": "object", "type": "object",
"required": [ "required": [
"logID",
"logIndex", "logIndex",
"body" "body",
"integratedTime"
], ],
"properties": { "properties": {
"body": { "body": {
...@@ -411,6 +413,11 @@ func init() { ...@@ -411,6 +413,11 @@ func init() {
"integratedTime": { "integratedTime": {
"type": "integer" "type": "integer"
}, },
"logID": {
"description": "This is the SHA256 hash of the DER-encoded public key for the log at the time the entry was included in the log",
"type": "string",
"pattern": "^[0-9a-fA-F]{64}$"
},
"logIndex": { "logIndex": {
"type": "integer" "type": "integer"
}, },
...@@ -421,7 +428,7 @@ func init() { ...@@ -421,7 +428,7 @@ func init() {
"$ref": "#/definitions/InclusionProof" "$ref": "#/definitions/InclusionProof"
}, },
"signedEntryTimestamp": { "signedEntryTimestamp": {
"description": "Signature over the logIndex, body and integratedTime.", "description": "Signature over the logID, logIndex, body and integratedTime.",
"type": "string", "type": "string",
"format": "byte" "format": "byte"
} }
...@@ -1193,8 +1200,10 @@ func init() { ...@@ -1193,8 +1200,10 @@ func init() {
"LogEntryAnon": { "LogEntryAnon": {
"type": "object", "type": "object",
"required": [ "required": [
"logID",
"logIndex", "logIndex",
"body" "body",
"integratedTime"
], ],
"properties": { "properties": {
"body": { "body": {
...@@ -1204,6 +1213,11 @@ func init() { ...@@ -1204,6 +1213,11 @@ func init() {
"integratedTime": { "integratedTime": {
"type": "integer" "type": "integer"
}, },
"logID": {
"description": "This is the SHA256 hash of the DER-encoded public key for the log at the time the entry was included in the log",
"type": "string",
"pattern": "^[0-9a-fA-F]{64}$"
},
"logIndex": { "logIndex": {
"type": "integer", "type": "integer",
"minimum": 0 "minimum": 0
...@@ -1215,7 +1229,7 @@ func init() { ...@@ -1215,7 +1229,7 @@ func init() {
"$ref": "#/definitions/InclusionProof" "$ref": "#/definitions/InclusionProof"
}, },
"signedEntryTimestamp": { "signedEntryTimestamp": {
"description": "Signature over the logIndex, body and integratedTime.", "description": "Signature over the logID, logIndex, body and integratedTime.",
"type": "string", "type": "string",
"format": "byte" "format": "byte"
} }
...@@ -1230,7 +1244,7 @@ func init() { ...@@ -1230,7 +1244,7 @@ func init() {
"$ref": "#/definitions/InclusionProof" "$ref": "#/definitions/InclusionProof"
}, },
"signedEntryTimestamp": { "signedEntryTimestamp": {
"description": "Signature over the logIndex, body and integratedTime.", "description": "Signature over the logID, logIndex, body and integratedTime.",
"type": "string", "type": "string",
"format": "byte" "format": "byte"
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment