Skip to content
Open
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
83 changes: 72 additions & 11 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package api

import (
"crypto/sha3"
"encoding/base64"
"encoding/json"
"fmt"
Expand All @@ -13,13 +14,15 @@ import (
"github.com/veraison/cmw"
"github.com/veraison/ratsd/plugin"
"github.com/veraison/ratsd/proto/compositor"
ratsdtoken "github.com/veraison/ratsd/ratsd-token"
"go.uber.org/zap"
)

// Defines missing consts in the API Spec
const (
ApplicationvndVeraisonCharesJson string = "application/vnd.veraison.chares+json"
JsonType string = "application/json"
nonceAdjustFunction string = ratsdtoken.NonceAdjustFunctionShake256
)

type Server struct {
Expand All @@ -40,6 +43,23 @@ func responseCodeToHTTP(responseCode uint32) int {
}
}

func adjustNonce(nonce []byte, size uint32) ([]byte, error) {
if size == 0 {
return nil, fmt.Errorf("nonce size must be greater than zero")
}

adjusted := make([]byte, int(size))
h := sha3.NewSHAKE256()
if _, err := h.Write(nonce); err != nil {
return nil, err
}
if _, err := h.Read(adjusted); err != nil {
return nil, err
}

return adjusted, nil
}

func NewServer(logger *zap.SugaredLogger, manager plugin.IManager, options string) *Server {
return &Server{
logger: logger,
Expand Down Expand Up @@ -170,11 +190,20 @@ func (s *Server) RatsdChares(w http.ResponseWriter, r *http.Request, param Ratsd
s.logger.Info("request nonce: ", requestNonce)
s.logger.Info("request media type: ", *(param.Accept))

// Use a map until we finalize ratsd output format
eat := make(map[string]interface{})
evidence := ratsdtoken.NewEvidence()
if err := evidence.Claims.SetNonce(nonce); err != nil {
errMsg := fmt.Sprintf("invalid nonce in the request: %s", err.Error())
p := &problems.DefaultProblem{
Type: string(TagGithubCom2024VeraisonratsdErrorInvalidrequest),
Title: string(InvalidRequest),
Detail: errMsg,
Status: http.StatusBadRequest,
}
s.reportProblem(w, p)
return
}

collection := cmw.NewCollection("tag:github.com,2025:veraison/ratsd/cmw")
eat["eat_profile"] = TagGithubCom2024Veraisonratsd
eat["eat_nonce"] = requestNonce
pl := s.manager.GetPluginList()
if len(pl) == 0 {
errMsg := "no sub-attester available"
Expand Down Expand Up @@ -204,7 +233,8 @@ func (s *Server) RatsdChares(w http.ResponseWriter, r *http.Request, param Ratsd
return false
}

outputCt := formatOut.Formats[0].ContentType
selectedFormat := formatOut.Formats[0]
outputCt := selectedFormat.ContentType
params, hasOption := options[pn]
if !hasOption || string(params) == "null" {
params = json.RawMessage{}
Expand All @@ -227,7 +257,8 @@ func (s *Server) RatsdChares(w http.ResponseWriter, r *http.Request, param Ratsd
if desiredCt, ok := attesterOptions["content-type"]; ok {
for _, f := range formatOut.Formats {
if f.ContentType == desiredCt {
outputCt = desiredCt
selectedFormat = f
outputCt = selectedFormat.ContentType
validCt = true
break
}
Expand All @@ -249,9 +280,32 @@ func (s *Server) RatsdChares(w http.ResponseWriter, r *http.Request, param Ratsd
}

s.logger.Info(pn, " output content type: ", outputCt)
attesterNonce, err := adjustNonce(nonce, selectedFormat.NonceSize)
if err != nil {
errMsg := fmt.Sprintf(
"failed to adjust nonce for attester %s: %s", pn, err.Error())
p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg)
s.reportProblem(w, p)
return false
}

if err := evidence.Claims.SetNonceAdjustFn(nonceAdjustFunction); err != nil {
errMsg := fmt.Sprintf("failed to set nonce adjustment function: %s", err.Error())
p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg)
s.reportProblem(w, p)
return false
}

if err := evidence.Claims.SetKeyandNonceSz(pn, uint(selectedFormat.NonceSize)); err != nil {
errMsg := fmt.Sprintf("failed to set nonce adjustment map: %s", err.Error())
p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg)
s.reportProblem(w, p)
return false
}

in := &compositor.EvidenceIn{
ContentType: outputCt,
Nonce: nonce,
Nonce: attesterNonce,
Options: params,
}

Expand Down Expand Up @@ -288,17 +342,24 @@ func (s *Server) RatsdChares(w http.ResponseWriter, r *http.Request, param Ratsd
}
}

serialized, err := collection.MarshalJSON()
if err != nil {
if err := evidence.Claims.SetCMW(collection); err != nil {
errMsg := fmt.Sprintf("failed to serialize CMW collection: %s", err.Error())
p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg)
s.reportProblem(w, p)
return
}
eat["cmw"] = serialized

response, err := json.Marshal(evidence)
if err != nil {
errMsg := fmt.Sprintf("failed to serialize RATSD token: %s", err.Error())
p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg)
s.reportProblem(w, p)
return
}

w.Header().Set("Content-Type", respCt)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(eat)
w.Write(response)
}

func (s *Server) RatsdSubattesters(w http.ResponseWriter, r *http.Request) {
Expand Down
Loading
Loading