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.")
|
||||
}
|
||||
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