better waitlist-gating (#557)
* better waitlist-gating (cherry picked from commit 490fe02b7c3558da18678dfb651c92ec9c4a75b5) * fix broken test * linter fixes * linter fixes * make extension verification optional * add certifcate gating script for captplanet * fixing tests * linter fixes * linter fixes? * moar linter fixes * Revert "moar linter fixes" This reverts commit 8139ccbd73cbbead987b7667567844f50f7df2c8. * just kill me * refactor * refactor tests * liniter... * cleanup
This commit is contained in:
parent
2a8b681c4d
commit
8b9711cb5e
@ -30,7 +30,7 @@ var argError = errs.Class("argError")
|
||||
func main() {
|
||||
cobra.EnableCommandSorting = false
|
||||
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ func main() {
|
||||
logger, _ := zap.NewDevelopment()
|
||||
defer printError(logger.Sync)
|
||||
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
if err != nil {
|
||||
logger.Error("Failed to create certificate authority: ", zap.Error(err))
|
||||
os.Exit(1)
|
||||
|
@ -44,7 +44,7 @@ func main() {
|
||||
logger, _ := zap.NewDevelopment()
|
||||
defer printError(logger.Sync)
|
||||
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
if err != nil {
|
||||
logger.Error("Failed to create certificate authority: ", zap.Error(err))
|
||||
os.Exit(1)
|
||||
|
@ -24,7 +24,7 @@ type Reporter struct {
|
||||
|
||||
// NewReporter instantiates a reporter
|
||||
func NewReporter(ctx context.Context, statDBPort string, maxRetries int) (reporter *Reporter, err error) {
|
||||
ca, err := provider.NewCA(ctx, 12, 14)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
|
||||
func TestGenerateSignature(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -41,7 +41,7 @@ func TestGenerateSignature(t *testing.T) {
|
||||
|
||||
func TestSignedMessageVerifier(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
|
@ -64,7 +64,7 @@ func TestNewKademlia(t *testing.T) {
|
||||
for i, v := range cases {
|
||||
dir := filepath.Join(rootdir, strconv.Itoa(i))
|
||||
|
||||
ca, err := provider.NewCA(context.Background(), 12, 4)
|
||||
ca, err := provider.NewTestCA(context.Background())
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
|
@ -92,7 +92,7 @@ func TestWorkerLookup(t *testing.T) {
|
||||
{
|
||||
name: "test valid chore returned",
|
||||
worker: func() *worker {
|
||||
ca, err := provider.NewCA(context.Background(), 12, 4)
|
||||
ca, err := provider.NewTestCA(context.Background())
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -138,7 +138,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
name: "test nil nodes",
|
||||
worker: func() *worker {
|
||||
ca, err := provider.NewCA(context.Background(), 12, 4)
|
||||
ca, err := provider.NewTestCA(context.Background())
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -154,7 +154,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
name: "test combined less than k",
|
||||
worker: func() *worker {
|
||||
ca, err := provider.NewCA(context.Background(), 12, 4)
|
||||
ca, err := provider.NewTestCA(context.Background())
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -182,7 +182,7 @@ func TestUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
func newTestServer(nn []*pb.Node) (*grpc.Server, *mockNodeServer) {
|
||||
ca, err := provider.NewCA(context.Background(), 12, 4)
|
||||
ca, err := provider.NewTestCA(context.Background())
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -14,7 +14,10 @@ type ID string
|
||||
|
||||
// NewFullIdentity creates a new ID for nodes with difficulty and concurrency params
|
||||
func NewFullIdentity(ctx context.Context, difficulty uint16, concurrency uint) (*provider.FullIdentity, error) {
|
||||
ca, err := provider.NewCA(ctx, difficulty, concurrency)
|
||||
ca, err := provider.NewCA(ctx, provider.NewCAOptions{
|
||||
Difficulty: difficulty,
|
||||
Concurrency: concurrency,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ func TestLookup(t *testing.T) {
|
||||
mdht.EXPECT().GetRoutingTable(gomock.Any()).Return(mrt, nil)
|
||||
mrt.EXPECT().ConnectionSuccess(gomock.Any()).Return(nil)
|
||||
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -154,7 +154,7 @@ func NewNodeID(t *testing.T) string {
|
||||
}
|
||||
|
||||
func newTestIdentity(t *testing.T) *provider.FullIdentity {
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
|
@ -68,7 +68,7 @@ func bootstrapTestNetwork(t *testing.T, ip, port string) ([]dht.DHT, pb.Node) {
|
||||
intro, err := kademlia.GetIntroNode(net.JoinHostPort(ip, pm))
|
||||
assert.NoError(t, err)
|
||||
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
|
@ -42,7 +42,7 @@ func TestNewOverlayClient(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, v := range cases {
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -101,7 +101,7 @@ func TestChoose(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -151,7 +151,7 @@ func TestLookup(t *testing.T) {
|
||||
go func() { assert.NoError(t, srv.Serve(lis)) }()
|
||||
defer srv.Stop()
|
||||
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -187,7 +187,7 @@ func TestBulkLookup(t *testing.T) {
|
||||
go func() { assert.NoError(t, srv.Serve(lis)) }()
|
||||
defer srv.Stop()
|
||||
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -219,7 +219,7 @@ func TestBulkLookupV2(t *testing.T) {
|
||||
go func() { assert.NoError(t, srv.Serve(lis)) }()
|
||||
defer srv.Stop()
|
||||
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
@ -291,7 +291,7 @@ func TestBulkLookupV2(t *testing.T) {
|
||||
}
|
||||
|
||||
func newServer(ctx context.Context, redisAddr string) (*grpc.Server, *Server, error) {
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -317,7 +317,7 @@ func newServer(ctx context.Context, redisAddr string) (*grpc.Server, *Server, er
|
||||
}
|
||||
|
||||
func newTestServer(ctx context.Context) (*grpc.Server, *mockOverlayServer, error) {
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
|
||||
@ -26,6 +27,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// AuthoritySignatureExtID is the asn1 object ID for a pkix extension holding a signature of the leaf cert, signed by some CA (e.g. the root cert)
|
||||
// This extension allows for an additional signature per certificate
|
||||
AuthoritySignatureExtID = asn1.ObjectIdentifier{2, 999, 1}
|
||||
// ErrNotExist is used when a file or directory doesn't exist
|
||||
ErrNotExist = errs.Class("file or directory not found error")
|
||||
// ErrGenerate is used when an error occurred during cert/key generation
|
||||
@ -45,6 +49,8 @@ var (
|
||||
ErrVerifyCertificateChain = errs.Class("certificate chain signature verification failed")
|
||||
// ErrVerifyCAWhitelist is used when the leaf of a peer certificate isn't signed by any CA in the whitelist
|
||||
ErrVerifyCAWhitelist = errs.Class("certificate isn't signed by any CA in the whitelist")
|
||||
// ErrSign is used when something goes wrong while generating a signature
|
||||
ErrSign = errs.Class("unable to generate signature")
|
||||
)
|
||||
|
||||
// PeerCertVerificationFunc is the signature for a `*tls.Config{}`'s
|
||||
@ -117,21 +123,41 @@ func VerifyPeerCertChains(_ [][]byte, parsedChains [][]*x509.Certificate) error
|
||||
return verifyChainSignatures(parsedChains[0])
|
||||
}
|
||||
|
||||
// VerifyCAWhitelist verifies that the peer identity's leaf was signed by any one of the
|
||||
// (certificate authority) certificates in the provided whitelist
|
||||
func VerifyCAWhitelist(cas []*x509.Certificate) PeerCertVerificationFunc {
|
||||
// VerifyCAWhitelist verifies that the peer identity's CA and leaf-extension was signed
|
||||
// by any one of the (certificate authority) certificates in the provided whitelist
|
||||
func VerifyCAWhitelist(cas []*x509.Certificate, verifyExtension bool) PeerCertVerificationFunc {
|
||||
if cas == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(_ [][]byte, parsedChains [][]*x509.Certificate) error {
|
||||
var err error
|
||||
var (
|
||||
leaf = parsedChains[0][0]
|
||||
err error
|
||||
)
|
||||
|
||||
// Leaf extension must contain leaf signature, signed by a CA in the whitelist.
|
||||
// That *same* CA must also have signed the leaf's parent cert (regular cert chain signature, not extension).
|
||||
for _, ca := range cas {
|
||||
err = verifyCertSignature(ca, parsedChains[0][0])
|
||||
err = verifyCertSignature(ca, parsedChains[0][1])
|
||||
if err == nil {
|
||||
return nil
|
||||
if !verifyExtension {
|
||||
break
|
||||
}
|
||||
|
||||
for _, ext := range leaf.Extensions {
|
||||
if ext.Id.Equal(AuthoritySignatureExtID) {
|
||||
err = verifySignature(ext.Value, leaf.RawTBSCertificate, leaf.PublicKey)
|
||||
if err != nil {
|
||||
return ErrVerifyCAWhitelist.New("authority signature extension verification error: %s", err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return ErrVerifyCAWhitelist.Wrap(err)
|
||||
}
|
||||
}
|
||||
|
@ -154,15 +154,19 @@ func TestVerifyCAWhitelist(t *testing.T) {
|
||||
lt, err := LeafTemplate()
|
||||
assert.NoError(t, err)
|
||||
|
||||
lp, ok := k.(*ecdsa.PrivateKey)
|
||||
lk, err := NewKey()
|
||||
assert.NoError(t, err)
|
||||
|
||||
lp, ok := lk.(*ecdsa.PrivateKey)
|
||||
assert.True(t, ok)
|
||||
|
||||
l, err := NewCert(lt, ct, &lp.PublicKey, k)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist(nil))([][]byte{l.Raw, c.Raw}, nil)
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist(nil, false))([][]byte{l.Raw, c.Raw}, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{c}))([][]byte{l.Raw, c.Raw}, nil)
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{c}, false))([][]byte{l.Raw, c.Raw}, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
zk, err := NewKey()
|
||||
@ -176,13 +180,48 @@ func TestVerifyCAWhitelist(t *testing.T) {
|
||||
z, err := NewCert(zt, nil, &zp.PublicKey, zk)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{z}))([][]byte{l.Raw, c.Raw}, nil)
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{z}, false))([][]byte{l.Raw, c.Raw}, nil)
|
||||
assert.True(t, ErrVerifyCAWhitelist.Has(err))
|
||||
assert.True(t, ErrVerifySignature.Has(err))
|
||||
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{z, c}))([][]byte{l.Raw, c.Raw}, nil)
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{z, c}, false))([][]byte{l.Raw, c.Raw}, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{c, z}))([][]byte{l.Raw, c.Raw}, nil)
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{c, z}, false))([][]byte{l.Raw, c.Raw}, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
xt, err := LeafTemplate()
|
||||
assert.NoError(t, err)
|
||||
|
||||
xk, err := NewKey()
|
||||
assert.NoError(t, err)
|
||||
|
||||
xp, ok := xk.(*ecdsa.PrivateKey)
|
||||
assert.True(t, ok)
|
||||
|
||||
x, err := NewCert(xt, zt, &xp.PublicKey, zk)
|
||||
assert.NoError(t, err)
|
||||
|
||||
yt, err := LeafTemplate()
|
||||
assert.NoError(t, err)
|
||||
|
||||
yk, err := NewKey()
|
||||
assert.NoError(t, err)
|
||||
|
||||
yp, ok := yk.(*ecdsa.PrivateKey)
|
||||
assert.True(t, ok)
|
||||
y, err := NewCert(yt, xt, &yp.PublicKey, xk)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{z, c}, false))([][]byte{z.Raw, x.Raw, y.Raw}, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{c, z}, false))([][]byte{z.Raw, x.Raw, y.Raw}, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{z, c}, true))([][]byte{z.Raw, x.Raw, y.Raw}, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{c, z}, true))([][]byte{z.Raw, x.Raw, y.Raw}, nil)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
@ -23,7 +23,9 @@ import (
|
||||
"github.com/zeebo/errs"
|
||||
)
|
||||
|
||||
type ecdsaSignature struct {
|
||||
// ECDSASignature holds the `r` and `s` values in an ecdsa signature
|
||||
// (see https://golang.org/pkg/crypto/ecdsa)
|
||||
type ECDSASignature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
@ -73,28 +75,31 @@ func verifyChainSignatures(certs []*x509.Certificate) error {
|
||||
}
|
||||
|
||||
func verifyCertSignature(parentCert, childCert *x509.Certificate) error {
|
||||
pubKey, ok := parentCert.PublicKey.(*ecdsa.PublicKey)
|
||||
return verifySignature(childCert.Signature, childCert.RawTBSCertificate, parentCert.PublicKey)
|
||||
}
|
||||
|
||||
func verifySignature(signedData []byte, data []byte, pubKey crypto.PublicKey) error {
|
||||
key, ok := pubKey.(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return ErrUnsupportedKey.New("%T", parentCert.PublicKey)
|
||||
return ErrUnsupportedKey.New("%T", key)
|
||||
}
|
||||
|
||||
signature := new(ecdsaSignature)
|
||||
signature := new(ECDSASignature)
|
||||
|
||||
if _, err := asn1.Unmarshal(childCert.Signature, signature); err != nil {
|
||||
if _, err := asn1.Unmarshal(signedData, signature); err != nil {
|
||||
return ErrVerifySignature.New("unable to unmarshal ecdsa signature: %v", err)
|
||||
}
|
||||
|
||||
h := crypto.SHA256.New()
|
||||
_, err := h.Write(childCert.RawTBSCertificate)
|
||||
_, err := h.Write(data)
|
||||
if err != nil {
|
||||
return ErrVerifySignature.Wrap(err)
|
||||
}
|
||||
digest := h.Sum(nil)
|
||||
|
||||
if !ecdsa.Verify(pubKey, digest, signature.R, signature.S) {
|
||||
if !ecdsa.Verify(key, digest, signature.R, signature.S) {
|
||||
return ErrVerifySignature.New("signature is not valid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -535,14 +535,14 @@ func NewTestServer(t *testing.T) *TestServer {
|
||||
}
|
||||
}
|
||||
|
||||
caS, err := provider.NewCA(context.Background(), 12, 4)
|
||||
caS, err := provider.NewTestCA(context.Background())
|
||||
check(err)
|
||||
fiS, err := caS.NewIdentity()
|
||||
check(err)
|
||||
so, err := fiS.ServerOption()
|
||||
check(err)
|
||||
|
||||
caC, err := provider.NewCA(context.Background(), 12, 4)
|
||||
caC, err := provider.NewTestCA(context.Background())
|
||||
check(err)
|
||||
fiC, err := caC.NewIdentity()
|
||||
check(err)
|
||||
|
@ -300,7 +300,7 @@ func TestDelete(t *testing.T) {
|
||||
|
||||
func TestSignedMessage(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
|
@ -67,7 +67,7 @@ func TestServicePut(t *testing.T) {
|
||||
|
||||
func TestServiceGet(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
|
@ -13,7 +13,10 @@ import (
|
||||
func TestNewCA(t *testing.T) {
|
||||
expectedDifficulty := uint16(4)
|
||||
|
||||
ca, err := NewCA(context.Background(), expectedDifficulty, 5)
|
||||
ca, err := NewCA(context.Background(), NewCAOptions{
|
||||
Difficulty: expectedDifficulty,
|
||||
Concurrency: 5,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, ca)
|
||||
|
||||
@ -28,7 +31,7 @@ func TestFullCertificateAuthority_NewIdentity(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
ca, err := NewCA(context.Background(), 12, 5)
|
||||
ca, err := NewTestCA(context.Background())
|
||||
check(err, ca)
|
||||
fi, err := ca.NewIdentity()
|
||||
check(err, fi)
|
||||
@ -44,7 +47,10 @@ func TestFullCertificateAuthority_NewIdentity(t *testing.T) {
|
||||
|
||||
func NewCABenchmark(b *testing.B, difficulty uint16, concurrency uint) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = NewCA(context.Background(), difficulty, concurrency)
|
||||
_, _ = NewCA(context.Background(), NewCAOptions{
|
||||
Difficulty: difficulty,
|
||||
Concurrency: concurrency,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/zeebo/errs"
|
||||
|
||||
@ -21,6 +20,7 @@ import (
|
||||
|
||||
// PeerCertificateAuthority represents the CA which is used to validate peer identities
|
||||
type PeerCertificateAuthority struct {
|
||||
RestChain []*x509.Certificate
|
||||
// Cert is the x509 certificate of the CA
|
||||
Cert *x509.Certificate
|
||||
// The ID is calculated from the CA public key.
|
||||
@ -29,6 +29,7 @@ type PeerCertificateAuthority struct {
|
||||
|
||||
// FullCertificateAuthority represents the CA which is used to author and validate full identities
|
||||
type FullCertificateAuthority struct {
|
||||
RestChain []*x509.Certificate
|
||||
// Cert is the x509 certificate of the CA
|
||||
Cert *x509.Certificate
|
||||
// The ID is calculated from the CA public key.
|
||||
@ -39,12 +40,26 @@ type FullCertificateAuthority struct {
|
||||
|
||||
// CASetupConfig is for creating a CA
|
||||
type CASetupConfig struct {
|
||||
CertPath string `help:"path to the certificate chain for this identity" default:"$CONFDIR/ca.cert"`
|
||||
KeyPath string `help:"path to the private key for this identity" default:"$CONFDIR/ca.key"`
|
||||
Difficulty uint64 `help:"minimum difficulty for identity generation" default:"12"`
|
||||
Timeout string `help:"timeout for CA generation; golang duration string (0 no timeout)" default:"5m"`
|
||||
Overwrite bool `help:"if true, existing CA certs AND keys will overwritten" default:"false"`
|
||||
Concurrency uint `help:"number of concurrent workers for certificate authority generation" default:"4"`
|
||||
ParentCertPath string `help:"path to the parent authority's certificate chain"`
|
||||
ParentKeyPath string `help:"path to the parent authority's private key"`
|
||||
CertPath string `help:"path to the certificate chain for this identity" default:"$CONFDIR/ca.cert"`
|
||||
KeyPath string `help:"path to the private key for this identity" default:"$CONFDIR/ca.key"`
|
||||
Difficulty uint64 `help:"minimum difficulty for identity generation" default:"12"`
|
||||
Timeout string `help:"timeout for CA generation; golang duration string (0 no timeout)" default:"5m"`
|
||||
Overwrite bool `help:"if true, existing CA certs AND keys will overwritten" default:"false"`
|
||||
Concurrency uint `help:"number of concurrent workers for certificate authority generation" default:"4"`
|
||||
}
|
||||
|
||||
// NewCAOptions is used to pass parameters to `NewCA`
|
||||
type NewCAOptions struct {
|
||||
// Difficulty is the number of trailing zero-bits the nodeID must have
|
||||
Difficulty uint16
|
||||
// Concurrency is the number of go routines used to generate a CA of sufficient difficulty
|
||||
Concurrency uint
|
||||
// ParentCert, if provided will be prepended to the certificate chain
|
||||
ParentCert *x509.Certificate
|
||||
// ParentKey ()
|
||||
ParentKey crypto.PrivateKey
|
||||
}
|
||||
|
||||
// PeerCAConfig is for locating a CA certificate without a private key
|
||||
@ -65,7 +80,30 @@ func (caS CASetupConfig) Status() TLSFilesStatus {
|
||||
|
||||
// Create generates and saves a CA using the config
|
||||
func (caS CASetupConfig) Create(ctx context.Context) (*FullCertificateAuthority, error) {
|
||||
ca, err := NewCA(ctx, uint16(caS.Difficulty), caS.Concurrency)
|
||||
var (
|
||||
err error
|
||||
parent *FullCertificateAuthority
|
||||
)
|
||||
if caS.ParentCertPath != "" && caS.ParentKeyPath != "" {
|
||||
parent, err = FullCAConfig{
|
||||
CertPath: caS.ParentCertPath,
|
||||
KeyPath: caS.ParentKeyPath,
|
||||
}.Load()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if parent == nil {
|
||||
parent = &FullCertificateAuthority{}
|
||||
}
|
||||
|
||||
ca, err := NewCA(ctx, NewCAOptions{
|
||||
Difficulty: uint16(caS.Difficulty),
|
||||
Concurrency: caS.Concurrency,
|
||||
ParentCert: parent.Cert,
|
||||
ParentKey: parent.Key,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -93,19 +131,11 @@ func (fc FullCAConfig) Load() (*FullCertificateAuthority, error) {
|
||||
return nil, errs.New("unable to parse EC private key: %v", err)
|
||||
}
|
||||
|
||||
ec, ok := p.Cert.PublicKey.(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, peertls.ErrUnsupportedKey.New("certificate public key type not supported: %T", k)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(k.PublicKey, *ec) {
|
||||
return nil, errs.New("certificate public key and loaded")
|
||||
}
|
||||
|
||||
return &FullCertificateAuthority{
|
||||
Cert: p.Cert,
|
||||
Key: k,
|
||||
ID: p.ID,
|
||||
RestChain: p.RestChain,
|
||||
Cert: p.Cert,
|
||||
Key: k,
|
||||
ID: p.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -138,28 +168,29 @@ func (pc PeerCAConfig) Load() (*PeerCertificateAuthority, error) {
|
||||
pc.CertPath, err)
|
||||
}
|
||||
|
||||
i, err := idFromKey(c[len(c)-1].PublicKey)
|
||||
i, err := idFromKey(c[0].PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PeerCertificateAuthority{
|
||||
Cert: c[0],
|
||||
ID: i,
|
||||
RestChain: c[1:],
|
||||
Cert: c[0],
|
||||
ID: i,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewCA creates a new full identity with the given difficulty
|
||||
func NewCA(ctx context.Context, difficulty uint16, concurrency uint) (*FullCertificateAuthority, error) {
|
||||
if concurrency < 1 {
|
||||
concurrency = 1
|
||||
func NewCA(ctx context.Context, opts NewCAOptions) (*FullCertificateAuthority, error) {
|
||||
if opts.Concurrency < 1 {
|
||||
opts.Concurrency = 1
|
||||
}
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
eC := make(chan error)
|
||||
caC := make(chan FullCertificateAuthority, 1)
|
||||
for i := 0; i < int(concurrency); i++ {
|
||||
go newCAWorker(ctx, difficulty, caC, eC)
|
||||
for i := 0; i < int(opts.Concurrency); i++ {
|
||||
go newCAWorker(ctx, opts.Difficulty, opts.ParentCert, opts.ParentKey, caC, eC)
|
||||
}
|
||||
|
||||
select {
|
||||
@ -186,7 +217,9 @@ func (fc FullCAConfig) Save(ca *FullCertificateAuthority) error {
|
||||
}
|
||||
defer utils.LogClose(k)
|
||||
|
||||
if err = peertls.WriteChain(c, ca.Cert); err != nil {
|
||||
chain := []*x509.Certificate{ca.Cert}
|
||||
chain = append(chain, ca.RestChain...)
|
||||
if err = peertls.WriteChain(c, chain...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = peertls.WriteKey(k, ca.Key); err != nil {
|
||||
@ -217,9 +250,18 @@ func (ca FullCertificateAuthority) NewIdentity() (*FullIdentity, error) {
|
||||
}
|
||||
|
||||
return &FullIdentity{
|
||||
CA: ca.Cert,
|
||||
Leaf: l,
|
||||
Key: k,
|
||||
ID: ca.ID,
|
||||
RestChain: ca.RestChain,
|
||||
CA: ca.Cert,
|
||||
Leaf: l,
|
||||
Key: k,
|
||||
ID: ca.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewTestCA returns a ca with a default difficulty and concurrency for use in tests
|
||||
func NewTestCA(ctx context.Context) (*FullCertificateAuthority, error) {
|
||||
return NewCA(ctx, NewCAOptions{
|
||||
Difficulty: 12,
|
||||
Concurrency: 4,
|
||||
})
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ const (
|
||||
|
||||
// PeerIdentity represents another peer on the network.
|
||||
type PeerIdentity struct {
|
||||
RestChain []*x509.Certificate
|
||||
// CA represents the peer's self-signed CA
|
||||
CA *x509.Certificate
|
||||
// Leaf represents the leaf they're currently using. The leaf should be
|
||||
@ -44,6 +45,7 @@ type PeerIdentity struct {
|
||||
// FullIdentity represents you on the network. In addition to a PeerIdentity,
|
||||
// a FullIdentity also has a Key, which a PeerIdentity doesn't have.
|
||||
type FullIdentity struct {
|
||||
RestChain []*x509.Certificate
|
||||
// CA represents the peer's self-signed CA. The ID is taken from this cert.
|
||||
CA *x509.Certificate
|
||||
// Leaf represents the leaf they're currently using. The leaf should be
|
||||
@ -56,6 +58,9 @@ type FullIdentity struct {
|
||||
// PeerCAWhitelist is a whitelist of CA certs which, if present, restricts which peers this identity will verify as valid;
|
||||
// peer certs must be signed by a CA in this list to pass peer certificate verification.
|
||||
PeerCAWhitelist []*x509.Certificate
|
||||
// VerfyAuthExtSig if true, client leafs which handshake with this identity must contain a valid "authority signature extension"
|
||||
// (NB: authority signature extensions are verified against certs in the `PeerCAWhitelist`; i.e. if true, a whitelist must be provided)
|
||||
VerifyAuthExtSig bool
|
||||
}
|
||||
|
||||
// IdentitySetupConfig allows you to run a set of Responsibilities with the given
|
||||
@ -73,6 +78,7 @@ type IdentityConfig struct {
|
||||
CertPath string `help:"path to the certificate chain for this identity" default:"$CONFDIR/identity.cert"`
|
||||
KeyPath string `help:"path to the private key for this identity" default:"$CONFDIR/identity.key"`
|
||||
PeerCAWhitelistPath string `help:"path to the CA cert whitelist (peer identities must be signed by one these to be verified)"`
|
||||
VerifyAuthExtSig bool `help:"if true, client leafs must contain a valid \"authority signature extension\" (NB: authority signature extensions are verified against certs in the peer ca whitelist; i.e. if true, a whitelist must be provided)" default:"false"`
|
||||
Address string `help:"address to listen on" default:":7777"`
|
||||
}
|
||||
|
||||
@ -121,6 +127,7 @@ func FullIdentityFromPEM(chainPEM, keyPEM, CAWhitelistPEM []byte) (*FullIdentity
|
||||
}
|
||||
|
||||
return &FullIdentity{
|
||||
RestChain: ch[2:],
|
||||
CA: ch[1],
|
||||
Leaf: ch[0],
|
||||
Key: k,
|
||||
@ -143,16 +150,17 @@ func ParseCertChain(chain [][]byte) ([]*x509.Certificate, error) {
|
||||
}
|
||||
|
||||
// PeerIdentityFromCerts loads a PeerIdentity from a pair of leaf and ca x509 certificates
|
||||
func PeerIdentityFromCerts(leaf, ca *x509.Certificate) (*PeerIdentity, error) {
|
||||
func PeerIdentityFromCerts(leaf, ca *x509.Certificate, rest []*x509.Certificate) (*PeerIdentity, error) {
|
||||
i, err := idFromKey(ca.PublicKey.(crypto.PublicKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PeerIdentity{
|
||||
CA: ca,
|
||||
ID: i,
|
||||
Leaf: leaf,
|
||||
RestChain: rest,
|
||||
CA: ca,
|
||||
ID: i,
|
||||
Leaf: leaf,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -163,7 +171,7 @@ func PeerIdentityFromPeer(peer *peer.Peer) (*PeerIdentity, error) {
|
||||
if len(c) < 2 {
|
||||
return nil, Error.New("invalid certificate chain")
|
||||
}
|
||||
pi, err := PeerIdentityFromCerts(c[0], c[1])
|
||||
pi, err := PeerIdentityFromCerts(c[0], c[1], c[2:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -237,7 +245,9 @@ func (ic IdentityConfig) Save(fi *FullIdentity) error {
|
||||
}
|
||||
defer utils.LogClose(k)
|
||||
|
||||
if err = peertls.WriteChain(c, fi.Leaf, fi.CA); err != nil {
|
||||
chain := []*x509.Certificate{fi.Leaf, fi.CA}
|
||||
chain = append(chain, fi.RestChain...)
|
||||
if err = peertls.WriteChain(c, chain...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = peertls.WriteKey(k, fi.Key); err != nil {
|
||||
@ -247,9 +257,7 @@ func (ic IdentityConfig) Save(fi *FullIdentity) error {
|
||||
}
|
||||
|
||||
// Run will run the given responsibilities with the configured identity.
|
||||
func (ic IdentityConfig) Run(ctx context.Context, interceptor grpc.UnaryServerInterceptor,
|
||||
responsibilities ...Responsibility) (
|
||||
err error) {
|
||||
func (ic IdentityConfig) Run(ctx context.Context, interceptor grpc.UnaryServerInterceptor, responsibilities ...Responsibility) (err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
pi, err := ic.Load()
|
||||
@ -273,10 +281,20 @@ func (ic IdentityConfig) Run(ctx context.Context, interceptor grpc.UnaryServerIn
|
||||
return s.Run(ctx)
|
||||
}
|
||||
|
||||
// RestChainRaw returns the rest (excluding leaf and CA) of the certficate chain as a 2d byte slice
|
||||
func (fi *FullIdentity) RestChainRaw() [][]byte {
|
||||
var chain [][]byte
|
||||
for _, cert := range fi.RestChain {
|
||||
chain = append(chain, cert.Raw)
|
||||
}
|
||||
return chain
|
||||
}
|
||||
|
||||
// ServerOption returns a grpc `ServerOption` for incoming connections
|
||||
// to the node with this full identity
|
||||
func (fi *FullIdentity) ServerOption(pcvFuncs ...peertls.PeerCertVerificationFunc) (grpc.ServerOption, error) {
|
||||
ch := [][]byte{fi.Leaf.Raw, fi.CA.Raw}
|
||||
ch = append(ch, fi.RestChainRaw()...)
|
||||
c, err := peertls.TLSCert(ch, fi.Leaf, fi.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -303,6 +321,7 @@ func (fi *FullIdentity) ServerOption(pcvFuncs ...peertls.PeerCertVerificationFun
|
||||
func (fi *FullIdentity) DialOption() (grpc.DialOption, error) {
|
||||
// TODO(coyle): add ID
|
||||
ch := [][]byte{fi.Leaf.Raw, fi.CA.Raw}
|
||||
ch = append(ch, fi.RestChainRaw()...)
|
||||
c, err := peertls.TLSCert(ch, fi.Leaf, fi.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -43,7 +43,7 @@ func TestPeerIdentityFromCertChain(t *testing.T) {
|
||||
l, err := peertls.NewCert(lT, caT, &lp.PublicKey, k)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pi, err := PeerIdentityFromCerts(l, c)
|
||||
pi, err := PeerIdentityFromCerts(l, c, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c, pi.CA)
|
||||
assert.Equal(t, l, pi.Leaf)
|
||||
@ -246,7 +246,7 @@ func TestVerifyPeer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
ca, err := NewCA(context.Background(), 12, 4)
|
||||
ca, err := NewTestCA(context.Background())
|
||||
check(err)
|
||||
fi, err := ca.NewIdentity()
|
||||
check(err)
|
||||
|
@ -45,7 +45,10 @@ type Provider struct {
|
||||
func NewProvider(identity *FullIdentity, lis net.Listener, interceptor grpc.UnaryServerInterceptor,
|
||||
responsibilities ...Responsibility) (*Provider, error) {
|
||||
// NB: talk to anyone with an identity
|
||||
ident, err := identity.ServerOption(peertls.VerifyCAWhitelist(identity.PeerCAWhitelist))
|
||||
ident, err := identity.ServerOption(peertls.VerifyCAWhitelist(
|
||||
identity.PeerCAWhitelist,
|
||||
identity.VerifyAuthExtSig,
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -7,7 +7,10 @@ import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"os"
|
||||
@ -56,7 +59,7 @@ func decodePEM(PEMBytes []byte) ([][]byte, error) {
|
||||
return DERBytes, nil
|
||||
}
|
||||
|
||||
func newCAWorker(ctx context.Context, difficulty uint16, caC chan FullCertificateAuthority, eC chan error) {
|
||||
func newCAWorker(ctx context.Context, difficulty uint16, parentCert *x509.Certificate, parentKey crypto.PrivateKey, caC chan FullCertificateAuthority, eC chan error) {
|
||||
var (
|
||||
k crypto.PrivateKey
|
||||
i nodeID
|
||||
@ -96,12 +99,7 @@ func newCAWorker(ctx context.Context, difficulty uint16, caC chan FullCertificat
|
||||
return
|
||||
}
|
||||
|
||||
p, ok := k.(*ecdsa.PrivateKey)
|
||||
if !ok {
|
||||
eC <- peertls.ErrUnsupportedKey.New("%T", k)
|
||||
return
|
||||
}
|
||||
c, err := peertls.NewCert(ct, nil, &p.PublicKey, k)
|
||||
c, err := newCACert(k, parentKey, ct, parentCert)
|
||||
if err != nil {
|
||||
eC <- err
|
||||
return
|
||||
@ -112,9 +110,59 @@ func newCAWorker(ctx context.Context, difficulty uint16, caC chan FullCertificat
|
||||
Key: k,
|
||||
ID: i,
|
||||
}
|
||||
if parentCert != nil {
|
||||
ca.RestChain = []*x509.Certificate{parentCert}
|
||||
}
|
||||
caC <- ca
|
||||
}
|
||||
|
||||
func newCACert(key, parentKey crypto.PrivateKey, template, parentCert *x509.Certificate) (*x509.Certificate, error) {
|
||||
p, ok := key.(*ecdsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, peertls.ErrUnsupportedKey.New("%T", key)
|
||||
}
|
||||
|
||||
var signingKey crypto.PrivateKey
|
||||
if parentKey != nil {
|
||||
signingKey = parentKey
|
||||
} else {
|
||||
signingKey = key
|
||||
}
|
||||
|
||||
cert, err := peertls.NewCert(template, parentCert, &p.PublicKey, signingKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if parentKey != nil {
|
||||
p, ok := parentKey.(*ecdsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, peertls.ErrUnsupportedKey.New("%T", key)
|
||||
}
|
||||
|
||||
hash := crypto.SHA256.New()
|
||||
_, err := hash.Write(cert.RawTBSCertificate)
|
||||
if err != nil {
|
||||
return nil, peertls.ErrSign.Wrap(err)
|
||||
}
|
||||
r, s, err := ecdsa.Sign(rand.Reader, p, hash.Sum(nil))
|
||||
if err != nil {
|
||||
return nil, peertls.ErrSign.Wrap(err)
|
||||
}
|
||||
|
||||
signature, err := asn1.Marshal(peertls.ECDSASignature{R: r, S: s})
|
||||
if err != nil {
|
||||
return nil, peertls.ErrSign.Wrap(err)
|
||||
}
|
||||
|
||||
cert.ExtraExtensions = append(cert.ExtraExtensions, pkix.Extension{
|
||||
Id: peertls.AuthoritySignatureExtID,
|
||||
Value: signature,
|
||||
})
|
||||
}
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
func idFromKey(k crypto.PublicKey) (nodeID, error) {
|
||||
kb, err := x509.MarshalPKIXPublicKey(k)
|
||||
if err != nil {
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
var ctx = context.Background()
|
||||
|
||||
func TestDialNode(t *testing.T) {
|
||||
ca, err := provider.NewCA(ctx, 12, 4)
|
||||
ca, err := provider.NewTestCA(ctx)
|
||||
assert.NoError(t, err)
|
||||
identity, err := ca.NewIdentity()
|
||||
assert.NoError(t, err)
|
||||
|
75
scripts/cert-gating.sh
Executable file
75
scripts/cert-gating.sh
Executable file
@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
basepath=$HOME/.storj/capt
|
||||
alpha_config=$basepath/config-alpha.yaml
|
||||
unauthorized_config=$basepath/config-unauthorized.yaml
|
||||
ca_whitelist=$basepath/ca-alpha-whitelist.cert
|
||||
ca_count=5
|
||||
ca_basepath=$basepath/ca-alpha-
|
||||
|
||||
ca_i_basepath() {
|
||||
echo "$ca_basepath$1"
|
||||
}
|
||||
rand_ca_basepath() {
|
||||
let i="($RANDOM % $ca_count) + 1"
|
||||
echo $(ca_i_basepath $i)
|
||||
}
|
||||
|
||||
case $1 in
|
||||
--help)
|
||||
echo "usage: $(basename $0) [setup|alpha|unauthorized]"
|
||||
;;
|
||||
setup)
|
||||
echo "setting up captplanet"
|
||||
captplanet setup --overwrite
|
||||
echo "clearing whitelist"
|
||||
echo > $ca_whitelist
|
||||
echo -n "generating alpha certificate authorities.."
|
||||
for i in $(seq 1 $ca_count); do
|
||||
echo -n "$i.."
|
||||
_basepath=$(ca_i_basepath $i)
|
||||
identity ca new --ca.overwrite \
|
||||
--ca.cert-path $_basepath.cert \
|
||||
--ca.key-path $_basepath.key
|
||||
cat $_basepath.cert >> $ca_whitelist
|
||||
done
|
||||
echo "done"
|
||||
echo -n "generating alpha identities"
|
||||
for dir in $basepath/{f*,sat*,up*}; do
|
||||
echo -n "."
|
||||
_ca_basepath=$(rand_ca_basepath)
|
||||
_ca_cert=$dir/ca-alpha.cert
|
||||
_ca_key=$dir/ca-alpha.key
|
||||
identity ca new --ca.overwrite \
|
||||
--ca.cert-path $_ca_cert \
|
||||
--ca.key-path $_ca_key \
|
||||
--ca.parent-cert-path $_ca_basepath.cert \
|
||||
--ca.parent-key-path $_ca_basepath.key
|
||||
identity id new --identity.overwrite \
|
||||
--identity.cert-path $dir/identity-alpha.cert \
|
||||
--identity.key-path $dir/identity-alpha.key \
|
||||
--ca.cert-path $_ca_cert \
|
||||
--ca.key-path $_ca_key
|
||||
done
|
||||
echo "done"
|
||||
echo "writing alpha config"
|
||||
cat $basepath/config.yaml | \
|
||||
sed "s,peer-ca-whitelist-path: \"\",peer-ca-whitelist-path: $ca_whitelist,g" | \
|
||||
sed -E 's,cert-path: (.+)\.cert,cert-path: \1-alpha.cert,g' | \
|
||||
sed -E 's,key-path: (.+)\.key,key-path: \1-alpha.key,g' \
|
||||
> $alpha_config
|
||||
echo "writing unauthorized config"
|
||||
cat $basepath/config.yaml | sed -E "s,peer-ca-whitelist-path: \"\",peer-ca-whitelist-path: $ca_whitelist,g" > "$unauthorized_config"
|
||||
;;
|
||||
alpha)
|
||||
captplanet run --config $alpha_config
|
||||
;;
|
||||
unauthorized)
|
||||
captplanet run --config $unauthorized_config
|
||||
;;
|
||||
run)
|
||||
captplanet run
|
||||
;;
|
||||
*)
|
||||
$0 --help
|
||||
;;
|
||||
esac
|
Loading…
Reference in New Issue
Block a user