Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upload generated timestamps #336

Merged
merged 5 commits into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions cmd/rekor-cli/app/pflags.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,27 +250,13 @@ func CreateIntotoFromPFlags() (models.ProposedEntry, error) {

func CreateRFC3161FromPFlags() (models.ProposedEntry, error) {
//TODO: how to select version of item to create
returnVal := models.Rfc3161{}

rfc3161 := viper.GetString("artifact")
b, err := ioutil.ReadFile(filepath.Clean(rfc3161))
if err != nil {
return nil, fmt.Errorf("error reading public key file: %w", err)
}

b64 := strfmt.Base64(b)
re := rfc3161_v001.V001Entry{
Rfc3161Obj: models.Rfc3161V001Schema{
Tsr: &models.Rfc3161V001SchemaTsr{
Content: &b64,
},
},
}

returnVal.Spec = re.Rfc3161Obj
returnVal.APIVersion = swag.String(re.APIVersion())

return &returnVal, nil
return rfc3161_v001.NewEntryFromBytes(b), nil
}

func CreateRpmFromPFlags() (models.ProposedEntry, error) {
Expand Down
27 changes: 18 additions & 9 deletions cmd/rekor-cli/app/timestamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"path/filepath"
"strconv"
"strings"
"time"

"github.com/sassoftware/relic/lib/pkcs9"
"github.com/sassoftware/relic/lib/x509tools"
Expand Down Expand Up @@ -94,7 +95,6 @@ func addTimestampFlags(cmd *cobra.Command) error {

cmd.Flags().String("out", "response.tsr", "path to a file to write response.")

// TODO: Add a flag to upload a pre-formed timestamp response to the log.
// TODO: Add a flag to indicate a JSON formatted timestamp request/response.
return nil
}
Expand Down Expand Up @@ -175,13 +175,15 @@ func createRequestFromFlags() (*pkcs9.TimeStampReq, error) {
}

type timestampCmdOutput struct {
Location string
Timestamp time.Time
Location string
UUID string
Index int64
}

func (t *timestampCmdOutput) String() string {
return fmt.Sprintf(`
Wrote response to: %v
`, t.Location)
return fmt.Sprintf("Artifact timestamped at %s\nWrote timestamp response to %v\nCreated entry at index %d, available at: %v%v\n",
t.Timestamp, t.Location, t.Index, viper.GetString("rekor_server"), t.UUID)
}

var timestampCmd = &cobra.Command{
Expand Down Expand Up @@ -218,12 +220,17 @@ var timestampCmd = &cobra.Command{
params.Request = ioutil.NopCloser(bytes.NewReader(requestBytes))

var respBytes bytes.Buffer
_, err = rekorClient.Timestamp.GetTimestampResponse(params, &respBytes)
resp, err := rekorClient.Timestamp.GetTimestampResponse(params, &respBytes)
if err != nil {
return nil, err
}
// Sanity check response and check if the TimeStampToken was successfully created
if _, err = timestampReq.ParseResponse(respBytes.Bytes()); err != nil {
psd, err := timestampReq.ParseResponse(respBytes.Bytes())
if err != nil {
return nil, err
}
genTime, err := util.GetSigningTime(psd)
if err != nil {
return nil, err
}

Expand All @@ -236,9 +243,11 @@ var timestampCmd = &cobra.Command{
return nil, err
}

// TODO: Add log index after support for uploading to transparency log is added.
return &timestampCmdOutput{
Location: outStr,
Location: outStr,
UUID: string(resp.Location),
Timestamp: genTime.Round(time.Second),
Index: resp.Index,
}, nil
}),
}
Expand Down
18 changes: 14 additions & 4 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,7 @@ paths:

/api/v1/timestamp:
post:
# TODO: Add uploads to transparency log.
summary: Returns a timestamp response generated by Rekor
summary: Generates a new timestamp response and creates a new log entry for the timestamp in the transparency log
operationId: getTimestampResponse
tags:
- timestamp
Expand All @@ -244,11 +243,22 @@ paths:
type: string
format: binary
responses:
200:
description: Returns a timestamp response
201:
description: Returns a timestamp response and the location of the log entry in the transprency log
schema:
asraa marked this conversation as resolved.
Show resolved Hide resolved
type: string
format: binary
headers:
ETag:
type: string
description: UUID of the log entry made for the timestamp response
Location:
type: string
description: URI location of the log entry made for the timestamp response
format: uri
Index:
type: integer
description: Log index of the log entry made for the timestamp response
400:
$ref: '#/responses/BadContent'
501:
Expand Down
39 changes: 27 additions & 12 deletions pkg/api/entries.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,26 +127,23 @@ func GetLogEntryByIndexHandler(params entries.GetLogEntryByIndexParams) middlewa
return entries.NewGetLogEntryByIndexOK().WithPayload(logEntry)
}

// CreateLogEntryHandler creates new entry into log
func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Responder {
func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middleware.Responder) {
ctx := params.HTTPRequest.Context()
httpReq := params.HTTPRequest
entry, err := types.NewEntry(params.ProposedEntry)
if err != nil {
return handleRekorAPIError(params, http.StatusBadRequest, err, err.Error())
return nil, handleRekorAPIError(params, http.StatusBadRequest, err, err.Error())
}

leaf, err := entry.Canonicalize(httpReq.Context())
leaf, err := entry.Canonicalize(ctx)
if err != nil {
return handleRekorAPIError(params, http.StatusInternalServerError, err, failedToGenerateCanonicalEntry)
return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, failedToGenerateCanonicalEntry)
}

tc := NewTrillianClient(httpReq.Context())
tc := NewTrillianClient(ctx)

resp := tc.addLeaf(leaf)
// this represents overall GRPC response state (not the results of insertion into the log)
if resp.status != codes.OK {
return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult)
return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult)
}

// this represents the results of inserting the proposed leaf into the log; status is nil in success path
Expand All @@ -156,9 +153,11 @@ func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Respo
case int32(code.Code_OK):
case int32(code.Code_ALREADY_EXISTS), int32(code.Code_FAILED_PRECONDITION):
existingUUID := hex.EncodeToString(rfc6962.DefaultHasher.HashLeaf(leaf))
return handleRekorAPIError(params, http.StatusConflict, fmt.Errorf("grpc error: %v", insertionStatus.String()), fmt.Sprintf(entryAlreadyExists, existingUUID), "entryURL", getEntryURL(*httpReq.URL, existingUUID))
err := fmt.Errorf("grpc error: %v", insertionStatus.String())
return nil, handleRekorAPIError(params, http.StatusConflict, err, fmt.Sprintf(entryAlreadyExists, existingUUID), "entryURL", getEntryURL(*params.HTTPRequest.URL, existingUUID))
default:
return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %v", insertionStatus.String()), trillianUnexpectedResult)
err := fmt.Errorf("grpc error: %v", insertionStatus.String())
return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, trillianUnexpectedResult)
}
}

Expand Down Expand Up @@ -201,7 +200,7 @@ func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Respo

signature, err := signEntry(ctx, api.signer, logEntryAnon)
if err != nil {
return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("signing entry error: %v", err), signingError)
return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("signing entry error: %v", err), signingError)
}

logEntryAnon.Verification = &models.LogEntryAnonVerification{
Expand All @@ -211,6 +210,22 @@ func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Respo
logEntry := models.LogEntry{
uuid: logEntryAnon,
}
return logEntry, nil
}

// CreateLogEntryHandler creates new entry into log
func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Responder {
httpReq := params.HTTPRequest

logEntry, err := createLogEntry(params)
if err != nil {
return err
}

var uuid string
for location := range logEntry {
uuid = location
}

return entries.NewCreateLogEntryCreated().WithPayload(logEntry).WithLocation(getEntryURL(*httpReq.URL, uuid)).WithETag(uuid)
}
Expand Down
32 changes: 27 additions & 5 deletions pkg/api/timestamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import (
"github.com/go-openapi/runtime/middleware"
"github.com/pkg/errors"
"github.com/sassoftware/relic/lib/pkcs9"
"github.com/sigstore/rekor/pkg/generated/restapi/operations/entries"
"github.com/sigstore/rekor/pkg/generated/restapi/operations/timestamp"
"github.com/sigstore/rekor/pkg/log"
rfc3161_v001 "github.com/sigstore/rekor/pkg/types/rfc3161/v0.0.1"
"github.com/sigstore/rekor/pkg/util"
)

Expand Down Expand Up @@ -62,15 +63,36 @@ func TimestampResponseHandler(params timestamp.GetTimestampResponseParams) middl
}

// Create response
ctx := params.HTTPRequest.Context()
httpReq := params.HTTPRequest
ctx := httpReq.Context()
resp, err := RequestFromRekor(ctx, *req)
if err != nil {
return handleRekorAPIError(params, http.StatusInternalServerError, err, failedToGenerateTimestampResponse)
}

// TODO: Upload to transparency log and add entry UUID to location header.
log.Logger.Errorf("generated OK")
return timestamp.NewGetTimestampResponseOK().WithPayload(ioutil.NopCloser(bytes.NewReader(resp)))
// Upload to transparency log and add entry UUID to location header.
cleReq := *httpReq
cleURL := entries.CreateLogEntryURL{}
cleReq.URL = cleURL.Must(cleURL.Build())
entryParams := entries.CreateLogEntryParams{
HTTPRequest: &cleReq,
ProposedEntry: rfc3161_v001.NewEntryFromBytes(resp),
}

// If middleware is returned, this indicates an error.
logEntry, middleware := createLogEntry(entryParams)
if middleware != nil {
return middleware
bobcallaway marked this conversation as resolved.
Show resolved Hide resolved
}

var uuid string
var newIndex int64
for location, entry := range logEntry {
uuid = location
newIndex = *entry.LogIndex
}

return timestamp.NewGetTimestampResponseCreated().WithPayload(ioutil.NopCloser(bytes.NewReader(resp))).WithLocation(getEntryURL(*cleReq.URL, uuid)).WithETag(uuid).WithIndex(newIndex)
}

func GetTimestampCertChainHandler(params timestamp.GetTimestampCertChainParams) middleware.Responder {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading