Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS x509 for Websocket #145

Closed
wants to merge 3 commits into from
Closed

TLS x509 for Websocket #145

wants to merge 3 commits into from

Conversation

dmikey
Copy link
Contributor

@dmikey dmikey commented May 3, 2024

This draft introduces converting an IPFS private key into a valid x509, and then using that to secure the WebSocket Connection with a TLS 1.2+ upgrade.

@dmikey dmikey requested review from Maelkum and uditdc May 3, 2024 15:27
@dmikey dmikey marked this pull request as ready for review May 6, 2024 22:22
Copy link
Collaborator

@Maelkum Maelkum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good, especially like that we have tests! Requesting changes because of the scenario where this crashes if we have websocket && !privateKey - remaining stuff looks good!

Makefile Show resolved Hide resolved
Makefile Outdated Show resolved Hide resolved
go.mod Outdated
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we run go mod tidy and include go.mod and go.sum afterwards?

case libp2pcrypto.Ed25519:
return ed25519.PrivateKey(rawKey), nil
default:
return nil, fmt.Errorf("unsupported key type for X.509 conversion")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be useful to know which key it was:

Suggested change
return nil, fmt.Errorf("unsupported key type for X.509 conversion")
return nil, fmt.Errorf("unsupported key type for X.509 conversion: %s", privKey.Type())

Comment on lines +67 to +77
func publicKey(priv crypto.PrivateKey) crypto.PublicKey {
switch key := priv.(type) {
case *rsa.PrivateKey:
return &key.PublicKey
case *ecdsa.PrivateKey:
return &key.PublicKey
case ed25519.PrivateKey:
return key.Public().(ed25519.PublicKey)
default:
panic("unsupported key type")
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to have this return crypto.PublicKey and an error than have this panic.

Instead in default I'd do return nil, fmt.Errorf("unsupported key type: %T", key)

Organization: []string{"b7s"},
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(365 * 24 * time.Hour), // 1 year validity
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps for visibility we define this in params.go:

var (
	DefaultCertificateDuration = 365 * 24 * time.Hour // 1 year
)

Then here we do:

Suggested change
NotAfter: time.Now().Add(365 * 24 * time.Hour), // 1 year validity
NotAfter: time.Now().Add(DefaultCertificateDuration),

I'd do the same for Organization.

// Create the certificate
derBytes, err := x509.CreateCertificate(rand.Reader, template, template, pubKey, privKey)
if err != nil {
return tls.Certificate{}, err
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we wrap the error here? Especially if we change the above to return public key and an error - we'd have two paths that return an error - it's useful to have context

libp2pcrypto "github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/assert"
)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd change these asserts to requires. That way it's consistent with the codebase and it'll rarely be useful to continue the test after the first error.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to have tests for other types of keys too - but I can add that in a separate PR.

addresses = append(addresses, wsAddr)
}
// define a subset of the default transports, so that we can offer a x509 certificate for the websocket transport
DefaultTransports := libp2p.ChainOptions(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
DefaultTransports := libp2p.ChainOptions(
transports := libp2p.ChainOptions(

}

// Convert libp2p private key to crypto.PrivateKey
cryptoPrivKey, err := convertLibp2pPrivKeyToCryptoPrivKey(key)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This here line relies on us having a key. However the key is optional - we could generate a libp2p identity on the fly.

If we start the node with node --websocket true (without --private-key) - this will blow up.

What I'm thinking:

  1. We change how private key config works for the host. Instead of this:
// WithPrivateKey specifies the private key for the Host.
func WithPrivateKey(filepath string) func(*Config) 

we do:

// WithPrivateKey specifies the private key for the Host.
func WithPrivateKey(key crypto.PrivKey) func(*Config)
  1. We make the key a hard requirement - host.New fails if it does not have a key.
  2. In the main() function of the node, we take care of a) reading the key from disk - if the private key is specified, or b) we generate an in-memory key that we will use for the current invocation. In either case we pass the key to the host. Then we can rely on having the key.

What do you think?

Signed-off-by: Derek Anderson <[email protected]>

add x509 generation

Signed-off-by: Derek Anderson <[email protected]>

add tests

Signed-off-by: Derek Anderson <[email protected]>

add tls config with cert

Signed-off-by: Derek Anderson <[email protected]>

x509 generation from libp2p cert, TLS upgrade for WS transport.

Signed-off-by: Derek Anderson <[email protected]>

cleanup

Signed-off-by: Derek Anderson <[email protected]>

put back in trap comment

Signed-off-by: Derek Anderson <[email protected]>

load the private key, and then generate the x509

Signed-off-by: Derek Anderson <[email protected]>

update makefile for platform detection

Signed-off-by: Derek Anderson <[email protected]>

update make file to run node

Signed-off-by: Derek Anderson <[email protected]>

update certificate creation for ed25519, update makefile

Signed-off-by: Derek Anderson <[email protected]>

configure org name

Signed-off-by: Derek Anderson <[email protected]>
Signed-off-by: Derek Anderson <[email protected]>
@dmikey dmikey closed this Jun 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants