Skip to content

Commit

Permalink
Implement /verifysignature endpoint
Browse files Browse the repository at this point in the history
This endpoint allows verification of a SignedMessage.
Currently, there's no authorization: as the user already has a signature,
and authenticator does not prevent doing disclosures with excessive personal
data. However, it should still probably be implement to prevent freeloading
on a public irma server.
  • Loading branch information
DeD1rk committed Nov 8, 2024
1 parent fbb506e commit da76d4c
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 8 deletions.
38 changes: 30 additions & 8 deletions requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import (
)

const (
LDContextDisclosureRequest = "https://irma.app/ld/request/disclosure/v2"
LDContextSignatureRequest = "https://irma.app/ld/request/signature/v2"
LDContextIssuanceRequest = "https://irma.app/ld/request/issuance/v2"
LDContextRevocationRequest = "https://irma.app/ld/request/revocation/v1"
LDContextFrontendOptionsRequest = "https://irma.app/ld/request/frontendoptions/v1"
LDContextClientSessionRequest = "https://irma.app/ld/request/client/v1"
LDContextSessionOptions = "https://irma.app/ld/options/v1"
DefaultJwtValidity = 120
LDContextDisclosureRequest = "https://irma.app/ld/request/disclosure/v2"
LDContextSignatureRequest = "https://irma.app/ld/request/signature/v2"
LDContextIssuanceRequest = "https://irma.app/ld/request/issuance/v2"
LDContextRevocationRequest = "https://irma.app/ld/request/revocation/v1"
LDContextSignatureVerificationRequest = "https://irma.app/ld/request/signatureverification/v1"
LDContextFrontendOptionsRequest = "https://irma.app/ld/request/frontendoptions/v1"
LDContextClientSessionRequest = "https://irma.app/ld/request/client/v1"
LDContextSessionOptions = "https://irma.app/ld/options/v1"
DefaultJwtValidity = 120
)

// BaseRequest contains information used by all IRMA session types, such the context and nonce,
Expand Down Expand Up @@ -271,6 +272,27 @@ type ClientSessionRequest struct {
Request SessionRequest `json:"request,omitempty"`
}

// A SignatureVerificationRequest is a request to verify a SignedMessage.
type SignatureVerificationRequest struct {
LDContext string `json:"@context,omitempty"`
Signature SignedMessage `json:"signature"`

// Optionally, the SignedMessage can be verified against a SignatureRequest
Request *SignatureRequest `json:"request,omitempty"`
}

func (r *SignatureVerificationRequest) Validate() error {
if r.LDContext != LDContextSignatureVerificationRequest {
return errors.New("not a signature verification request")
}
if r.Request != nil {
if err := r.Request.Validate(); err != nil {
return err
}
}
return nil
}

func (choice *DisclosureChoice) Validate() error {
if choice == nil {
return nil
Expand Down
24 changes: 24 additions & 0 deletions server/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ type LegacySessionResult struct {
Err *irma.RemoteError `json:"error,omitempty"`
}

type SignatureVerificationResult struct {
ProofStatus irma.ProofStatus `json:"proofStatus,omitempty"`
Disclosed [][]*irma.DisclosedAttribute `json:"disclosed,omitempty"`
Err *irma.RemoteError `json:"error,omitempty"`
}

const (
ComponentRevocation = "revocation"
ComponentSession = "session"
Expand Down Expand Up @@ -269,6 +275,24 @@ func wrapSessionRequest(request irma.SessionRequest) (irma.RequestorRequest, err
}
}

func ParseSignatureVerificationRequest(request interface{}) (*irma.SignatureVerificationRequest, error) {
switch r := request.(type) {
case irma.SignatureVerificationRequest:
return &r, nil
case string:
return ParseSignatureVerificationRequest([]byte(r))
case []byte:
msg := irma.SignatureVerificationRequest{}
if err := irma.UnmarshalValidate(r, &msg); err != nil {
return nil, err
}

return &msg, nil
default:
return nil, errors.New("Invalid request type")
}
}

// LocalIP returns the IP address of one of the (non-loopback) network interfaces
func LocalIP() (string, error) {
// Based on https://play.golang.org/p/BDt3qEQ_2H from https://stackoverflow.com/a/23558495
Expand Down
28 changes: 28 additions & 0 deletions server/requestorserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ func (s *Server) Handler() http.Handler {
})

r.Get("/publickey", s.handlePublicKey)
r.Post("/verifysignature", s.handleVerifySignature)
})

router.Group(func(r chi.Router) {
Expand Down Expand Up @@ -492,6 +493,33 @@ func (s *Server) handlePublicKey(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(pubBytes)
}

func (s *Server) handleVerifySignature(w http.ResponseWriter, r *http.Request) {
defer common.Close(r.Body)
body, err := io.ReadAll(r.Body)
if err != nil {
s.conf.Logger.Error("Could not read signature verification request HTTP POST body")
_ = server.LogError(err)
server.WriteError(w, server.ErrorInvalidRequest, err.Error())
return
}

verreq, err := server.ParseSignatureVerificationRequest(body)
if err != nil {
server.WriteError(w, server.ErrorInvalidRequest, err.Error())
return
}

disclosed, proofStatus, err := verreq.Signature.Verify(s.conf.IrmaConfiguration, verreq.Request)
var rerr *irma.RemoteError
if err != nil && err == irma.ErrMissingPublicKey {
rerr = server.RemoteError(server.ErrorUnknownPublicKey, err.Error())
} else if err != nil {
rerr = server.RemoteError(server.ErrorUnknown, err.Error())
}
res := server.SignatureVerificationResult{ProofStatus: proofStatus, Disclosed: disclosed, Err: rerr}
server.WriteJson(w, res)
}

func (s *Server) createSession(w http.ResponseWriter, requestor string, rrequest irma.RequestorRequest) {
// Authorize request: check if the requestor is allowed to verify or issue
// the requested attributes or credentials
Expand Down

0 comments on commit da76d4c

Please sign in to comment.