mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-04 15:35:38 +00:00
f13e5e38b2
Signed-off-by: David Anderson <danderson@tailscale.com>
48 lines
1.5 KiB
Go
48 lines
1.5 KiB
Go
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"path/filepath"
|
|
"regexp"
|
|
)
|
|
|
|
var unsafeHostnameCharacters = regexp.MustCompile(`[^a-zA-Z0-9-\.]`)
|
|
|
|
type manualCertManager struct {
|
|
cert *tls.Certificate
|
|
hostname string
|
|
}
|
|
|
|
// NewManualCertManager returns a cert provider which read certificate by given hostname on create.
|
|
func NewManualCertManager(certdir, hostname string) (*manualCertManager, error) {
|
|
keyname := unsafeHostnameCharacters.ReplaceAllString(hostname, "")
|
|
crtPath := filepath.Join(certdir, keyname+".crt")
|
|
keyPath := filepath.Join(certdir, keyname+".key")
|
|
cert, err := tls.LoadX509KeyPair(crtPath, keyPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("can not load x509 key pair for hostname %q: %w", keyname, err)
|
|
}
|
|
// ensure hostname matches with the certificate
|
|
x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("can not load cert: %w", err)
|
|
}
|
|
if err := x509Cert.VerifyHostname(hostname); err != nil {
|
|
return nil, fmt.Errorf("cert invalid for hostname %q: %w", hostname, err)
|
|
}
|
|
return &manualCertManager{cert: &cert, hostname: hostname}, nil
|
|
}
|
|
|
|
func (m *manualCertManager) GetCertificate(hi *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
|
if hi.ServerName != m.hostname {
|
|
return nil, fmt.Errorf("cert mismatch with hostname: %q", hi.ServerName)
|
|
}
|
|
return m.cert, nil
|
|
}
|