From 2805adff068eda4d717fc0457a69eb5a6dcd4c4e Mon Sep 17 00:00:00 2001 From: liuxinfeng Date: Tue, 12 Sep 2023 18:12:17 +0800 Subject: [PATCH 1/2] Added the utils for generating keys and certificates --- go.mod | 20 ++-- utils/certificate.go | 210 ++++++++++++++++++++++++++++++++++++++ utils/certificate_test.go | 78 ++++++++++++++ utils/key.go | 108 ++++++++++++++++++++ utils/key_test.go | 29 ++++++ 5 files changed, 432 insertions(+), 13 deletions(-) create mode 100644 utils/certificate.go create mode 100644 utils/certificate_test.go create mode 100644 utils/key.go create mode 100644 utils/key_test.go diff --git a/go.mod b/go.mod index 37390527..761b069c 100644 --- a/go.mod +++ b/go.mod @@ -8,18 +8,12 @@ require ( github.com/aristanetworks/goarista v0.0.0-20210107181124-fad53805024e // indirect github.com/btcsuite/btcd v0.21.0-beta // indirect github.com/ethereum/go-ethereum v1.9.16 - github.com/go-ole/go-ole v1.2.5 // indirect - github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 // indirect - github.com/google/uuid v1.1.1 - github.com/holiman/uint256 v1.1.1 // indirect - github.com/shirou/gopsutil v3.20.12+incompatible // indirect - github.com/sirupsen/logrus v1.8.1 - github.com/spf13/cobra v1.0.0 - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.6.2 - github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 - golang.org/x/net v0.2.0 // indirect - golang.org/x/sync v0.1.0 // indirect + github.com/google/uuid v1.3.0 + github.com/liuxinfeng96/bc-crypto v0.2.12 + github.com/sirupsen/logrus v1.9.0 + github.com/spf13/cobra v1.5.0 + github.com/spf13/viper v1.8.1 + github.com/stretchr/testify v1.7.0 + golang.org/x/crypto v0.12.0 gopkg.in/urfave/cli.v1 v1.20.0 ) diff --git a/utils/certificate.go b/utils/certificate.go new file mode 100644 index 00000000..d7149721 --- /dev/null +++ b/utils/certificate.go @@ -0,0 +1,210 @@ +package utils + +import ( + "crypto/rand" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "time" + + bcx509 "github.com/liuxinfeng96/bc-crypto/x509" +) + +const DefaultFiscoBcosCertOrganization = "fisco-bcos" + +const ( + DefaultCertificateCountry = "CN" + DefaultCertificateProvince = "GuangDong" + DefaultCertificateLocality = "ShenZhen" +) + +// GenerateCertificateSigningRequest +// create the CSR with X.509 +// return the CSR byte array with PEM +func GenerateCertificateSigningRequest(privateKeyBytes []byte, + role, certName string) ([]byte, error) { + + sk, err := bcx509.ParsePrivateKey(privateKeyBytes) + if err != nil { + return nil, err + } + + signatureAlgorithm, err := bcx509.GetSignatureAlgorithm(sk) + if err != nil { + return nil, err + } + + templateX509 := &bcx509.CertificateRequest{ + SignatureAlgorithm: signatureAlgorithm, + Subject: pkix.Name{ + Country: []string{DefaultCertificateCountry}, + Locality: []string{DefaultCertificateLocality}, + Province: []string{DefaultCertificateProvince}, + OrganizationalUnit: []string{role}, + Organization: []string{DefaultFiscoBcosCertOrganization}, + CommonName: certName, + }, + } + + data, err := bcx509.CreateCertificateRequest(rand.Reader, templateX509, sk) + if err != nil { + return nil, err + } + + pemCSR := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: data}) + + return pemCSR, nil +} + +// GenerateCertificateSelf +// create a self-signed digital certificate with X.509 +// return the certificate byte array with PEM +func GenerateCertificateSelf(privateKeyBytes, csrBytes []byte, + days int) ([]byte, error) { + + csr, err := bcx509.ParseCertificateRequestFromPEM(csrBytes) + if err != nil { + return nil, err + } + + if err = csr.CheckSignature(); err != nil { + return nil, err + } + + keyUsage, extKeyUsage := bcx509.GetKeyUsageAndExtKeyUsage(true) + + notBefore := time.Now().UTC() + + sn, err := rand.Int(rand.Reader, big.NewInt(1<<62)) + if err != nil { + return nil, err + } + + caKey, err := bcx509.ParsePrivateKey(privateKeyBytes) + if err != nil { + return nil, err + } + + signatureAlgorithm, err := bcx509.GetSignatureAlgorithm(caKey) + if err != nil { + return nil, err + } + + template := &bcx509.Certificate{ + SerialNumber: sn, + NotBefore: notBefore, + NotAfter: notBefore.Add(365 * 10 * time.Hour * 24).UTC(), + BasicConstraintsValid: true, + IsCA: true, + KeyUsage: keyUsage, + ExtKeyUsage: extKeyUsage, + DNSNames: csr.DNSNames, + Subject: csr.Subject, + Extensions: csr.Extensions, + ExtraExtensions: csr.ExtraExtensions, + SignatureAlgorithm: signatureAlgorithm, + PublicKeyAlgorithm: csr.PublicKeyAlgorithm, + PublicKey: csr.PublicKey, + } + + template.SubjectKeyId, err = bcx509.ComputeSKI(csr.PublicKey) + if err != nil { + return nil, err + } + + templateOfIssuer := new(bcx509.Certificate) + templateOfIssuer = template + + certDER, err := bcx509.CreateCertificate(rand.Reader, template, templateOfIssuer, + csr.PublicKey, caKey) + if err != nil { + return nil, err + } + + certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) + + return certPEM, nil + +} + +// GenerateCertificate +// create a certificate with X.509 +// return the certificate byte array with PEM +func GenerateCertificate(caCertBytes, caKeyBytes, csrBytes []byte, isCa bool, + days int) ([]byte, error) { + csr, err := bcx509.ParseCertificateRequestFromPEM(csrBytes) + if err != nil { + return nil, err + } + + if err = csr.CheckSignature(); err != nil { + return nil, err + } + + keyUsage, extKeyUsage := bcx509.GetKeyUsageAndExtKeyUsage(isCa) + + notBefore := time.Now().UTC() + + sn, err := rand.Int(rand.Reader, big.NewInt(1<<62)) + if err != nil { + return nil, err + } + + caKey, err := bcx509.ParsePrivateKey(caKeyBytes) + if err != nil { + return nil, err + } + + signatureAlgorithm, err := bcx509.GetSignatureAlgorithm(caKey) + if err != nil { + return nil, err + } + + template := &bcx509.Certificate{ + SerialNumber: sn, + NotBefore: notBefore, + NotAfter: notBefore.Add(365 * 10 * time.Hour * 24).UTC(), + BasicConstraintsValid: true, + IsCA: isCa, + KeyUsage: keyUsage, + ExtKeyUsage: extKeyUsage, + DNSNames: csr.DNSNames, + Subject: csr.Subject, + Extensions: csr.Extensions, + ExtraExtensions: csr.ExtraExtensions, + SignatureAlgorithm: signatureAlgorithm, + PublicKeyAlgorithm: csr.PublicKeyAlgorithm, + PublicKey: csr.PublicKey, + } + + template.SubjectKeyId, err = bcx509.ComputeSKI(csr.PublicKey) + if err != nil { + return nil, err + } + + certOfIssuer, err := bcx509.ParseCertificateFromPEM(caCertBytes) + if err != nil { + return nil, err + } + + template.Issuer = certOfIssuer.Subject + + if certOfIssuer.SubjectKeyId != nil { + template.AuthorityKeyId = certOfIssuer.SubjectKeyId + } else { + template.AuthorityKeyId, err = bcx509.ComputeSKI(certOfIssuer.PublicKey) + if err != nil { + return nil, err + } + } + + certDER, err := bcx509.CreateCertificate(rand.Reader, template, certOfIssuer, + csr.PublicKey, caKey) + if err != nil { + return nil, err + } + + certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) + + return certPEM, nil +} diff --git a/utils/certificate_test.go b/utils/certificate_test.go new file mode 100644 index 00000000..11bc83d2 --- /dev/null +++ b/utils/certificate_test.go @@ -0,0 +1,78 @@ +package utils + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCreateCertificateSigningRequest(t *testing.T) { + sk, err := GenerateSecp256k1Key() + require.Nil(t, err) + + // sk, err := GenerateSm2Key() + // require.Nil(t, err) + + // sk, err := GenerateRSA2048Key() + // require.Nil(t, err) + + csrBytes, err := GenerateCertificateSigningRequest(sk, "node", "node1") + require.Nil(t, err) + + fmt.Println(string(csrBytes)) +} + +func TestCreateCertificateSelf(t *testing.T) { + sk, err := GenerateSecp256k1Key() + require.Nil(t, err) + + // sk, err := GenerateSm2Key() + // require.Nil(t, err) + + // sk, err := GenerateRSA2048Key() + // require.Nil(t, err) + + csrBytes, err := GenerateCertificateSigningRequest(sk, "group-ca", "ca1") + require.Nil(t, err) + + caBytes, err := GenerateCertificateSelf(sk, csrBytes, 365) + require.Nil(t, err) + + fmt.Println(string(caBytes)) + +} + +func TestCreateCertificate(t *testing.T) { + // caSk, err := GenerateSecp256k1Key() + // require.Nil(t, err) + + caSk, err := GenerateSm2Key() + require.Nil(t, err) + + // caSk, err := GenerateRSA2048Key() + // require.Nil(t, err) + + caCsrBytes, err := GenerateCertificateSigningRequest(caSk, "group-ca", "ca1") + require.Nil(t, err) + + caBytes, err := GenerateCertificateSelf(caSk, caCsrBytes, 365) + require.Nil(t, err) + + // sk, err := GenerateSecp256k1Key() + // require.Nil(t, err) + + // sk, err := GenerateSm2Key() + // require.Nil(t, err) + + sk, err := GenerateRSA2048Key() + require.Nil(t, err) + + csrBytes, err := GenerateCertificateSigningRequest(sk, "node", "node1") + require.Nil(t, err) + + certBytes, err := GenerateCertificate(caBytes, caSk, csrBytes, false, 365) + require.Nil(t, err) + + fmt.Println(string(certBytes)) +} diff --git a/utils/key.go b/utils/key.go new file mode 100644 index 00000000..f056cce5 --- /dev/null +++ b/utils/key.go @@ -0,0 +1,108 @@ +package utils + +import ( + "bytes" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + + "github.com/liuxinfeng96/bc-crypto/ecdsa" + bcx509 "github.com/liuxinfeng96/bc-crypto/x509" +) + +// GenerateSecp256k1Key +// generate the private key of the Secp256k1 algorithm +// return the key byte array with PEM +func GenerateSecp256k1Key() ([]byte, error) { + key, err := bcx509.GenerateKey(bcx509.EC_Secp256k1) + if err != nil { + return nil, err + } + + ecKey, ok := key.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("the wrong type of key") + } + + skDer, err := bcx509.MarshalECPrivateKey(ecKey) + if err != nil { + return nil, err + } + + skBlock := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: skDer, + } + + skBuf := new(bytes.Buffer) + if err = pem.Encode(skBuf, skBlock); err != nil { + return nil, err + } + + return skBuf.Bytes(), nil +} + +// GenerateSm2Key +// generate the private key of the SM2 algorithm +// return the key byte array with PEM +func GenerateSm2Key() ([]byte, error) { + key, err := bcx509.GenerateKey(bcx509.EC_SM2) + if err != nil { + return nil, err + } + + ecKey, ok := key.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("the wrong type of key") + } + + skDer, err := bcx509.MarshalECPrivateKey(ecKey) + if err != nil { + return nil, err + } + + skBlock := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: skDer, + } + + skBuf := new(bytes.Buffer) + if err = pem.Encode(skBuf, skBlock); err != nil { + return nil, err + } + + return skBuf.Bytes(), nil +} + +// GenerateRSA2048Key +// generate the private key of the RSA2048 algorithm +// return the key byte array with PEM +func GenerateRSA2048Key() ([]byte, error) { + key, err := bcx509.GenerateKey(bcx509.RSA2048) + if err != nil { + return nil, err + } + + rsaKey, ok := key.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("the wrong type of key") + } + + skDer, err := x509.MarshalPKCS8PrivateKey(rsaKey) + if err != nil { + return nil, err + } + + skBlock := &pem.Block{ + Type: "PRIVATE KEY", + Bytes: skDer, + } + + skBuf := new(bytes.Buffer) + if err = pem.Encode(skBuf, skBlock); err != nil { + return nil, err + } + + return skBuf.Bytes(), nil +} diff --git a/utils/key_test.go b/utils/key_test.go new file mode 100644 index 00000000..e8b406a8 --- /dev/null +++ b/utils/key_test.go @@ -0,0 +1,29 @@ +package utils + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGenerateKey(t *testing.T) { + secp256k1Key, err := GenerateSecp256k1Key() + require.Nil(t, err) + + fmt.Print(string(secp256k1Key)) + fmt.Println("---------------------------测试分割线--------------------------------") + + sm2Key, err := GenerateSm2Key() + require.Nil(t, err) + + fmt.Print(string(sm2Key)) + fmt.Println("---------------------------测试分割线--------------------------------") + + rsa2048Key, err := GenerateRSA2048Key() + require.Nil(t, err) + + fmt.Print(string(rsa2048Key)) + fmt.Println("---------------------------测试分割线--------------------------------") + +} From 8360590f2a21c33935f926f0c4bec6cda5d1fc89 Mon Sep 17 00:00:00 2001 From: liuxinfeng Date: Wed, 13 Sep 2023 09:23:40 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E7=AD=BE=E5=8F=91=E6=97=A5=E6=9C=9F?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/certificate.go | 4 ++-- utils/certificate_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/certificate.go b/utils/certificate.go index d7149721..d58792cf 100644 --- a/utils/certificate.go +++ b/utils/certificate.go @@ -93,7 +93,7 @@ func GenerateCertificateSelf(privateKeyBytes, csrBytes []byte, template := &bcx509.Certificate{ SerialNumber: sn, NotBefore: notBefore, - NotAfter: notBefore.Add(365 * 10 * time.Hour * 24).UTC(), + NotAfter: notBefore.Add(time.Hour * 24 * time.Duration(days)).UTC(), BasicConstraintsValid: true, IsCA: true, KeyUsage: keyUsage, @@ -163,7 +163,7 @@ func GenerateCertificate(caCertBytes, caKeyBytes, csrBytes []byte, isCa bool, template := &bcx509.Certificate{ SerialNumber: sn, NotBefore: notBefore, - NotAfter: notBefore.Add(365 * 10 * time.Hour * 24).UTC(), + NotAfter: notBefore.Add(time.Hour * 24 * time.Duration(days)).UTC(), BasicConstraintsValid: true, IsCA: isCa, KeyUsage: keyUsage, diff --git a/utils/certificate_test.go b/utils/certificate_test.go index 11bc83d2..0082e8e4 100644 --- a/utils/certificate_test.go +++ b/utils/certificate_test.go @@ -71,7 +71,7 @@ func TestCreateCertificate(t *testing.T) { csrBytes, err := GenerateCertificateSigningRequest(sk, "node", "node1") require.Nil(t, err) - certBytes, err := GenerateCertificate(caBytes, caSk, csrBytes, false, 365) + certBytes, err := GenerateCertificate(caBytes, caSk, csrBytes, false, 365*10) require.Nil(t, err) fmt.Println(string(certBytes))