Skip to content

Commit

Permalink
Merge branch 'master' into doc-small-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
oncilla authored Sep 24, 2024
2 parents e30c93a + 9ceb22a commit f07fe5c
Show file tree
Hide file tree
Showing 37 changed files with 572 additions and 123 deletions.
1 change: 1 addition & 0 deletions doc/command/scion-pki/scion-pki.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ SEE ALSO
* :ref:`scion-pki certificate <scion-pki_certificate>` - Manage certificates for the SCION control plane PKI.
* :ref:`scion-pki completion <scion-pki_completion>` - Generate the autocompletion script for the specified shell
* :ref:`scion-pki key <scion-pki_key>` - Manage private and public keys
* :ref:`scion-pki kms <scion-pki_kms>` - Run the step-kms-plugin
* :ref:`scion-pki trc <scion-pki_trc>` - Manage TRCs for the SCION control plane PKI
* :ref:`scion-pki version <scion-pki_version>` - Show the scion-pki version information

2 changes: 2 additions & 0 deletions doc/command/scion-pki/scion-pki_certificate_create.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,14 @@ Options
--bundle Bundle the certificate with the issuer certificate as a certificate chain
--ca string The path to the issuer certificate
--ca-key string The path to the issuer private key used to sign the new certificate
--ca-kms string The uri to configure a Cloud KMS or an HSM used for signing the certificate.
--common-name string The common name that replaces the common name in the subject template
--csr Generate a certificate signign request instead of a certificate
--curve string The elliptic curve to use (P-256|P-384|P-521) (default "P-256")
--force Force overwritting existing files
-h, --help help for create
--key string The path to the existing private key to use instead of creating a new one
--kms string The uri to configure a Cloud KMS or an HSM.
--not-after time The NotAfter time of the certificate. Can either be a timestamp or an offset.
If the value is a timestamp, it is expected to either be an RFC 3339 formatted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Options
::

-h, --help help for private
--kms string The uri to configure a Cloud KMS or an HSM.
--separator string The separator between file names (default "\n")

SEE ALSO
Expand Down
1 change: 1 addition & 0 deletions doc/command/scion-pki/scion-pki_certificate_sign.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Options
--bundle Bundle the certificate with the issuer certificate as a certificate chain
--ca string The path to the issuer certificate
--ca-key string The path to the issuer private key used to sign the new certificate
--ca-kms string The uri to configure a Cloud KMS or an HSM used for signing the certificate.
-h, --help help for sign
--not-after time The NotAfter time of the certificate. Can either be a timestamp or an offset.
Expand Down
1 change: 1 addition & 0 deletions doc/command/scion-pki/scion-pki_key_match_certificate.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Options
::

-h, --help help for certificate
--kms string The uri to configure a Cloud KMS or an HSM.
--separator string The separator between file names (default "\n")

SEE ALSO
Expand Down
1 change: 1 addition & 0 deletions doc/command/scion-pki/scion-pki_key_public.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Options

--force Force overwritting existing public key
-h, --help help for public
--kms string The uri to configure a Cloud KMS or an HSM.
--out string Path to write public key

SEE ALSO
Expand Down
45 changes: 45 additions & 0 deletions doc/command/scion-pki/scion-pki_kms.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
:orphan:

.. _scion-pki_kms:

scion-pki kms
-------------

Run the step-kms-plugin

Synopsis
~~~~~~~~


This command leverages the step-kms-plugin to interact with cloud Key Management
Systems (KMS) and Hardware Security Modules (HSM).

The commands are passed directly to the step-kms-plugin. For more information on
the available commands and their usage, please refer to the step-kms-plugin
documentation at https://github.com/smallstep/step-kms-plugin. In order to enable
KMS support, the step-kms-plugin must be installed and available in the PATH.

Various commands of the scion-pki tool allow the use of KMS. In all cases, the
private key needs to already exist in the KMS. To instruct the scion-pki tool to
use the key in the KMS, the --kms flag must be set.

For more information about supported KMSs and uri pattern, please consult
https://smallstep.com/docs/step-ca/cryptographic-protection.


::

scion-pki kms [command] [flags]

Options
~~~~~~~

::

-h, --help help for kms

SEE ALSO
~~~~~~~~

* :ref:`scion-pki <scion-pki>` - SCION Control Plane PKI Management Tool

1 change: 1 addition & 0 deletions doc/command/scion-pki/scion-pki_trc_sign.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Options
::

-h, --help help for sign
--kms string The uri to configure a Cloud KMS or an HSM.
-o, --out string Output file path. If --out is set, --out-dir is ignored.
--out-dir string Output directory. If --out is set, --out-dir is ignored. (default ".")

Expand Down
48 changes: 35 additions & 13 deletions private/path/combinator/combinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ package combinator
import (
"crypto/sha256"
"encoding/binary"
"sort"
"hash"
"slices"

"github.com/scionproto/scion/pkg/addr"
seg "github.com/scionproto/scion/pkg/segment"
Expand Down Expand Up @@ -61,8 +62,9 @@ func Combine(src, dst addr.IA, ups, cores, downs []*seg.PathSegment,

solutions := newDMG(ups, cores, downs).GetPaths(vertexFromIA(src), vertexFromIA(dst))
paths := make([]Path, len(solutions))
st := newHashState()
for i, solution := range solutions {
paths[i] = solution.Path()
paths[i] = solution.Path(st)
}
paths = filterLongPaths(paths)
if !findAllIdentical {
Expand All @@ -72,10 +74,11 @@ func Combine(src, dst addr.IA, ups, cores, downs []*seg.PathSegment,
}

type Path struct {
Dst addr.IA
SCIONPath path.SCION
Metadata snet.PathMetadata
Weight int // XXX(matzf): unused, drop this?
Dst addr.IA
SCIONPath path.SCION
Metadata snet.PathMetadata
Weight int // XXX(matzf): unused, drop this?
Fingerprint snet.PathFingerprint
}

// filterLongPaths returns a new slice containing only those paths that do not
Expand Down Expand Up @@ -112,18 +115,17 @@ func filterDuplicates(paths []Path) []Path {
// unique path interface sequence (== fingerprint).
uniquePaths := make(map[snet.PathFingerprint]int)
for i, p := range paths {
key := fingerprint(p.Metadata.Interfaces)
prev, dupe := uniquePaths[key]
prev, dupe := uniquePaths[p.Fingerprint]
if !dupe || p.Metadata.Expiry.After(paths[prev].Metadata.Expiry) {
uniquePaths[key] = i
uniquePaths[p.Fingerprint] = i
}
}

toKeep := make([]int, 0, len(uniquePaths))
for _, idx := range uniquePaths {
toKeep = append(toKeep, idx)
}
sort.Ints(toKeep)
slices.Sort(toKeep)
filtered := make([]Path, 0, len(toKeep))
for _, i := range toKeep {
filtered = append(filtered, paths[i])
Expand All @@ -135,8 +137,9 @@ func filterDuplicates(paths []Path) []Path {
// ASes and BRs, i.e. by its PathInterfaces.
// XXX(matzf): copied from snet.Fingerprint. Perhaps snet.Fingerprint could be adapted to
// take []snet.PathInterface directly.
func fingerprint(interfaces []snet.PathInterface) snet.PathFingerprint {
h := sha256.New()
func fingerprint(interfaces []snet.PathInterface, st hashState) snet.PathFingerprint {
h := st.hash
h.Reset()
for _, intf := range interfaces {
if err := binary.Write(h, binary.BigEndian, intf.IA); err != nil {
panic(err)
Expand All @@ -145,5 +148,24 @@ func fingerprint(interfaces []snet.PathInterface) snet.PathFingerprint {
panic(err)
}
}
return snet.PathFingerprint(h.Sum(nil))
// convert the snet.PathFingerprint, this is safe because the underlying
// type is string.
return snet.PathFingerprint(h.Sum(st.buf[:0]))
}

func checkUnderlyingType[S ~string](_ S) bool { return true }

// This check ensures that the underlying type of the PathFingerprint
// is string. This is required to create a copy of the buffer. If it were
// to be moved to a []byte, we need to change the code to create
// a proper copy.
var _ = checkUnderlyingType(snet.PathFingerprint(""))

type hashState struct {
hash hash.Hash
buf []byte
}

func newHashState() hashState {
return hashState{hash: sha256.New(), buf: make([]byte, 0, sha256.Size)}
}
1 change: 1 addition & 0 deletions private/path/combinator/combinator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,7 @@ func TestFilterDuplicates(t *testing.T) {
Interfaces: interfaces,
Expiry: expiry,
},
Fingerprint: combinator.Fingerprint(interfaces, combinator.NewHashState()),
}
}

Expand Down
2 changes: 2 additions & 0 deletions private/path/combinator/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ package combinator

var (
FilterDuplicates = filterDuplicates
Fingerprint = fingerprint
NewHashState = newHashState
)
90 changes: 39 additions & 51 deletions private/path/combinator/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ package combinator

import (
"bytes"
"cmp"
"encoding/binary"
"fmt"
"math"
"sort"
"slices"
"time"

"github.com/scionproto/scion/pkg/addr"
Expand Down Expand Up @@ -193,9 +194,9 @@ func (g *dmg) AddEdge(src, dst vertex, segment *inputSegment, e *edge) {
}

// GetPaths returns all the paths from src to dst, sorted according to weight.
func (g *dmg) GetPaths(src, dst vertex) pathSolutionList {
var solutions pathSolutionList
queue := pathSolutionList{&pathSolution{currentVertex: src}}
func (g *dmg) GetPaths(src, dst vertex) []*pathSolution {
var solutions []*pathSolution
queue := []*pathSolution{{currentVertex: src}}
for len(queue) > 0 {
currentPathSolution := queue[0]
queue = queue[1:]
Expand Down Expand Up @@ -234,7 +235,29 @@ func (g *dmg) GetPaths(src, dst vertex) pathSolutionList {
}
}
}
sort.Sort(solutions)
slices.SortFunc(solutions, func(a, b *pathSolution) int {
d := cmp.Or(
cmp.Compare(a.cost, b.cost),
cmp.Compare(len(a.edges), len(b.edges)),
)
if d != 0 {
return d
}
trailA, trailB := a.edges, b.edges
for ka := range trailA {
idA := trailA[ka].segment.ID()
idB := trailB[ka].segment.ID()
d := cmp.Or(
bytes.Compare(idA, idB),
cmp.Compare(trailA[ka].edge.Shortcut, trailB[ka].edge.Shortcut),
cmp.Compare(trailA[ka].edge.Peer, trailB[ka].edge.Peer),
)
if d != 0 {
return d
}
}
return 0
})
return solutions
}

Expand All @@ -247,13 +270,21 @@ func (g *dmg) GetPaths(src, dst vertex) pathSolutionList {
type inputSegment struct {
*seg.PathSegment
Type proto.PathSegType
id []byte
}

// IsDownSeg returns true if the segment is a DownSegment.
func (s *inputSegment) IsDownSeg() bool {
return s.Type == proto.PathSegType_down
}

func (s *inputSegment) ID() []byte {
if s.id == nil {
s.id = s.PathSegment.ID()
}
return s.id
}

// Vertex is a union-like type for the AS vertices and Peering link vertices in
// a DMG that can be used as key in maps.
type vertex struct {
Expand Down Expand Up @@ -310,7 +341,7 @@ type pathSolution struct {

// Path builds the forwarding path with metadata by extracting it from a path
// between source and destination in the DMG.
func (solution *pathSolution) Path() Path {
func (solution *pathSolution) Path(hashState hashState) Path {
mtu := ^uint16(0)
var segments segmentList
var epicPathAuths [][]byte
Expand Down Expand Up @@ -427,7 +458,8 @@ func (solution *pathSolution) Path() Path {
InternalHops: staticInfo.InternalHops,
Notes: staticInfo.Notes,
},
Weight: solution.cost,
Weight: solution.cost,
Fingerprint: fingerprint(interfaces, hashState),
}

if authPHVF, authLHVF, ok := isEpicAvailable(epicPathAuths); ok {
Expand Down Expand Up @@ -531,50 +563,6 @@ func calculateBeta(se *solutionEdge) uint16 {
return beta
}

// PathSolutionList is a sort.Interface implementation for a slice of solutions.
type pathSolutionList []*pathSolution

func (sl pathSolutionList) Len() int {
return len(sl)
}

// Less sorts according to the following priority list:
// - total path cost (number of hops)
// - number of segments
// - segmentIDs
// - shortcut index
// - peer entry index
func (sl pathSolutionList) Less(i, j int) bool {
if sl[i].cost != sl[j].cost {
return sl[i].cost < sl[j].cost
}

trailI, trailJ := sl[i].edges, sl[j].edges
if len(trailI) != len(trailJ) {
return len(trailI) < len(trailJ)
}

for ki := range trailI {
idI := trailI[ki].segment.ID()
idJ := trailJ[ki].segment.ID()
idcmp := bytes.Compare(idI, idJ)
if idcmp != 0 {
return idcmp == -1
}
if trailI[ki].edge.Shortcut != trailJ[ki].edge.Shortcut {
return trailI[ki].edge.Shortcut < trailJ[ki].edge.Shortcut
}
if trailI[ki].edge.Peer != trailJ[ki].edge.Peer {
return trailI[ki].edge.Peer < trailJ[ki].edge.Peer
}
}
return false
}

func (sl pathSolutionList) Swap(i, j int) {
sl[i], sl[j] = sl[j], sl[i]
}

// solutionEdge contains a graph edge and additional metadata required during
// graph exploration.
type solutionEdge struct {
Expand Down
3 changes: 0 additions & 3 deletions private/revcache/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ func NoRevokedHopIntf(ctx context.Context, revCache RevCache,
if err != nil || rev != nil {
return false, err
}
if rev != nil {
return false, nil
}
}
}
return true, nil
Expand Down
12 changes: 12 additions & 0 deletions scion-pki/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
load("//tools/lint:go.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = [
"flags.go",
"plugin.go",
],
importpath = "github.com/scionproto/scion/scion-pki",
visibility = ["//visibility:public"],
deps = ["@com_github_spf13_pflag//:go_default_library"],
)
Loading

0 comments on commit f07fe5c

Please sign in to comment.