src/server/pkg/cert/cert.go
func GenerateSelfSignedCert(address string, name *pkix.Name, ipAddresses ...string) (*tls.Certificate, error) {
	// Generate Subject Distinguished Name
	if name == nil {
		name = &pkix.Name{}
	}
	switch {
	case address == "" && name.CommonName == "":
		return nil, errors.New("must set either \"address\" or \"name.CommonName\"")
	case address != "" && name.CommonName == "":
		name.CommonName = address
	case address != "" && name.CommonName != "" && name.CommonName != address:
		return nil, fmt.Errorf("set address to \"%s\" but name.CommonName to \"%s\"", address, name.CommonName)
	default:
		// name.CommonName is already valid--nothing to do
	}

	// Parse IPs in ipAddresses
	parsedIPs := []net.IP{}
	for _, strIP := range ipAddresses {
		nextParsedIP := net.ParseIP(strIP)
		if nextParsedIP == nil {
			return nil, fmt.Errorf("invalid IP: %s", strIP)
		}
		parsedIPs = append(parsedIPs, nextParsedIP)
	}
	// Generate key pair. According to
	// https://security.stackexchange.com/questions/5096/rsa-vs-dsa-for-ssh-authentication-keys
	// RSA is likely to be faster and more secure in practice than DSA/ECDSA, so
	// this only generates RSA keys
	key, err := rsa.GenerateKey(rand.Reader, rsaKeySize)
	if err != nil {
		return nil, fmt.Errorf("could not generate RSA private key: %v", err)
	}

	// Generate unsigned cert
	cert := x509.Certificate{
		// the x509 spec requires every x509 cert must have a serial number that is
		// unique for the signing CA. All of the certs generated by this package
		// are self-signed, so this just starts at 1 and counts up
		SerialNumber: big.NewInt(atomic.AddInt64(&serialNumber, 1)),
		Subject:      *name,
		NotBefore:    time.Now().Add(-1 * time.Second),
		NotAfter:     time.Now().Add(validDur),

		KeyUsage: x509.KeyUsageCertSign | // can sign certs (need for self-signing)
			x509.KeyUsageKeyEncipherment | // can encrypt other keys (need for TLS in symmetric mode)
			x509.KeyUsageKeyAgreement, // can establish keys (need for TLS in Diffie-Hellman mode)
		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, // can authenticate server (for TLS)

		IsCA:                  true, // must be set b/c KeyUsageCertSign is set
		BasicConstraintsValid: true, // mark "Basic Constraints" extn critical(?)
		MaxPathLenZero:        true, // must directly sign all end entity certs
		IPAddresses:           parsedIPs,
		DNSNames:              []string{address},
	}

	// Sign 'cert' (cert is both 'template' and 'parent' b/c it's self-signed)
	signedCertDER, err := x509.CreateCertificate(rand.Reader, &cert, &cert, &key.PublicKey, key)
	if err != nil {
		return nil, fmt.Errorf("could not self-sign certificate: %v", err)
	}
	signedCert, err := x509.ParseCertificate(signedCertDER)
	if err != nil {
		return nil, fmt.Errorf("could not parse the just-generated signed certificate: %v", err)
	}
	return &tls.Certificate{
		Certificate: [][]byte{signedCertDER},
		Leaf:        signedCert,
		PrivateKey:  key,
	}, nil
}
func GenerateSelfSignedCert(address string, name *pkix.Name, ipAddresses ...string) (*tls.Certificate, error) {
	// Generate Subject Distinguished Name
	if name == nil {
		name = &pkix.Name{}
	}
	switch {
	case address == "" && name.CommonName == "":
		return nil, errors.New("must set either \"address\" or \"name.CommonName\"")
	case address != "" && name.CommonName == "":
		name.CommonName = address
	case address != "" && name.CommonName != "" && name.CommonName != address:
		return nil, fmt.Errorf("set address to \"%s\" but name.CommonName to \"%s\"", address, name.CommonName)
	default:
		// name.CommonName is already valid--nothing to do
	}

	// Parse IPs in ipAddresses
	parsedIPs := []net.IP{}
	for _, strIP := range ipAddresses {
		nextParsedIP := net.ParseIP(strIP)
		if nextParsedIP == nil {
			return nil, fmt.Errorf("invalid IP: %s", strIP)
		}
		parsedIPs = append(parsedIPs, nextParsedIP)
	}
	// Generate key pair. According to
	// https://security.stackexchange.com/questions/5096/rsa-vs-dsa-for-ssh-authentication-keys
	// RSA is likely to be faster and more secure in practice than DSA/ECDSA, so
	// this only generates RSA keys
	key, err := rsa.GenerateKey(rand.Reader, rsaKeySize)
	if err != nil {
		return nil, fmt.Errorf("could not generate RSA private key: %v", err)
	}

	// Generate unsigned cert
	cert := x509.Certificate{
		// the x509 spec requires every x509 cert must have a serial number that is
		// unique for the signing CA. All of the certs generated by this package
		// are self-signed, so this just starts at 1 and counts up
		SerialNumber: big.NewInt(atomic.AddInt64(&serialNumber, 1)),
		Subject:      *name,
		NotBefore:    time.Now().Add(-1 * time.Second),
		NotAfter:     time.Now().Add(validDur),

		KeyUsage: x509.KeyUsageCertSign | // can sign certs (need for self-signing)
			x509.KeyUsageKeyEncipherment | // can encrypt other keys (need for TLS in symmetric mode)
			x509.KeyUsageKeyAgreement, // can establish keys (need for TLS in Diffie-Hellman mode)
		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, // can authenticate server (for TLS)

		IsCA:                  true, // must be set b/c KeyUsageCertSign is set
		BasicConstraintsValid: true, // mark "Basic Constraints" extn critical(?)
		MaxPathLenZero:        true, // must directly sign all end entity certs
		IPAddresses:           parsedIPs,
		DNSNames:              []string{address},
	}

	// Sign 'cert' (cert is both 'template' and 'parent' b/c it's self-signed)
	signedCertDER, err := x509.CreateCertificate(rand.Reader, &cert, &cert, &key.PublicKey, key)
	if err != nil {
		return nil, fmt.Errorf("could not self-sign certificate: %v", err)
	}
	signedCert, err := x509.ParseCertificate(signedCertDER)
	if err != nil {
		return nil, fmt.Errorf("could not parse the just-generated signed certificate: %v", err)
	}
	return &tls.Certificate{
		Certificate: [][]byte{signedCertDER},
		Leaf:        signedCert,
		PrivateKey:  key,
	}, nil
}
// GenerateSelfSignedCert generates a self-signed TLS cert for the domain name
// 'address', with a private key. Other attributes of the subject can be set in
// 'name' and ip addresses can be set in 'ipAddresses'