Can now generate TLS certificates

They do not yet have the host information yet and are not accepted by anyone
making them very useless
testing
Justin Reichardt 2022-08-20 17:28:11 -05:00
parent 7c56c5d5c7
commit ed9d23ceb9
3 changed files with 395 additions and 7 deletions

View File

@ -0,0 +1,233 @@
/*
Certutils manages certificates.
To Create a Certificate start with:
var ca CA
From there you will want to edit:
- Location
- Name
- X509Cert
- Signer (If it is suppose to be signed by another CA, you must add it before initializing)
Then initialize it:
ca.Initialize
Create the files:
ca.WriteToFile()
*/
package certutils
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"log"
"math/big"
"os"
"path"
)
// I want to give Shane Utt credit for being the example for how this module creates and signs certs
/*
* CA holds information regarding a key pair and certificate
*/
type CA struct {
Location string // Location is the location of the keys
Name string // This is the name of the certificate, it will append ".key" and ".crt" when writing them:w
TLSConf *tls.Config
CRTPEM []byte // This will hold the certificate pem byte file until it is writen to files
PrivKeyPEM []byte // This will hold the private key pem byte file until it is writen to files
X509Cert *x509.Certificate // Make sure to change this to match what you want your certificate to say
Signer *CA // Signer is the address of who you want to sign this key
keyPair *rsa.PrivateKey
}
// If a location is given it will check for one at the location first.
// If one does not exist it will create one using the provided certificate.
// If one does exist it will check it against the certificate and decided if a new one needs to be made.
// If a Certificate is not provided then the default template will be used.
// The name it looks for is "ca": ca.key, ca.crt if no name is provided
func (ca CA) Initialize() (CA, error) {
var err error
// Check for name
if ca.Name == "" {
ca.Name = "ca"
}
// Check if CA Exists
var caBuf CA
caBuf, err = fillFromFile(ca)
if err == nil {
ca = caBuf
} else {
log.Print(err)
// Check for certificate
if ca.X509Cert == nil {
return ca, errors.New("No x509 certificate provided")
}
// If CA does not exist then create one
ca, err = ca.Build()
if err != nil {
return ca, err
}
}
return ca, err
}
func fillFromFile(ca CA) (CA, error) {
var err error
file := path.Join(ca.Location + ca.Name)
_, err = os.Stat(file + ".crt")
if err != nil {
return ca, err
}
ca.CRTPEM, err = os.ReadFile(file + ".crt")
if err != nil {
return ca, err
}
_, err = os.Stat(file + ".key")
if err != nil {
return ca, err
}
ca.PrivKeyPEM, err = os.ReadFile(file + ".key")
if err != nil {
return ca, err
}
log.Print("Reading keys from file")
// Decode crt pem
var p *pem.Block
p, _ = pem.Decode(ca.CRTPEM)
if p == nil {
return ca, errors.New("Failed to parse: " + file + ".crt")
}
certBuf, err := x509.ParseCertificate(p.Bytes)
if err != nil {
return ca, err
}
// This is where it needs to check if they match, for now it will just assign it
ca.X509Cert = certBuf
// Decode key pem
p, _ = pem.Decode(ca.PrivKeyPEM)
if p == nil {
return ca, errors.New("Failed to parse: " + file + ".key")
}
ca.keyPair, err = x509.ParsePKCS1PrivateKey(p.Bytes)
if err != nil {
return ca, err
}
return ca, err
}
// WriteToFile will create a key and crt file using the Location and Name on the CA
func (ca CA) WriteToFile() (err error) {
var file string
file = path.Join(ca.Location, ca.Name+".crt")
log.Print("Creating: " + file)
err = os.WriteFile(file, ca.CRTPEM, 0660)
if err != nil {
return
}
file = path.Join(ca.Location, ca.Name+".key")
log.Print("Creating: " + file)
err = os.WriteFile(file, ca.PrivKeyPEM, 0660)
return
}
// This is run when initializing unless the files already exist. You can force the building process here afterwards if you want to use the current one's x509 certificate but regenerate everything else.
func (ca CA) Build() (CA, error) {
log.Print("Generating key" + ca.Name)
var err error
// Changing the default serial number
// For some reason it uses 2019 as the default, I need to watch this in the event it changes
if ca.X509Cert.SerialNumber.Cmp(big.NewInt(2019)) == 0 {
// generate a random serial number
// Later should modify this to use issuerDN+serial
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return ca, err
}
ca.X509Cert.SerialNumber = serialNumber
}
// create our private and public key
caKeyPair, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return ca, err
}
ca.keyPair = caKeyPair
if ca.Signer == nil {
ca.Signer = &ca
}
// create the CA
caBytes, err := x509.CreateCertificate(rand.Reader, ca.X509Cert, ca.Signer.X509Cert, &caKeyPair.PublicKey, ca.Signer.keyPair)
if err != nil {
return ca, err
}
// pem encode
crtPEM := new(bytes.Buffer)
pem.Encode(crtPEM, &pem.Block{
Type: "CERTIFICATE",
Bytes: caBytes,
})
privKeyPEM := new(bytes.Buffer)
pem.Encode(privKeyPEM, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(caKeyPair),
})
ca.CRTPEM = crtPEM.Bytes()
ca.PrivKeyPEM = privKeyPEM.Bytes()
return ca, err
}
func (ca CA) TlsConfigCreate() (*tls.Config, error) {
certpool := x509.NewCertPool()
if certpool.AppendCertsFromPEM(ca.CRTPEM) == false {
return nil, errors.New("Failed to AppendCertsFromPEM" + ca.Name)
}
TLSConf := &tls.Config{
RootCAs: certpool,
}
return TLSConf, nil
}

View File

@ -0,0 +1,79 @@
package certutils
import (
"testing"
"crypto/x509"
"crypto/x509/pkix"
"math/big"
"time"
"net"
)
// Parent template for all further certificates
var x509CATmpl = &x509.Certificate{
SerialNumber: big.NewInt(2019),
Subject: pkix.Name{
Organization: []string{"Master CA of Localhost"},
Country: []string{"XX"},
Province: []string{""},
Locality: []string{"Your computer"},
StreetAddress: []string{""},
PostalCode: []string{"5432"},
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
IsCA: true,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
}
var x509ServerTmpl = &x509.Certificate{
SerialNumber: big.NewInt(2019),
Subject: pkix.Name{
Organization: []string{"The Website"},
Country: []string{"US"},
Province: []string{""},
Locality: []string{"webserver"},
StreetAddress: []string{"bus 1"},
PostalCode: []string{"8"},
},
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
SubjectKeyId: []byte{1, 2, 3, 4, 6},
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature,
}
func TestWriteToFile (t *testing.T){
var ca, server CA
var err error
ca.Name = "TestCertificateAuthority"
ca.X509Cert = x509CATmpl
ca, err = ca.Initialize()
if (err != nil){
t.Error("Failed to genrate the TestCertificateAuthority certificate" + err.Error())
}
server.Name = "server"
server.X509Cert = x509ServerTmpl
server.Signer = &ca
server, err = server.Initialize()
if (err != nil){
t.Error("Failed to generate the server certificate" + err.Error())
}
err = ca.WriteToFile()
if (err != nil){
t.Error("Failed to write the TestCertificateAuthority files" + err.Error())
}
err = server.WriteToFile()
if (err != nil){
t.Error("Failed to write the sever portion" + err.Error())
}
}

View File

@ -2,9 +2,17 @@
package serve
import (
"crypto/x509"
"crypto/x509/pkix"
"net/http"
"jbreich/rhosts/serve/certutils"
"jbreich/rhosts/cfg"
"log"
"os"
"path"
"math/big"
"time"
"net"
)
func Start(exit chan bool) {
@ -14,17 +22,85 @@ func Start(exit chan bool) {
exit <- true
return
}
go httpServer()
go httpsServer(config.System.Var + "/certs/")
go httpsServer(path.Join(config.System.Var, "certs"))
}
func httpServer() (err error) {
err = http.ListenAndServe("127.0.0.1:80", http.HandlerFunc(httpHandler))
return
func httpServer(){
err := http.ListenAndServe("127.0.0.1:80", http.HandlerFunc(httpHandler))
if (err != nil) {log.Fatal("Failed to start httls server")}
}
func httpsServer(certLoc string) (err error) {
err = http.ListenAndServeTLS("127.0.0.1:80", certLoc+"ca.crt", certLoc+"ca.key", http.HandlerFunc(httpHandler))
func httpsServer(certPath string) {
var err error
// Create certificates if they do not exist
// CA
err = os.MkdirAll(certPath,0755)
if (err != nil){log.Fatal("Could not create cert path: " + err.Error())}
var ca certutils.CA
ca.Location = certPath
ca.Name = "ca"
ca.X509Cert = &x509.Certificate{
SerialNumber: big.NewInt(2019),
Subject: pkix.Name{
Organization: []string{"Rhost"},
Country: []string{""},
Province: []string{""},
Locality: []string{"Your computer"},
StreetAddress: []string{""},
PostalCode: []string{""},
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
IsCA: true,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
}
ca,err = ca.Initialize()
if(err!=nil){log.Fatal("Failed to build the ca: " + err.Error())}
err = ca.WriteToFile()
if(err!=nil){log.Fatal("Failed to write the ca: " + err.Error())}
// Server Certificate
var serverCa certutils.CA
serverCa.Location = certPath
serverCa.Name = "server"
serverCa.Signer = &ca
serverCa.X509Cert = &x509.Certificate{
SerialNumber: big.NewInt(2019),
Subject: pkix.Name{
Organization: []string{"The Website"},
Country: []string{"US"},
Province: []string{""},
Locality: []string{"webserver"},
StreetAddress: []string{""},
PostalCode: []string{""},
},
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
SubjectKeyId: []byte{1, 2, 3, 4, 6},
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature,
}
serverCa,err = serverCa.Initialize()
if(err!=nil){log.Fatal("Failed to build the server certificate: " + err.Error())}
serverCa.WriteToFile()
if(err!=nil){log.Fatal("Failed to write the server certificate: " + err.Error())}
// Starting the server
err = http.ListenAndServeTLS("127.0.0.1:443", path.Join(certPath, "server.crt"), path.Join(certPath, "server.key"), http.HandlerFunc(httpHandler))
if (err != nil) {log.Fatal("Failed to start httls server: " + err.Error())}
return
}