mirror of
https://github.com/nabbar/golib.git
synced 2025-10-04 15:32:48 +08:00

- rework package to allow convert config to model and retrive config from model - add sub package to manage cipher, curves, auth client, tls version, certificates, root ca... - add some small test (can be expande to having more coverage) - optimize some code Package httpcli: - update code following change in certificates Package httpserver: - update code following change in certificates Package Config/Components: - update code following change in certificates Package FTPClient: - update code following change in certificates Package Nats: - update code following change in certificates
215 lines
6.6 KiB
Go
215 lines
6.6 KiB
Go
/*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2020 Nicolas JUHEL
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
package certificates_test
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/json"
|
|
"encoding/pem"
|
|
"math/big"
|
|
"net"
|
|
"os"
|
|
"time"
|
|
|
|
libtls "github.com/nabbar/golib/certificates"
|
|
tlscrt "github.com/nabbar/golib/certificates/certs"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
func genCertififcate() ([]byte, []byte) {
|
|
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(priv).ToNot(BeNil())
|
|
|
|
keyUsage := x509.KeyUsageDigitalSignature
|
|
notBefore := time.Now()
|
|
notAfter := notBefore.Add(time.Hour * 24 * 365)
|
|
|
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
|
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
template := x509.Certificate{
|
|
SerialNumber: serialNumber,
|
|
Subject: pkix.Name{
|
|
Organization: []string{"Acme Co"},
|
|
},
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
KeyUsage: keyUsage,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
BasicConstraintsValid: true,
|
|
}
|
|
template.DNSNames = append(template.DNSNames, "example.com")
|
|
template.DNSNames = append(template.DNSNames, "localhost")
|
|
|
|
if ip := net.ParseIP("127.0.0.1"); ip != nil {
|
|
template.IPAddresses = append(template.IPAddresses, ip)
|
|
}
|
|
|
|
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
bufPub := bytes.NewBuffer(make([]byte, 0))
|
|
err = pem.Encode(bufPub, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
bufKey := bytes.NewBuffer(make([]byte, 0))
|
|
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
err = pem.Encode(bufKey, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
return bufPub.Bytes(), bufKey.Bytes()
|
|
}
|
|
|
|
func writeGenCert(pub, key string) {
|
|
p, k := genCertififcate()
|
|
|
|
f, e := os.Create(pub)
|
|
Expect(e).ToNot(HaveOccurred())
|
|
_, e = f.Write(p)
|
|
Expect(e).ToNot(HaveOccurred())
|
|
Expect(f.Close()).ToNot(HaveOccurred())
|
|
|
|
f, e = os.Create(key)
|
|
Expect(e).ToNot(HaveOccurred())
|
|
_, e = f.Write(k)
|
|
Expect(e).ToNot(HaveOccurred())
|
|
Expect(f.Close()).ToNot(HaveOccurred())
|
|
}
|
|
|
|
func getConfigFile() []byte {
|
|
writeGenCert(pubFile, keyFile)
|
|
|
|
str := &tlscrt.ConfigPair{
|
|
Key: keyFile,
|
|
Pub: pubFile,
|
|
}
|
|
|
|
p, e := json.Marshal(str)
|
|
Expect(e).ToNot(HaveOccurred())
|
|
|
|
var oldConfig string = `{
|
|
"authClient": "none",
|
|
"certs": [` + string(p) + `],
|
|
"cipherList": ["RSA_AES_128_GCM_SHA256", "RSA_AES_256_GCM_SHA384", "ECDHE_RSA_AES_128_GCM_SHA256", "ECDHE_ECDSA_AES_128_GCM_SHA256", "ECDHE_RSA_AES_256_GCM_SHA384", "ECDHE_ECDSA_AES_256_GCM_SHA384", "ECDHE_RSA_CHACHA20_POLY1305_SHA256", "ECDHE_ECDSA_CHACHA20_POLY1305_SHA256", "AES_128_GCM_SHA256", "AES_256_GCM_SHA384", "CHACHA20_POLY1305_SHA256"],
|
|
"clientCA": [],
|
|
"curveList": ["X25519", "P256", "P384", "P521"],
|
|
"dynamicSizingDisable": false,
|
|
"inheritDefault": false,
|
|
"rootCA": [],
|
|
"sessionTicketDisable": false,
|
|
"versionMax": "1.3",
|
|
"versionMin": "1.2"
|
|
}`
|
|
|
|
return []byte(oldConfig)
|
|
}
|
|
|
|
func getConfigChain() []byte {
|
|
pub, key := genCertififcate()
|
|
str := "\n" + string(pub) + string(key)
|
|
buf, err := json.Marshal(str)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
var oldConfig string = `{
|
|
"authClient": "none",
|
|
"certs": [` + string(buf) + `],
|
|
"cipherList": ["RSA_AES_128_GCM_SHA256", "RSA_AES_256_GCM_SHA384", "ECDHE_RSA_AES_128_GCM_SHA256", "ECDHE_ECDSA_AES_128_GCM_SHA256", "ECDHE_RSA_AES_256_GCM_SHA384", "ECDHE_ECDSA_AES_256_GCM_SHA384", "ECDHE_RSA_CHACHA20_POLY1305_SHA256", "ECDHE_ECDSA_CHACHA20_POLY1305_SHA256", "AES_128_GCM_SHA256", "AES_256_GCM_SHA384", "CHACHA20_POLY1305_SHA256"],
|
|
"clientCA": [],
|
|
"curveList": ["X25519", "P256", "P384", "P521"],
|
|
"dynamicSizingDisable": false,
|
|
"inheritDefault": false,
|
|
"rootCA": [],
|
|
"sessionTicketDisable": false,
|
|
"versionMax": "1.3",
|
|
"versionMin": "1.2"
|
|
}`
|
|
|
|
return []byte(oldConfig)
|
|
}
|
|
|
|
var _ = Describe("certificates test", func() {
|
|
|
|
Context("Using a config json", func() {
|
|
It("must success to new Config when certificates are paste as file mode", func() {
|
|
cfg := libtls.Config{}
|
|
|
|
p := getConfigFile()
|
|
Expect(len(p)).To(BeNumerically(">", 0))
|
|
|
|
e := json.Unmarshal(p, &cfg)
|
|
Expect(e).ToNot(HaveOccurred())
|
|
|
|
cnf := cfg.New()
|
|
Expect(cnf).ToNot(BeNil())
|
|
Expect(len(cnf.GetCertificatePair())).To(Equal(1))
|
|
|
|
cfgtls := cnf.TLS("localhost")
|
|
Expect(cfgtls).ToNot(BeNil())
|
|
Expect(len(cfgtls.Certificates)).To(Equal(1))
|
|
Expect(len(cfgtls.CipherSuites)).To(BeNumerically(">", 0))
|
|
Expect(len(cfgtls.CurvePreferences)).To(BeNumerically(">", 0))
|
|
|
|
p, e = json.Marshal(cnf.Config())
|
|
Expect(e).ToNot(HaveOccurred())
|
|
Expect(len(p)).To(BeNumerically(">", 0))
|
|
})
|
|
It("must success to new Config when certificates are paste as chain mode", func() {
|
|
cfg := libtls.Config{}
|
|
|
|
p := getConfigChain()
|
|
Expect(len(p)).To(BeNumerically(">", 0))
|
|
|
|
e := json.Unmarshal(p, &cfg)
|
|
Expect(e).ToNot(HaveOccurred())
|
|
|
|
cnf := cfg.New()
|
|
Expect(cnf).ToNot(BeNil())
|
|
Expect(len(cnf.GetCertificatePair())).To(Equal(1))
|
|
|
|
cfgtls := cnf.TLS("localhost")
|
|
Expect(cfgtls).ToNot(BeNil())
|
|
Expect(len(cfgtls.Certificates)).To(Equal(1))
|
|
Expect(len(cfgtls.CipherSuites)).To(BeNumerically(">", 0))
|
|
Expect(len(cfgtls.CurvePreferences)).To(BeNumerically(">", 0))
|
|
|
|
p, e = json.Marshal(cnf)
|
|
Expect(e).ToNot(HaveOccurred())
|
|
Expect(len(p)).To(BeNumerically(">", 0))
|
|
})
|
|
})
|
|
})
|