2018-12-11 02:59:03 +10:00
|
|
|
// Copyright 2015 Matthew Holt
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
2022-09-27 02:19:28 +10:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2018-12-11 02:59:03 +10:00
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
package certmagic
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/tls"
|
|
|
|
"crypto/x509"
|
2019-02-03 04:10:17 +10:00
|
|
|
"net"
|
2018-12-11 02:59:03 +10:00
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestGetCertificate(t *testing.T) {
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
c := &Cache{
|
|
|
|
cache: make(map[string]Certificate),
|
|
|
|
cacheIndex: make(map[string][]string),
|
2022-09-27 02:19:28 +10:00
|
|
|
logger: defaultTestLogger,
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
}
|
2022-09-27 02:19:28 +10:00
|
|
|
cfg := &Config{Logger: defaultTestLogger, certCache: c}
|
2018-12-11 02:59:03 +10:00
|
|
|
|
2019-02-03 04:10:17 +10:00
|
|
|
// create a test connection for conn.LocalAddr()
|
|
|
|
l, _ := net.Listen("tcp", "127.0.0.1:0")
|
|
|
|
defer l.Close()
|
|
|
|
conn, _ := net.Dial("tcp", l.Addr().String())
|
|
|
|
if conn == nil {
|
|
|
|
t.Errorf("failed to create a test connection")
|
|
|
|
}
|
|
|
|
defer conn.Close()
|
|
|
|
|
|
|
|
hello := &tls.ClientHelloInfo{ServerName: "example.com", Conn: conn}
|
|
|
|
helloSub := &tls.ClientHelloInfo{ServerName: "sub.example.com", Conn: conn}
|
|
|
|
helloNoSNI := &tls.ClientHelloInfo{Conn: conn}
|
|
|
|
helloNoMatch := &tls.ClientHelloInfo{ServerName: "nomatch", Conn: conn}
|
2018-12-11 02:59:03 +10:00
|
|
|
|
|
|
|
// When cache is empty
|
|
|
|
if cert, err := cfg.GetCertificate(hello); err == nil {
|
|
|
|
t.Errorf("GetCertificate should return error when cache is empty, got: %v", cert)
|
|
|
|
}
|
|
|
|
if cert, err := cfg.GetCertificate(helloNoSNI); err == nil {
|
|
|
|
t.Errorf("GetCertificate should return error when cache is empty even if server name is blank, got: %v", cert)
|
|
|
|
}
|
|
|
|
|
|
|
|
// When cache has one certificate in it
|
|
|
|
firstCert := Certificate{Names: []string{"example.com"}, Certificate: tls.Certificate{Leaf: &x509.Certificate{DNSNames: []string{"example.com"}}}}
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
c.cacheCertificate(firstCert)
|
2018-12-11 02:59:03 +10:00
|
|
|
if cert, err := cfg.GetCertificate(hello); err != nil {
|
|
|
|
t.Errorf("Got an error but shouldn't have, when cert exists in cache: %v", err)
|
|
|
|
} else if cert.Leaf.DNSNames[0] != "example.com" {
|
|
|
|
t.Errorf("Got wrong certificate with exact match; expected 'example.com', got: %v", cert)
|
|
|
|
}
|
2019-02-03 04:10:17 +10:00
|
|
|
if _, err := cfg.GetCertificate(helloNoSNI); err == nil {
|
|
|
|
t.Errorf("Did not get an error with no SNI and no DefaultServerName, but should have: %v", err)
|
2018-12-11 02:59:03 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// When retrieving wildcard certificate
|
|
|
|
wildcardCert := Certificate{
|
|
|
|
Names: []string{"*.example.com"},
|
|
|
|
Certificate: tls.Certificate{Leaf: &x509.Certificate{DNSNames: []string{"*.example.com"}}},
|
2019-06-25 03:51:58 +10:00
|
|
|
hash: "(don't overwrite the first one)",
|
2018-12-11 02:59:03 +10:00
|
|
|
}
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
c.cacheCertificate(wildcardCert)
|
2018-12-11 02:59:03 +10:00
|
|
|
if cert, err := cfg.GetCertificate(helloSub); err != nil {
|
|
|
|
t.Errorf("Didn't get wildcard cert, got: cert=%v, err=%v ", cert, err)
|
|
|
|
} else if cert.Leaf.DNSNames[0] != "*.example.com" {
|
|
|
|
t.Errorf("Got wrong certificate, expected wildcard: %v", cert)
|
|
|
|
}
|
|
|
|
|
|
|
|
// When cache is NOT empty but there's no SNI
|
2019-02-03 04:10:17 +10:00
|
|
|
if _, err := cfg.GetCertificate(helloNoSNI); err == nil {
|
|
|
|
t.Errorf("Expected TLS allert when no SNI and no DefaultServerName, but got: %v", err)
|
2018-12-11 02:59:03 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// When no certificate matches, raise an alert
|
|
|
|
if _, err := cfg.GetCertificate(helloNoMatch); err == nil {
|
|
|
|
t.Errorf("Expected an error when no certificate matched the SNI, got: %v", err)
|
|
|
|
}
|
2019-02-03 04:10:17 +10:00
|
|
|
|
|
|
|
// When default SNI is set and SNI is missing, retrieve default cert
|
|
|
|
cfg.DefaultServerName = "example.com"
|
|
|
|
if cert, err := cfg.GetCertificate(helloNoSNI); err != nil {
|
|
|
|
t.Errorf("Got an error with no SNI with DefaultServerName, but shouldn't have: %v", err)
|
|
|
|
} else if cert == nil || cert.Leaf.DNSNames[0] != "example.com" {
|
|
|
|
t.Errorf("Expected default cert, got: %v", cert)
|
|
|
|
}
|
|
|
|
|
|
|
|
// When default SNI is set and SNI is missing but IP address matches, retrieve IP cert
|
|
|
|
ipCert := Certificate{
|
|
|
|
Names: []string{"127.0.0.1"},
|
|
|
|
Certificate: tls.Certificate{Leaf: &x509.Certificate{IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}}},
|
2019-06-25 03:51:58 +10:00
|
|
|
hash: "(don't overwrite the first or second one)",
|
2019-02-03 04:10:17 +10:00
|
|
|
}
|
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor
This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.
The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.
There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.
Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.
* Fix little oopsies
* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-21 02:44:55 +10:00
|
|
|
c.cacheCertificate(ipCert)
|
2019-02-03 04:10:17 +10:00
|
|
|
if cert, err := cfg.GetCertificate(helloNoSNI); err != nil {
|
|
|
|
t.Errorf("Got an error with no SNI but matching IP, but shouldn't have: %v", err)
|
|
|
|
} else if cert == nil || len(cert.Leaf.IPAddresses) == 0 {
|
|
|
|
t.Errorf("Expected IP cert, got: %v", cert)
|
|
|
|
}
|
2018-12-11 02:59:03 +10:00
|
|
|
}
|