Skip to content
This repository was archived by the owner on Apr 30, 2025. It is now read-only.

Commit 47ead2d

Browse files
ameowliageofffranks
authored andcommitted
add unit test to show gorouter can use ecdsa certs
1 parent 8ee00df commit 47ead2d

File tree

2 files changed

+133
-2
lines changed

2 files changed

+133
-2
lines changed

router/router_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,6 +1715,49 @@ var _ = Describe("Router", func() {
17151715
defer resp.Body.Close()
17161716
})
17171717

1718+
Context("when using ECDSA cert", func() {
1719+
BeforeEach(func() {
1720+
certChain := test_util.CreateSignedECDSACertWithRootCA(test_util.CertNames{SANs: test_util.SubjectAltNames{DNS: "test." + test_util.LocalhostDNS}})
1721+
config.CACerts = []string{string(certChain.CACertPEM)}
1722+
config.SSLCertificates = append(config.SSLCertificates, certChain.TLSCert())
1723+
config.CipherSuites = []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}
1724+
cert = certChain.CertPEM
1725+
1726+
rootCAs := x509.NewCertPool()
1727+
rootCAs.AddCert(certChain.CACert)
1728+
tlsClientConfig = &tls.Config{
1729+
RootCAs: rootCAs,
1730+
}
1731+
tlsClientConfig.CipherSuites = []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}
1732+
client = &http.Client{Transport: &http.Transport{
1733+
TLSClientConfig: tlsClientConfig,
1734+
}}
1735+
})
1736+
1737+
It("serves ssl traffic", func() {
1738+
app := test.NewGreetApp([]route.Uri{"test." + test_util.LocalhostDNS}, config.Port, mbusClient, nil)
1739+
app.RegisterAndListen()
1740+
Eventually(func() bool {
1741+
return appRegistered(registry, app)
1742+
}).Should(BeTrue())
1743+
1744+
uri := fmt.Sprintf("https://test.%s:%d/", test_util.LocalhostDNS, config.SSLPort)
1745+
req, _ := http.NewRequest("GET", uri, nil)
1746+
1747+
resp, err := client.Do(req)
1748+
Expect(err).ToNot(HaveOccurred())
1749+
Expect(resp).ToNot(BeNil())
1750+
1751+
Expect(resp.StatusCode).To(Equal(http.StatusOK))
1752+
1753+
bytes, err := io.ReadAll(resp.Body)
1754+
Expect(err).ToNot(HaveOccurred())
1755+
Expect(bytes).To(ContainSubstring("Hello"))
1756+
defer resp.Body.Close()
1757+
})
1758+
1759+
})
1760+
17181761
It("fails when the client uses an unsupported cipher suite", func() {
17191762
tlsClientConfig.MaxVersion = tls.VersionTLS12 // Can not configure cipher suites for TLS1.3
17201763
tlsClientConfig.CipherSuites = []uint16{tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}

test_util/helpers.go

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,9 @@ type CertChain struct {
321321
CertPEM, CACertPEM []byte
322322
PrivKeyPEM, CAPrivKeyPEM []byte
323323

324-
CACert *x509.Certificate
325-
CAPrivKey *rsa.PrivateKey
324+
CACert *x509.Certificate
325+
CAPrivKey *rsa.PrivateKey
326+
CAPrivKeyECDSA *ecdsa.PrivateKey
326327
}
327328

328329
func (cc *CertChain) AsTLSConfig() *tls.Config {
@@ -397,6 +398,50 @@ func CreateExpiredSignedCertWithRootCA(cert CertNames) CertChain {
397398
}
398399
}
399400

401+
func CreateSignedECDSACertWithRootCA(cert CertNames) CertChain {
402+
rootPrivateKey, rootCADER := CreateECDSACertDER("theCA")
403+
// generate a random serial number (a real cert authority would have some logic behind this)
404+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
405+
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
406+
Expect(err).ToNot(HaveOccurred())
407+
408+
subject := pkix.Name{Organization: []string{"xyz, Inc."}}
409+
410+
certTemplate := x509.Certificate{
411+
SerialNumber: serialNumber,
412+
Subject: subject,
413+
SignatureAlgorithm: x509.ECDSAWithSHA256,
414+
NotBefore: time.Now(),
415+
NotAfter: time.Now().Add(time.Hour), // valid for an hour
416+
BasicConstraintsValid: true,
417+
}
418+
if cert.SANs.IP != "" {
419+
certTemplate.IPAddresses = []net.IP{net.ParseIP(cert.SANs.IP)}
420+
}
421+
422+
if cert.SANs.DNS != "" {
423+
certTemplate.DNSNames = []string{cert.SANs.DNS}
424+
}
425+
rootCert, err := x509.ParseCertificate(rootCADER)
426+
Expect(err).NotTo(HaveOccurred())
427+
428+
ownKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
429+
Expect(err).NotTo(HaveOccurred())
430+
431+
certDER, err := x509.CreateCertificate(rand.Reader, &certTemplate, rootCert, &ownKey.PublicKey, rootPrivateKey)
432+
Expect(err).NotTo(HaveOccurred())
433+
ownKeyPEM, ownCertPEM := CreateECDSAKeyPairFromDER(certDER, ownKey)
434+
rootKeyPEM, rootCertPEM := CreateECDSAKeyPairFromDER(rootCADER, rootPrivateKey)
435+
return CertChain{
436+
CertPEM: ownCertPEM,
437+
PrivKeyPEM: ownKeyPEM,
438+
CACertPEM: rootCertPEM,
439+
CAPrivKeyPEM: rootKeyPEM,
440+
CACert: rootCert,
441+
CAPrivKeyECDSA: rootPrivateKey,
442+
}
443+
}
444+
400445
func CreateSignedCertWithRootCA(cert CertNames) CertChain {
401446
rootPrivateKey, rootCADER := CreateCertDER("theCA")
402447
// generate a random serial number (a real cert authority would have some logic behind this)
@@ -446,6 +491,37 @@ func (c *CertChain) TLSCert() tls.Certificate {
446491
return cert
447492
}
448493

494+
func CreateECDSACertDER(cname string) (*ecdsa.PrivateKey, []byte) {
495+
// generate a random serial number (a real cert authority would have some logic behind this)
496+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
497+
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
498+
Expect(err).ToNot(HaveOccurred())
499+
500+
subject := pkix.Name{Organization: []string{"xyz, Inc."}}
501+
if cname != "" {
502+
subject.CommonName = cname
503+
}
504+
505+
tmpl := x509.Certificate{
506+
SerialNumber: serialNumber,
507+
Subject: subject,
508+
SignatureAlgorithm: x509.ECDSAWithSHA256,
509+
NotBefore: time.Now(),
510+
NotAfter: time.Now().Add(time.Hour), // valid for an hour
511+
BasicConstraintsValid: true,
512+
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
513+
DNSNames: []string{cname},
514+
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
515+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
516+
IsCA: true,
517+
}
518+
519+
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
520+
Expect(err).ToNot(HaveOccurred())
521+
certDER, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, &privKey.PublicKey, privKey)
522+
Expect(err).ToNot(HaveOccurred())
523+
return privKey, certDER
524+
}
449525
func CreateCertDER(cname string) (*rsa.PrivateKey, []byte) {
450526
// generate a random serial number (a real cert authority would have some logic behind this)
451527
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
@@ -478,6 +554,18 @@ func CreateCertDER(cname string) (*rsa.PrivateKey, []byte) {
478554
return privKey, certDER
479555
}
480556

557+
func CreateECDSAKeyPairFromDER(certDER []byte, privKey *ecdsa.PrivateKey) (keyPEM, certPEM []byte) {
558+
b := pem.Block{Type: "CERTIFICATE", Bytes: certDER}
559+
certPEM = pem.EncodeToMemory(&b)
560+
keyB, err := x509.MarshalECPrivateKey(privKey)
561+
Expect(err).ToNot(HaveOccurred())
562+
keyPEM = pem.EncodeToMemory(&pem.Block{
563+
Type: "RSA PRIVATE KEY",
564+
Bytes: keyB,
565+
})
566+
567+
return
568+
}
481569
func CreateKeyPairFromDER(certDER []byte, privKey *rsa.PrivateKey) (keyPEM, certPEM []byte) {
482570
b := pem.Block{Type: "CERTIFICATE", Bytes: certDER}
483571
certPEM = pem.EncodeToMemory(&b)

0 commit comments

Comments
 (0)