-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Derek Anderson <dmikey@users.noreply.github.com>
- Loading branch information
Showing
2 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package crypto | ||
|
||
import ( | ||
"crypto" | ||
"crypto/ecdsa" | ||
"crypto/ed25519" | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/tls" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"fmt" | ||
"math/big" | ||
"time" | ||
|
||
"github.com/go-acme/lego/v4/certcrypto" | ||
"github.com/go-acme/lego/v4/certificate" | ||
"github.com/go-acme/lego/v4/challenge/http01" | ||
"github.com/go-acme/lego/v4/challenge/tlsalpn01" | ||
"github.com/go-acme/lego/v4/lego" | ||
"github.com/go-acme/lego/v4/registration" | ||
libp2pcrypto "github.com/libp2p/go-libp2p/core/crypto" | ||
) | ||
|
||
// Convert a libp2p PrivKey to a crypto.PrivateKey | ||
func convertLibp2pPrivKeyToCryptoPrivKey(privKey libp2pcrypto.PrivKey) (crypto.PrivateKey, error) { | ||
rawKey, err := privKey.Raw() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
switch privKey.Type() { | ||
case libp2pcrypto.RSA: | ||
return x509.ParsePKCS1PrivateKey(rawKey) | ||
case libp2pcrypto.ECDSA: | ||
return x509.ParseECPrivateKey(rawKey) | ||
case libp2pcrypto.Ed25519: | ||
return ed25519.PrivateKey(rawKey), nil | ||
default: | ||
return nil, fmt.Errorf("unsupported key type for X.509 conversion: %v", privKey.Type()) | ||
} | ||
} | ||
|
||
func generateX509Certificate(privKey crypto.PrivateKey) (tls.Certificate, error) { | ||
// Define certificate template | ||
template := &x509.Certificate{ | ||
SerialNumber: big.NewInt(1), | ||
Subject: pkix.Name{ | ||
Organization: []string{"b7s"}, | ||
}, | ||
NotBefore: time.Now(), | ||
NotAfter: time.Now().Add(365 * 24 * time.Hour), // 1 year validity | ||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, | ||
} | ||
|
||
pubKey := publicKey(privKey) | ||
|
||
// Create the certificate | ||
derBytes, err := x509.CreateCertificate(rand.Reader, template, template, pubKey, privKey) | ||
if err != nil { | ||
return tls.Certificate{}, fmt.Errorf("x509 certificate creation error: %w", err) | ||
} | ||
|
||
// Encode the certificate and private key | ||
cert := tls.Certificate{ | ||
Certificate: [][]byte{derBytes}, | ||
PrivateKey: privKey, | ||
} | ||
|
||
return cert, nil | ||
} | ||
|
||
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") | ||
} | ||
} | ||
|
||
// Generate an ACME compatible certificate | ||
func generateACMECertificate(domains []string, email string, privKey crypto.PrivateKey) (*certificate.Resource, error) { | ||
user := MyUser{ | ||
Email: email, | ||
key: privKey, | ||
} | ||
|
||
config := lego.NewConfig(&user) | ||
config.CADirURL = lego.LEDirectoryStaging | ||
config.Certificate.KeyType = certcrypto.RSA2048 | ||
|
||
client, err := lego.NewClient(config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "5002")) | ||
if err != nil { | ||
return nil, err | ||
} | ||
err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", "5001")) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
user.Registration = reg | ||
|
||
request := certificate.ObtainRequest{ | ||
Domains: domains, | ||
Bundle: true, | ||
} | ||
|
||
return client.Certificate.Obtain(request) | ||
} | ||
|
||
// User structure to hold account details for ACME | ||
type MyUser struct { | ||
Email string | ||
Registration *registration.Resource | ||
key crypto.PrivateKey | ||
} | ||
|
||
func (u *MyUser) GetEmail() string { | ||
return u.Email | ||
} | ||
func (u MyUser) GetRegistration() *registration.Resource { | ||
return u.Registration | ||
} | ||
func (u *MyUser) GetPrivateKey() crypto.PrivateKey { | ||
return u.key | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package crypto | ||
|
||
import ( | ||
"crypto/rand" | ||
"testing" | ||
|
||
libp2pcrypto "github.com/libp2p/go-libp2p/core/crypto" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestConvertLibp2pPrivKeyToCryptoPrivKey(t *testing.T) { | ||
// Generate a libp2p ECDSA key pair for testing | ||
priv, _, err := libp2pcrypto.GenerateECDSAKeyPair(rand.Reader) | ||
require.NoError(t, err, "failed to generate libp2p ECDSA key pair") | ||
|
||
// Convert the libp2p private key to a crypto.PrivateKey | ||
cryptoPriv, err := convertLibp2pPrivKeyToCryptoPrivKey(priv) | ||
require.NoError(t, err, "failed to convert libp2p private key to crypto private key") | ||
require.NotNil(t, cryptoPriv, "converted crypto private key should not be nil") | ||
} | ||
|
||
func TestConvertLibp2pRSAPrivKeyToCryptoPrivKey(t *testing.T) { | ||
// Generate a libp2p RSA key pair for testing | ||
priv, _, err := libp2pcrypto.GenerateRSAKeyPair(2048, rand.Reader) | ||
require.NoError(t, err, "failed to generate libp2p RSA key pair") | ||
|
||
// Convert the libp2p private key to a crypto.PrivateKey | ||
cryptoPriv, err := convertLibp2pPrivKeyToCryptoPrivKey(priv) | ||
require.NoError(t, err, "failed to convert libp2p private key to crypto private key") | ||
require.NotNil(t, cryptoPriv, "converted crypto private key should not be nil") | ||
} | ||
|
||
func TestConvertLibp2pEd25519PrivKeyToCryptoPrivKey(t *testing.T) { | ||
// Generate a libp2p Ed25519 key pair for testing | ||
priv, _, err := libp2pcrypto.GenerateEd25519Key(rand.Reader) | ||
require.NoError(t, err, "failed to generate libp2p Ed25519 key pair") | ||
|
||
// Convert the libp2p private key to a crypto.PrivateKey | ||
cryptoPriv, err := convertLibp2pPrivKeyToCryptoPrivKey(priv) | ||
require.NoError(t, err, "failed to convert libp2p private key to crypto private key") | ||
require.NotNil(t, cryptoPriv, "converted crypto private key should not be nil") | ||
} | ||
|
||
func TestGenerateX509Certificate(t *testing.T) { | ||
// Generate a libp2p ECDSA key pair for testing | ||
priv, _, err := libp2pcrypto.GenerateECDSAKeyPair(rand.Reader) | ||
require.NoError(t, err, "failed to generate libp2p ECDSA key pair") | ||
|
||
// Convert the libp2p private key to a crypto.PrivateKey | ||
cryptoPriv, err := convertLibp2pPrivKeyToCryptoPrivKey(priv) | ||
require.NoError(t, err, "failed to convert libp2p private key") | ||
|
||
// Generate an X.509 certificate | ||
cert, err := generateX509Certificate(cryptoPriv) | ||
require.NoError(t, err, "failed to generate X.509 certificate") | ||
require.NotEmpty(t, cert.Certificate, "certificate should contain at least one DER encoded block") | ||
} | ||
|
||
func TestGenerateX509CertificateRSA(t *testing.T) { | ||
// Generate a libp2p RSA key pair for testing | ||
priv, _, err := libp2pcrypto.GenerateRSAKeyPair(2048, rand.Reader) | ||
require.NoError(t, err, "failed to generate libp2p RSA key pair") | ||
|
||
// Convert the libp2p private key to a crypto.PrivateKey | ||
cryptoPriv, err := convertLibp2pPrivKeyToCryptoPrivKey(priv) | ||
require.NoError(t, err, "failed to convert libp2p private key") | ||
|
||
// Generate an X.509 certificate | ||
cert, err := generateX509Certificate(cryptoPriv) | ||
require.NoError(t, err, "failed to generate X.509 certificate") | ||
require.NotEmpty(t, cert.Certificate, "certificate should contain at least one DER encoded block") | ||
} | ||
|
||
func TestGenerateX509CertificateEd25519(t *testing.T) { | ||
// Generate a libp2p Ed25519 key pair for testing | ||
priv, _, err := libp2pcrypto.GenerateEd25519Key(rand.Reader) | ||
require.NoError(t, err, "failed to generate libp2p Ed25519 key pair") | ||
|
||
// Convert the libp2p private key to a crypto.PrivateKey | ||
cryptoPriv, err := convertLibp2pPrivKeyToCryptoPrivKey(priv) | ||
require.NoError(t, err, "failed to convert libp2p private key") | ||
|
||
// Generate an X.509 certificate | ||
cert, err := generateX509Certificate(cryptoPriv) | ||
require.NoError(t, err, "failed to generate X.509 certificate") | ||
require.NotEmpty(t, cert.Certificate, "certificate should contain at least one DER encoded block") | ||
} |