Skip to content
This repository has been archived by the owner on Aug 19, 2022. It is now read-only.

Commit

Permalink
switch to option instead of exported methods
Browse files Browse the repository at this point in the history
  • Loading branch information
peterargue committed Mar 22, 2022
1 parent 2a580c6 commit 449626c
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 11 deletions.
43 changes: 32 additions & 11 deletions crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,35 @@ type Identity struct {
config tls.Config
}

type IdentityConfig struct {
CertTemplate *x509.Certificate
}

type IdentityOption func(r *IdentityConfig)

// WithCertTemplate specifies the template to use when generating a new certificate.
func WithCertTemplate(template *x509.Certificate) IdentityOption {
return func(c *IdentityConfig) {
c.CertTemplate = template
}
}

// NewIdentity creates a new identity
func NewIdentity(privKey ic.PrivKey) (*Identity, error) {
certTmpl, err := defaultCertTemplate()
if err != nil {
return nil, err
func NewIdentity(privKey ic.PrivKey, opts ...IdentityOption) (*Identity, error) {
config := IdentityConfig{}
for _, opt := range opts {
opt(&config)
}

var err error
if config.CertTemplate == nil {
config.CertTemplate, err = DefaultCertTemplate()
if err != nil {
return nil, err
}
}

cert, err := KeyToCertificate(privKey, certTmpl)
cert, err := keyToCertificate(privKey, config.CertTemplate)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -163,10 +184,10 @@ func PubKeyFromCertChain(chain []*x509.Certificate) (ic.PubKey, error) {
return pubKey, nil
}

// GenerateSignedExtension uses the provided private key to sign the public key, and returns the
// generateSignedExtension uses the provided private key to sign the public key, and returns the
// signature within a pkix.Extension.
// This extension is included in a certificate to cryptographically tie it to the libp2p private key.
func GenerateSignedExtension(sk ic.PrivKey, pubKey crypto.PublicKey) (*pkix.Extension, error) {
func generateSignedExtension(sk ic.PrivKey, pubKey crypto.PublicKey) (*pkix.Extension, error) {
keyBytes, err := ic.MarshalPublicKey(sk.GetPublic())
if err != nil {
return nil, err
Expand All @@ -190,17 +211,17 @@ func GenerateSignedExtension(sk ic.PrivKey, pubKey crypto.PublicKey) (*pkix.Exte
return &pkix.Extension{Id: extensionID, Critical: extensionCritical, Value: value}, nil
}

// KeyToCertificate generates a new ECDSA private key and corresponding x509 certificate.
// keyToCertificate generates a new ECDSA private key and corresponding x509 certificate.
// The certificate includes an extension that cryptographically ties it to the provided libp2p
// private key to authenticate TLS connections.
func KeyToCertificate(sk ic.PrivKey, certTmpl *x509.Certificate) (*tls.Certificate, error) {
func keyToCertificate(sk ic.PrivKey, certTmpl *x509.Certificate) (*tls.Certificate, error) {
certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}

// after calling CreateCertificate, these will end up in Certificate.Extensions
extension, err := GenerateSignedExtension(sk, certKey.Public())
extension, err := generateSignedExtension(sk, certKey.Public())
if err != nil {
return nil, err
}
Expand All @@ -216,7 +237,7 @@ func KeyToCertificate(sk ic.PrivKey, certTmpl *x509.Certificate) (*tls.Certifica
}, nil
}

func defaultCertTemplate() (*x509.Certificate, error) {
func DefaultCertTemplate() (*x509.Certificate, error) {
bigNum := big.NewInt(1 << 62)
sn, err := rand.Int(rand.Reader, bigNum)
if err != nil {
Expand Down
48 changes: 48 additions & 0 deletions crypto_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package libp2ptls

import (
"crypto/x509"
"testing"

"github.com/stretchr/testify/assert"
)

func TestNewIdentityCertificates(t *testing.T) {
_, key := createPeer(t)
cn := "a.test.name"
email := "unittest@example.com"

t.Run("NewIdentity with default template", func(t *testing.T) {
// Generate an identity using the default template
id, err := NewIdentity(key)
assert.NoError(t, err)

// Extract the x509 certificate
x509Cert, err := x509.ParseCertificate(id.config.Certificates[0].Certificate[0])
assert.NoError(t, err)

// verify the common name and email are not set
assert.Empty(t, x509Cert.Subject.CommonName)
assert.Empty(t, x509Cert.EmailAddresses)
})

t.Run("NewIdentity with custom template", func(t *testing.T) {
tmpl, err := DefaultCertTemplate()
assert.NoError(t, err)

tmpl.Subject.CommonName = cn
tmpl.EmailAddresses = []string{email}

// Generate an identity using the custom template
id, err := NewIdentity(key, WithCertTemplate(tmpl))
assert.NoError(t, err)

// Extract the x509 certificate
x509Cert, err := x509.ParseCertificate(id.config.Certificates[0].Certificate[0])
assert.NoError(t, err)

// verify the common name and email are set
assert.Equal(t, cn, x509Cert.Subject.CommonName)
assert.Equal(t, email, x509Cert.EmailAddresses[0])
})
}

0 comments on commit 449626c

Please sign in to comment.