Skip to content

Commit

Permalink
TrustStore: Add chain push handler (#3501)
Browse files Browse the repository at this point in the history
Add certificate chain push handler to the trust store.

fixes #3486
  • Loading branch information
oncilla authored and scrye committed Dec 10, 2019
1 parent 2de21b4 commit 50b21fa
Show file tree
Hide file tree
Showing 5 changed files with 343 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go/lib/infra/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ type CryptoMaterialProvider interface {
// TrustStoreOpts contains the base options when interacting with the trust store.
type TrustStoreOpts struct {
// Server provides an address where the store should send crypto material
// request, if they are not available locally. If it is not set, the
// requests, if they are not available locally. If it is not set, the
// trust store does its own server resolution.
Server net.Addr
// LocalOnly indicates that the store should only check locally.
Expand Down
8 changes: 8 additions & 0 deletions go/lib/infra/modules/trust/v2/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"db.go",
"handlers.go",
"inserter.go",
"inspector.go",
"provider.go",
Expand All @@ -16,7 +17,10 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//go/lib/addr:go_default_library",
"//go/lib/common:go_default_library",
"//go/lib/ctrl/cert_mgmt:go_default_library",
"//go/lib/infra:go_default_library",
"//go/lib/infra/messenger:go_default_library",
"//go/lib/infra/modules/db:go_default_library",
"//go/lib/infra/modules/trust/v2/internal/decoded:go_default_library",
"//go/lib/log:go_default_library",
Expand All @@ -25,6 +29,7 @@ go_library(
"//go/lib/scrypto/trc/v2:go_default_library",
"//go/lib/serrors:go_default_library",
"//go/lib/snet:go_default_library",
"//go/proto:go_default_library",
"@org_golang_x_xerrors//:go_default_library",
],
)
Expand All @@ -33,6 +38,7 @@ go_test(
name = "go_default_test",
srcs = [
"export_test.go",
"handlers_test.go",
"inserter_test.go",
"inspector_test.go",
"main_test.go",
Expand All @@ -48,7 +54,9 @@ go_test(
deps = [
"//go/lib/addr:go_default_library",
"//go/lib/common:go_default_library",
"//go/lib/ctrl/cert_mgmt:go_default_library",
"//go/lib/infra:go_default_library",
"//go/lib/infra/mock_infra:go_default_library",
"//go/lib/infra/modules/trust/v2/internal/decoded:go_default_library",
"//go/lib/infra/modules/trust/v2/mock_v2:go_default_library",
"//go/lib/log:go_default_library",
Expand Down
15 changes: 15 additions & 0 deletions go/lib/infra/modules/trust/v2/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package trust

import (
"github.com/scionproto/scion/go/lib/addr"
"github.com/scionproto/scion/go/lib/infra"
"github.com/scionproto/scion/go/lib/snet"
)

Expand All @@ -41,6 +42,9 @@ var (
// NewResolver allows instantiating the private resolver for black-box
// testing.
NewResolver = newTestResolver
// NewChainPushHandler allows instantiating the private chain push handler for black-box
// testing.
NewChainPushHandler = newTestChainPushHandler
)

// newTestCryptoProvider returns a new crypto provider for testing.
Expand Down Expand Up @@ -105,3 +109,14 @@ func newTestResolver(db DBRead, inserter Inserter, rpc RPC) Resolver {
rpc: rpc,
}
}

// newChainPushHandler returns a new chain push handler for testing.
func newTestChainPushHandler(request *infra.Request, provider CryptoProvider,
inserter Inserter) *chainPushHandler {

return &chainPushHandler{
request: request,
provider: provider,
inserter: inserter,
}
}
107 changes: 107 additions & 0 deletions go/lib/infra/modules/trust/v2/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright 2019 Anapaya Systems
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package trust

import (
"context"
"errors"
"net"

"github.com/scionproto/scion/go/lib/addr"
"github.com/scionproto/scion/go/lib/common"
"github.com/scionproto/scion/go/lib/ctrl/cert_mgmt"
"github.com/scionproto/scion/go/lib/infra"
"github.com/scionproto/scion/go/lib/infra/messenger"
"github.com/scionproto/scion/go/lib/infra/modules/trust/v2/internal/decoded"
"github.com/scionproto/scion/go/lib/log"
"github.com/scionproto/scion/go/lib/scrypto"
"github.com/scionproto/scion/go/lib/scrypto/trc/v2"
"github.com/scionproto/scion/go/proto"
)

type chainPushHandler struct {
request *infra.Request
provider CryptoProvider
inserter Inserter
}

func (h *chainPushHandler) Handle() *infra.HandlerResult {
if h.request == nil {
log.Error("[TrustStore:chainPushHandler] Request is nil")
return infra.MetricsErrInternal
}
logger := log.FromCtx(h.request.Context())
if h.request.Message == nil {
logger.Error("[TrustStore:chainPushHandler] Request message is nil")
return infra.MetricsErrInternal
}
chainPush, ok := h.request.Message.(*cert_mgmt.Chain)
if !ok {
logger.Error("[TrustStore:chainPushHandler] Wrong message type, expected cert_mgmt.Chain",
"msg", h.request.Message, "type", common.TypeOf(h.request.Message))
return infra.MetricsErrInternal
}
logger.Trace("[TrustStore:chainPushHandler] Received push", "chainPush", chainPush,
"peer", h.request.Peer)
rw, ok := infra.ResponseWriterFromContext(h.request.Context())
if !ok {
logger.Warn(
"[TrustStore:chainPushHandler] Unable to service request, no ResponseWriter found")
return infra.MetricsErrInternal
}
sendAck := messenger.SendAckHelper(h.request.Context(), rw)

dec, err := decoded.DecodeChain(chainPush.RawChain)
if err != nil {
logger.Error("[TrustStore:chainPushHandler] Unable to parse chain from push", "err", err)
sendAck(proto.Ack_ErrCode_reject, messenger.AckRejectFailedToParse)
return infra.MetricsErrInvalid
}
err = h.inserter.InsertChain(h.request.Context(), dec, newTRCGetter(h.provider, h.request.Peer))
switch {
case err == nil:
sendAck(proto.Ack_ErrCode_ok, "")
return infra.MetricsResultOk
case errors.Is(err, ErrContentMismatch):
logger.Error("[TrustStore:chainPushHandler] Certificate already exists with different hash",
"err", err, "chain", dec, "peer", h.request.Peer)
sendAck(proto.Ack_ErrCode_reject, messenger.AckRejectFailedToVerify)
return infra.MetricsErrInvalid
case errors.Is(err, ErrValidation), errors.Is(err, ErrVerification):
logger.Error("[TrustStore:chainPushHandler] Unable to verify certificate chain",
"err", err, "chain", dec, "peer", h.request.Peer)
sendAck(proto.Ack_ErrCode_reject, messenger.AckRejectFailedToVerify)
return infra.MetricsErrInvalid
default:
logger.Error("[TrustStore:chainPushHandler] Error inserting certificate chain",
"err", err, "chain", dec, "peer", h.request.Peer)
sendAck(proto.Ack_ErrCode_reject, messenger.AckRetryDBError)
return infra.MetricsErrInternal
}
}

func newTRCGetter(provider CryptoProvider, peer net.Addr) func(context.Context,
addr.ISD, scrypto.Version) (*trc.TRC, error) {

return func(ctx context.Context, isd addr.ISD, version scrypto.Version) (*trc.TRC, error) {
opts := infra.TRCOpts{
TrustStoreOpts: infra.TrustStoreOpts{
Server: peer,
},
AllowInactive: true,
}
return provider.GetTRC(ctx, isd, version, opts)
}
}
Loading

0 comments on commit 50b21fa

Please sign in to comment.