package config import ( "context" "crypto/sha256" "crypto/tls" "crypto/x509" "fmt" "slices" "time" "forge.cadoles.com/arcad/arcast/pkg/network" "forge.cadoles.com/arcad/arcast/pkg/selfsigned" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) func GenerateSelfSignedCert(ctx context.Context, filename string, conf *Config) error { if !conf.HTTPS.SelfSigned.Enabled { return nil } if conf.HTTPS.Cert != nil && conf.HTTPS.Key != nil { return nil } rawCert, rawKey, err := selfsigned.NewLANKeyPair() if err != nil { return errors.Wrap(err, "could not generate self signed x509 key pair") } conf.HTTPS.Cert = rawCert conf.HTTPS.Key = rawKey networkFingerprint, err := getNetworkFingerprint() if err != nil { return errors.Wrap(err, "could not retrieve network fingerprint") } conf.HTTPS.SelfSigned.NetworkFingerprint = networkFingerprint return nil } func RenewExpiredSelfSignedCert(ctx context.Context, filename string, conf *Config) error { if !conf.HTTPS.SelfSigned.Enabled { return nil } if conf.HTTPS.Cert == nil || conf.HTTPS.Key == nil { if err := GenerateSelfSignedCert(ctx, filename, conf); err != nil { return errors.WithStack(err) } } cert, err := tls.X509KeyPair(conf.HTTPS.Cert, conf.HTTPS.Key) if err != nil { return errors.Wrap(err, "could not parse x509 cert/key pair") } leaf, err := x509.ParseCertificate(cert.Certificate[0]) if err != nil { logger.Error(ctx, "could not parse x509 certificate, regenerating one", logger.CapturedE(errors.WithStack(err))) if err := GenerateSelfSignedCert(ctx, filename, conf); err != nil { return errors.WithStack(err) } } // Check that self-signed certificate is still valid if time.Now().Before(leaf.NotAfter) { return nil } logger.Warn(ctx, "self-signed certificate has expired, regenerating one", logger.CapturedE(errors.WithStack(err))) if err := GenerateSelfSignedCert(ctx, filename, conf); err != nil { return errors.WithStack(err) } return nil } func getNetworkFingerprint() (string, error) { ips, err := network.GetLANIPv4Addrs() if err != nil { return "", errors.WithStack(err) } slices.Sort(ips) hash := sha256.New() for _, ip := range ips { if _, err := hash.Write([]byte(ip)); err != nil { return "", errors.WithStack(err) } } return fmt.Sprintf("%x", hash.Sum(nil)), nil }