File builder
* Code that will build a certificate file from its configuration * Run it on all configured files from main
This commit is contained in:
parent
0e642c85a6
commit
a651e408ed
2 changed files with 192 additions and 0 deletions
177
buildcert.go
Normal file
177
buildcert.go
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Max supported CA chain length
|
||||||
|
const MAX_CA_CHAIN_LENGTH = 8
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Certificate building, including the configuration, LDAP connection,
|
||||||
|
// and the array of chunks that's being built.
|
||||||
|
tCertificateBuilder struct {
|
||||||
|
config *tCertificateFileConfig
|
||||||
|
conn *tLdapConn
|
||||||
|
data [][]byte
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Initialize a certificate file building using a LDAP connection and
|
||||||
|
// certificate file configuration.
|
||||||
|
func NewCertificateBuilder(conn *tLdapConn, config *tCertificateFileConfig) tCertificateBuilder {
|
||||||
|
return tCertificateBuilder{
|
||||||
|
config: config,
|
||||||
|
conn: conn,
|
||||||
|
data: make([][]byte, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the certificate file's data, returning any error that occurs while
|
||||||
|
// reading the source data.
|
||||||
|
func (b *tCertificateBuilder) Build() error {
|
||||||
|
err := b.appendPemFiles(b.config.PrependFiles)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = b.appendCertificate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = b.appendCaCertificates()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = b.appendPemFiles(b.config.AppendFiles)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if b.config.Reverse {
|
||||||
|
b.reverseChunks()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append PEM files from a list.
|
||||||
|
func (b *tCertificateBuilder) appendPemFiles(files []string) error {
|
||||||
|
for _, path := range files {
|
||||||
|
var err error
|
||||||
|
err = b.appendPem(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append a PEM file to the current list of data chunks
|
||||||
|
func (b *tCertificateBuilder) appendPem(input string) error {
|
||||||
|
data, err := ioutil.ReadFile(input)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Could not load '%s': %w", input, err)
|
||||||
|
}
|
||||||
|
rest := data
|
||||||
|
hadBlock := false
|
||||||
|
for {
|
||||||
|
var block *pem.Block
|
||||||
|
block, rest = pem.Decode(rest)
|
||||||
|
if block == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
hadBlock = true
|
||||||
|
b.data = append(b.data, pem.EncodeToMemory(block))
|
||||||
|
}
|
||||||
|
if hadBlock {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("No PEM blocks found in '%s'", input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the main, end-entity certificate from the LDAP
|
||||||
|
func (b *tCertificateBuilder) appendCertificate() error {
|
||||||
|
if b.config.Certificate != "" {
|
||||||
|
dn := b.conn.Config.Structure.BaseDN
|
||||||
|
if dn != "" {
|
||||||
|
dn = "," + dn
|
||||||
|
}
|
||||||
|
dn = b.config.Certificate + dn
|
||||||
|
data, err := b.conn.getEndEntityCertificate(dn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.data = append(b.data, data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append all CA certificates, reading the list from the LDAP or from the
|
||||||
|
// configuration.
|
||||||
|
func (b *tCertificateBuilder) appendCaCertificates() error {
|
||||||
|
if len(b.config.CACertificates) != 0 {
|
||||||
|
return b.appendListedCaCerts()
|
||||||
|
} else if b.config.CAChainOf != "" {
|
||||||
|
return b.appendChainedCaCerts()
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append CA certificates based on a list of DNs
|
||||||
|
func (b *tCertificateBuilder) appendListedCaCerts() error {
|
||||||
|
bdn := b.conn.Config.Structure.BaseDN
|
||||||
|
if bdn != "" {
|
||||||
|
bdn = "," + bdn
|
||||||
|
}
|
||||||
|
for _, dn := range b.config.CACertificates {
|
||||||
|
data, _, err := b.conn.getCaCertificate(dn + bdn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if data == nil {
|
||||||
|
return fmt.Errorf("No CA certificate at DN '%s'", dn)
|
||||||
|
}
|
||||||
|
b.data = append(b.data, data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append CA certificates by following a chain starting at some DN
|
||||||
|
func (b *tCertificateBuilder) appendChainedCaCerts() error {
|
||||||
|
nFound := 0
|
||||||
|
dn := b.config.CAChainOf
|
||||||
|
if b.conn.Config.Structure.BaseDN != "" {
|
||||||
|
dn = dn + "," + b.conn.Config.Structure.BaseDN
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
data, nextDn, err := b.conn.getCaCertificate(dn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if nFound != 0 {
|
||||||
|
if data == nil {
|
||||||
|
return fmt.Errorf("No CA certificate at DN '%s'", dn)
|
||||||
|
}
|
||||||
|
b.data = append(b.data, data)
|
||||||
|
}
|
||||||
|
if nextDn == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dn = nextDn
|
||||||
|
nFound += 1
|
||||||
|
if nFound == MAX_CA_CHAIN_LENGTH {
|
||||||
|
return fmt.Errorf("DN '%s': CA chain length exceeded", dn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the chunks in the list
|
||||||
|
func (b *tCertificateBuilder) reverseChunks() {
|
||||||
|
l := len(b.data) / 2
|
||||||
|
for i := 0; i < l/2; i++ {
|
||||||
|
j := l - i - 1
|
||||||
|
b.data[i], b.data[j] = b.data[j], b.data[i]
|
||||||
|
}
|
||||||
|
}
|
15
main.go
15
main.go
|
@ -70,4 +70,19 @@ func main() {
|
||||||
log.WithField("error", err).Fatal("Failed to initialize socket.")
|
log.WithField("error", err).Fatal("Failed to initialize socket.")
|
||||||
}
|
}
|
||||||
listener.Close()
|
listener.Close()
|
||||||
|
|
||||||
|
conn := getLdapConnection(cfg.LdapConfig)
|
||||||
|
if conn == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.close()
|
||||||
|
for i := range cfg.Certificates {
|
||||||
|
builder := NewCertificateBuilder(conn, &cfg.Certificates[i])
|
||||||
|
err := builder.Build()
|
||||||
|
if err != nil {
|
||||||
|
log.WithField("error", err).Error("Failed to build data for certificate '", cfg.Certificates[i].Path)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// FIXME: check existing file, try to write
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue