-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpandaweb.go
60 lines (54 loc) · 1.9 KB
/
pandaweb.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package pandaweb
import (
"crypto/tls"
"errors"
"fmt"
"sync"
)
// CertificateManager manages vending the correct certificate for a given
// ClientHello. It also handles updating certificates (e.g. renewals). Its
// methods are safe for simultaneous use by multiple goroutines.
type CertificateManager struct {
certificates []tls.Certificate
nameToCertificate map[string]*tls.Certificate
m sync.RWMutex
}
// SetCertificates updates the set of certificates. It parses the certificates
// and builds a map from names to certificates based on the CommonName and
// SubjectAlternateName fields of the leaf certificates.
func (cm *CertificateManager) SetCertificates(certificates []tls.Certificate) {
c := &tls.Config{
Certificates: certificates,
}
c.BuildNameToCertificate()
cm.m.Lock()
cm.certificates = certificates
cm.nameToCertificate = c.NameToCertificate
cm.m.Unlock()
}
// LoadX509KeyPair updates CertificateManager's certificates from a pair of PEM
// encoded files.
func (cm *CertificateManager) LoadX509KeyPair(certFile, keyFile string) error {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return fmt.Errorf("CertificateManager failed to load X509 key pair: %v", err)
}
certs := []tls.Certificate{cert}
cm.SetCertificates(certs)
return nil
}
// GetCertificate returns certificate corresponding to the SNI info in the
// ClientHello, or the first certificate if no SNI info is provided. It returns
// nil if it cannot find an appropriate certificate given the SNI info.
func (cm *CertificateManager) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
cm.m.RLock()
defer cm.m.RUnlock()
if len(cm.certificates) == 0 {
return nil, errors.New("CertificateManager does not have any certificates")
}
if clientHello.ServerName == "" {
return &cm.certificates[0], nil
}
c, _ := cm.nameToCertificate[clientHello.ServerName]
return c, nil
}