123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- package utils
- import (
- "crypto/rand"
- "crypto/rsa"
- "crypto/tls"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/pem"
- "io/ioutil"
- "math/big"
- "net"
- "os"
- "time"
- )
- func getTLSConfig(caCert, cert, key []byte, allowInsecure bool) (*tls.Config, error) {
- // TLS config
- var tlsConfig tls.Config
- tlsConfig.InsecureSkipVerify = allowInsecure
- certPool := x509.NewCertPool()
- certPool.AppendCertsFromPEM(caCert)
- tlsConfig.RootCAs = certPool
- keypair, err := tls.X509KeyPair(cert, key)
- if err != nil {
- return &tlsConfig, err
- }
- tlsConfig.Certificates = []tls.Certificate{keypair}
- if allowInsecure {
- tlsConfig.InsecureSkipVerify = true
- }
- return &tlsConfig, nil
- }
- func newCertificate(org string) (*x509.Certificate, error) {
- now := time.Now()
- // need to set notBefore slightly in the past to account for time
- // skew in the VMs otherwise the certs sometimes are not yet valid
- notBefore := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute()-5, 0, 0, time.Local)
- notAfter := notBefore.Add(time.Hour * 24 * 1080)
- serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
- serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
- if err != nil {
- return nil, err
- }
- return &x509.Certificate{
- SerialNumber: serialNumber,
- Subject: pkix.Name{
- Organization: []string{org},
- },
- NotBefore: notBefore,
- NotAfter: notAfter,
- KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement,
- BasicConstraintsValid: true,
- }, nil
- }
- // GenerateCACertificate generates a new certificate authority from the specified org
- // and bit size and stores the resulting certificate and key file
- // in the arguments.
- func GenerateCACertificate(certFile, keyFile, org string, bits int) error {
- template, err := newCertificate(org)
- if err != nil {
- return err
- }
- template.IsCA = true
- template.KeyUsage |= x509.KeyUsageCertSign
- template.KeyUsage |= x509.KeyUsageKeyEncipherment
- template.KeyUsage |= x509.KeyUsageKeyAgreement
- priv, err := rsa.GenerateKey(rand.Reader, bits)
- if err != nil {
- return err
- }
- derBytes, err := x509.CreateCertificate(rand.Reader, template, template, &priv.PublicKey, priv)
- if err != nil {
- return err
- }
- certOut, err := os.Create(certFile)
- if err != nil {
- return err
- }
- pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
- certOut.Close()
- keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- return err
- }
- pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
- keyOut.Close()
- return nil
- }
- // GenerateCert generates a new certificate signed using the provided
- // certificate authority files and stores the result in the certificate
- // file and key provided. The provided host names are set to the
- // appropriate certificate fields.
- func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error {
- template, err := newCertificate(org)
- if err != nil {
- return err
- }
- // client
- if len(hosts) == 1 && hosts[0] == "" {
- template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
- template.KeyUsage = x509.KeyUsageDigitalSignature
- } else { // server
- template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
- for _, h := range hosts {
- if ip := net.ParseIP(h); ip != nil {
- template.IPAddresses = append(template.IPAddresses, ip)
- } else {
- template.DNSNames = append(template.DNSNames, h)
- }
- }
- }
- tlsCert, err := tls.LoadX509KeyPair(caFile, caKeyFile)
- if err != nil {
- return err
- }
- priv, err := rsa.GenerateKey(rand.Reader, bits)
- if err != nil {
- return err
- }
- x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
- if err != nil {
- return err
- }
- derBytes, err := x509.CreateCertificate(rand.Reader, template, x509Cert, &priv.PublicKey, tlsCert.PrivateKey)
- if err != nil {
- return err
- }
- certOut, err := os.Create(certFile)
- if err != nil {
- return err
- }
- pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
- certOut.Close()
- keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- return err
- }
- pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
- keyOut.Close()
- return nil
- }
- func ValidateCertificate(addr, caCertPath, serverCertPath, serverKeyPath string) (bool, error) {
- caCert, err := ioutil.ReadFile(caCertPath)
- if err != nil {
- return false, err
- }
- serverCert, err := ioutil.ReadFile(serverCertPath)
- if err != nil {
- return false, err
- }
- serverKey, err := ioutil.ReadFile(serverKeyPath)
- if err != nil {
- return false, err
- }
- tlsConfig, err := getTLSConfig(caCert, serverCert, serverKey, false)
- if err != nil {
- return false, err
- }
- dialer := &net.Dialer{
- Timeout: time.Second * 2,
- }
- _, err = tls.DialWithDialer(dialer, "tcp", addr, tlsConfig)
- if err != nil {
- return false, nil
- }
- return true, nil
- }
|