shared

package
v0.0.0-...-6352a9e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 10, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package shared provides common utility functions and types used across the cert-auth command-line application for managing a certificate authority. It wraps OpenSSL operations to create, sign, and revoke X.509 certificates, manage private keys, load certificate databases, and handle interactive password prompts.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApproveCertificate

func ApproveCertificate(id string, certType CertificateType, days int) error

ApproveCertificate signs a pending certificate signing request (CSR) using the local certificate authority configuration. It locates the CSR file at csr/<id>.csr, prompts the operator for the CA private key password, and invokes OpenSSL in batch mode with the appropriate extensions for the given certType ("server" or "client") and the requested validity period in days.

The CA configuration is read from ca.cnf in the current working directory. The corresponding OpenSSL extension section used is "<certType>_ext".

func AskPassword

func AskPassword(filePath string) (string, error)

AskPassword prompts the user to enter a pass phrase for the file at the given filePath, resolved relative to the current working directory. Input is read securely without echo using the terminal raw mode. Returns the entered password as a string, or an error if reading fails.

func AskPrivateKeyPassword

func AskPrivateKeyPassword() (string, error)

AskPrivateKeyPassword prompts the user for the password of the CA's private key file located at "private/ca.key". It delegates to AskPassword with the constructed file path. Returns the entered password or an error if the prompt fails.

func EnableOCSP

func EnableOCSP(password string) error

EnableOCSP initializes OCSP support for the current certificate authority. It generates an ocsp.cnf configuration file populated with the authority's country, organization, and common name, then creates a new OCSP private key, certificate signing request, and OCSP certificate signed by the CA. If password is empty, the user is prompted interactively for the CA private key password. Returns an error if OCSP is already enabled (ocsp.cnf exists), the settings cannot be loaded, the password prompt fails, the configuration file cannot be written, or any key/certificate generation step fails.

func EnableTimestamp

func EnableTimestamp(password string) error

EnableTimestamp initializes timestamp authority (TSA) support for the current certificate authority. It generates a timestamp.cnf configuration file populated with the authority's country, organization, and common name (suffixed with "Timestamp Authority"), then creates a new timestamp private key, certificate signing request, and TSA certificate signed by the CA. If password is empty, the user is prompted interactively for the CA private key password. Returns an error if timestamping is already enabled (timestamp.cnf exists), the settings cannot be loaded, the password prompt fails, the configuration file cannot be written, or any key/certificate generation step fails.

func ImportRequest

func ImportRequest(filePath string) (string, error)

ImportRequest validates and imports a certificate signing request (CSR) from the given filePath into the authority's csr/ directory. The file must exist and contain a CSR with a valid self-signature. On success, the CSR is copied into the csr/ directory with a randomly generated 15-character ID as its filename (e.g. "csr/a3f9c2d1b8e2f4a.csr") and that ID is returned. Returns an error if the file does not exist, cannot be parsed, has an invalid signature, or cannot be copied.

func ImportSubordinate

func ImportSubordinate(filePath, pass string) (string, string, error)

ImportSubordinate imports and signs a subordinate certificate authority's certificate signing request (CSR) from the given filePath using the provided CA private key password. The CSR is imported via ImportRequest, then signed via SignRequest with a validity period of 1825 days (5 years). On success, the serial number is extracted from the resulting certificate using OpenSSL and returned alongside the generated certificate ID. Returns an error if the import, signing, or serial extraction fails.

func IsCertificateAuthority

func IsCertificateAuthority() error

IsCertificateAuthority checks whether the current working directory contains a certificate authority by verifying the presence of a ca.yml configuration file. Returns an error if the file does not exist.

func IsRootCertificateAuthority

func IsRootCertificateAuthority() error

IsRootCertificateAuthority checks whether the current working directory is a root certificate authority. It first verifies the presence of a ca.yml file via IsCertificateAuthority, then loads the authority settings and checks that the authority type is RootAuthority. Returns an error if the directory is not a certificate authority, the settings cannot be loaded, or the authority type is not RootAuthority.

func NewCertificate

func NewCertificate(data RequestData, days int) (string, error)

NewCertificate creates a new certificate end-to-end by generating a private key, a certificate signing request (CSR), and a signed certificate, all identified by a randomly generated 15-character ID. The process is:

  1. Generate a 15-character random ID.
  2. Prompt the user for a pass phrase for the new private key (stored at "private/<id>.key").
  3. Generate a new private key of DefaultKeyType at the key path.
  4. Generate a CSR at "csr/<id>.csr" using the key and the provided RequestData.
  5. Sign the CSR via ApproveCertificate using the certificate type from RequestData and the given validity period in days.

Returns the generated ID on success, or an error if any step fails.

func NewPrivateKey

func NewPrivateKey(filePath string, keyType KeyType, pass string) error

NewPrivateKey generates a new encrypted private key at filePath using the specified keyType algorithm. If pass is empty the operator is interactively prompted for a passphrase via AskPassword.

func NewRequest

func NewRequest(requestFile, keyFile, pass string, data RequestData) error

NewRequest creates an OpenSSL CSR configuration file (<requestFile>.cnf) and then generates the corresponding certificate signing request (<requestFile>.csr) for the given RequestData.

func RandomID

func RandomID(length int) (string, error)

RandomID generates a cryptographically random hex-encoded string by reading the specified number of random bytes from crypto/rand and encoding them as hexadecimal. The returned string will be twice the length of the requested byte count (e.g. a length of 15 produces a 30-character hex string). Returns an error if the random byte generation fails.

func ReplaceOCSP

func ReplaceOCSP(reason RevokeType) error

ReplaceOCSP revokes the existing OCSP responder certificate and issues a new one. The revocation reason must be either Superseded or KeyCompromise; any other reason is rejected. The current OCSP certificate ("cert/ocsp.pem") and private key ("private/ocsp.key") are removed after revocation, the CRL is updated, and a new OCSP key, CSR, and certificate are generated. Returns an error if OCSP is not enabled in the authority settings, the reason is not permitted, the OCSP certificate is missing, the CA private key password prompt fails, or any revocation, removal, CRL update, or generation step fails.

func ReplaceTimestamp

func ReplaceTimestamp() error

ReplaceTimestamp replaces the existing timestamp authority (TSA) certificate and private key with newly generated ones. The current certificate ("cert/timestamp.pem") and private key ("private/timestamp.key") are removed before a new key, CSR, and certificate are generated. Unlike ReplaceOCSP, the old certificate is not formally revoked via OpenSSL before removal. Returns an error if timestamp is not enabled in the authority settings, the timestamp certificate is missing, the CA private key password prompt fails, or any removal or generation step fails.

func RequestSubject

func RequestSubject(data RequestData) []byte

RequestSubject builds the [req_subj] section of an OpenSSL configuration file from the given RequestData and returns it as a byte slice. The country and organization are always included. State, locality, and organizational unit are only written when their respective fields are non-empty. The common name is always written last using the Name field.

func RevokeCertificate

func RevokeCertificate(filePath string, reason RevokeType) error

RevokeCertificate revokes the X.509 certificate at the given file path using OpenSSL with the ca.cnf configuration and the specified revocation reason. It prompts the user interactively for the CA private key password. After successful revocation, the certificate file is renamed with a ".revoked" suffix. Returns an error if the file does not exist, the password prompt fails, or the OpenSSL command fails.

func SaveSettings

func SaveSettings(authority *Authority) error

SaveSettings persists the provided Authority configuration to the ca.yml file in the current working directory and updates the cached instance. Returns an error if authority is nil or if the file cannot be written.

func SaveSubordinateSettings

func SaveSubordinateSettings(subordinate Authority) error

SaveSubordinateSettings writes the given subordinate Authority configuration as a ca.yml file under a subdirectory named after the subordinate. If the subordinate name matches the current directory name, it writes ca.yml directly into the current directory. Returns an error if the file already exists or if marshalling the YAML fails.

func ShowCertificate

func ShowCertificate(id string, revoked bool) error

ShowCertificate displays certificate information from the current authority. If id is non-empty, the corresponding PEM file is located at "certs/<id>.pem" (or "certs/<id>.pem.revoked" if revoked is true) and its full text representation is printed to stdout via OpenSSL. If id is empty, the certificate database is loaded via LoadCertificateDB and printed to stdout as indented JSON. Returns an error if the certificate file does not exist, the OpenSSL command fails, the database cannot be loaded, or the JSON marshalling fails.

func ShowRequest

func ShowRequest(id string) error

ShowRequest displays certificate signing request (CSR) information from the current authority. If id is non-empty, the corresponding CSR file is located at "csr/<id>.csr" and its full text representation is printed to stdout via OpenSSL, including signature verification. Returns an error if the CSR file does not exist, the OpenSSL command fails, any individual request cannot be loaded, or the JSON marshalling fails.

func SignRequest

func SignRequest(id, pass string, days int) error

SignRequest signs the CSR identified by id using the CA configured in ca.cnf and writes the resulting certificate to "certs/<id>.pem". The CSR is read from "csr/<id>.csr". The subca_ext extensions are applied and the certificate is valid for the given number of days. If pass is empty, the user is prompted interactively for the CA private key password. The OpenSSL ca command is run in batch (non-interactive) mode. Returns an error if the password prompt fails or the OpenSSL command fails.

func SubjectAlternativeName

func SubjectAlternativeName(name string, additionalNames []string) []byte

SubjectAlternativeName builds the [server_req] and [san_list] sections of an OpenSSL configuration file for a server certificate's Subject Alternative Names (SANs) and returns the result as a byte slice. The primary name is always added as a DNS SAN. Each entry in additionalNames is classified by type using regular expressions and added to the appropriate SAN category:

  • URI: matches entries containing "://" (e.g. "https://example.com").
  • Email: matches entries containing "@" (e.g. "user@example.com").
  • IP: matches IPv4 addresses (e.g. "192.168.1.1") or uppercase IPv6 addresses (e.g. "2001:DB8::1").
  • DNS: all remaining entries, excluding duplicates of the primary name.

Entries in each category are written in OpenSSL indexed format (e.g. "DNS.0", "DNS.1"). The order of categories in the output is URI, DNS, IP, then email.

func SubordinateExists

func SubordinateExists(name string) (bool, error)

SubordinateExists reports whether a subordinate CA with the given name is registered with the current root certificate authority. It first verifies that the current directory is a certificate authority and specifically a root authority, then searches the authority's Subordinates list for a matching name. Returns false and an error if the current directory is not a certificate authority, is not a root authority, or the settings cannot be loaded. Returns true and nil if a matching subordinate is found, or false and nil if it is not.

func UpdateAuthority

func UpdateAuthority(password string) error

UpdateAuthority updates the certificate authority database by running the OpenSSL ca -updatedb command using the ca.cnf configuration. This marks any expired certificates in the database as expired. If password is empty, the user is prompted interactively for the CA private key password. Returns an error if the password prompt fails or the OpenSSL command fails.

func UpdateCRL

func UpdateCRL(password string) error

UpdateCRL regenerates the certificate revocation list (CRL) for the current authority using the OpenSSL ca -gencrl command and writes it to "ca.crl", using the ca.cnf configuration. If password is empty, the user is prompted interactively for the CA private key password. Returns an error if the password prompt fails or the OpenSSL command fails.

func ValidateCertificate

func ValidateCertificate(path string, bundle bool) error

ValidateCertificate verifies a certificate at the given path against a CA chain file using OpenSSL. The certificate file must exist. If bundle is false, the CA file used is "certs/ca-chain.pem" if it exists, falling back to "certs/ca.pem". If bundle is true, Mozilla's root CA bundle is downloaded from https://curl.se/ca/cacert.pem, saved to "certs/ca-bundle.pem", and used as the CA file. Returns an error if the certificate file does not exist, the CA bundle download or write fails, or the OpenSSL verify command fails.

func ValidateSubordinate

func ValidateSubordinate(id string, name string) error

ValidateSubordinate verifies that the subordinate CA identified by name has a serial number matching the given id. It loads the subordinate's Authority configuration from its subdirectory via LoadSubordinate and compares the stored serial against id. Returns nil if they match, or an error if the subordinate's directory does not exist, the configuration cannot be loaded, or the serial number does not match.

Types

type Authority

type Authority struct {
	// Type indicates whether this authority is a root, subordinate, or imported CA.
	Type AuthorityType `yaml:"type"`

	// Public indicates whether the CA is publicly accessible (e.g., CRL/OCSP URLs are public).
	Public bool `yaml:"public_access"`

	// Name is the short filesystem-friendly identifier for the authority directory.
	Name string `yaml:"authority_name"`

	// Domain is the DNS domain associated with the certificate authority.
	Domain string `yaml:"domain"`

	// Country is the two-letter ISO country code used in certificate subjects.
	Country string `yaml:"country"`

	// Organization is the organization name used in certificate subjects.
	Organization string `yaml:"organization"`

	// CommonName is the common name (CN) used in the CA certificate subject.
	CommonName string `yaml:"common_name"`

	// OCSP indicates whether an OCSP responder is configured for this authority.
	OCSP bool `yaml:"ocsp"`

	// TimeStamp indicates whether a timestamping certificates is configured for this authority.
	TimeStamp bool `yaml:"timestamp"`

	// Serial is the hexadecimal number used to identify the authority.
	Serial string `yaml:"serial"`

	// Subordinates is the list of subordinate CAs managed under this root authority.
	Subordinates []Subordinate `yaml:"subordinates"`
}

Authority represents the configuration and identity of a certificate authority. It is serialized to and deserialized from a YAML configuration file (ca.yml) and describes whether the CA is a root, subordinate, or imported authority, along with its organizational identity, optional services (OCSP, timestamp), and any known subordinate CAs.

func GetSettings

func GetSettings() (Authority, error)

GetSettings loads and returns the Authority configuration from the ca.yml file in the current working directory. The settings are loaded once and cached for subsequent calls. Returns an error if the file cannot be read or parsed.

func LoadSubordinate

func LoadSubordinate(name string) (*Authority, error)

LoadSubordinate loads and returns the Authority configuration for the named subordinate CA. It first verifies that the named subordinate is registered with the current authority via SubordinateExists, then reads and unmarshals the ca.yml file from the subordinate's subdirectory. Returns an error if the subordinate is not registered, its directory does not exist, the ca.yml file is missing or unreadable, or the YAML cannot be unmarshalled.

type AuthorityType

type AuthorityType string

AuthorityType represents the role of a certificate authority within the PKI hierarchy. Valid values are "root", "subordinate", and "imported".

const (
	// RootAuthority indicates the CA is a self-signed root certificate authority.
	RootAuthority AuthorityType = "root"

	// SubordinateAuthority indicates the CA is an intermediate CA signed by a root CA.
	SubordinateAuthority AuthorityType = "subordinate"

	// ImportedAuthority indicates the CA was imported from an external source
	// rather than created locally.
	ImportedAuthority AuthorityType = "imported"
)

func (*AuthorityType) Set

func (e *AuthorityType) Set(v string) error

Set validates and assigns a CertificateType from a string value. Accepted values are "root", "subordinate", and "imported". Any other value returns an error. It satisfies the pflag.Value interface.

func (*AuthorityType) String

func (e *AuthorityType) String() string

String returns the string representation of the AuthorityType. It satisfies the fmt.Stringer and pflag.Value interfaces.

func (*AuthorityType) Type

func (e *AuthorityType) Type() string

Type returns the type name used in pflag usage messages. It satisfies the pflag.Value interface.

type CertificateData

type CertificateData struct {
	// SerialNumber is the unique hexadecimal serial number of the certificate.
	SerialNumber string

	// DistinguishedName is the full subject DN string from the certificate.
	DistinguishedName string

	// Status is the human-readable validity state of the certificate:
	// "Valid", "Expired", "Revoked", or "Unknown".
	Status string

	// ExpirationDate is the date and time at which the certificate expires.
	ExpirationDate time.Time

	// RevocationDate is the date and time the certificate was revoked,
	// if applicable.
	RevocationDate time.Time

	// RevocationReason is the reason string provided when the certificate
	// was revoked, if applicable.
	RevocationReason RevokeType
}

CertificateData holds the parsed fields from a single certificate entry, including the serial number, subject distinguished name, validity period, and current revocation status.

func LoadCertificateDB

func LoadCertificateDB(revoked bool) ([]CertificateData, error)

LoadCertificateDB reads and parses the OpenSSL certificate index file located at db/index and returns a slice of CertificateData entries.

type CertificateRequest

type CertificateRequest struct {
	// Name is the filename or identifier associated with the CSR.
	Name string

	// Subject is the distinguished name (DN) of the entity requesting the
	// certificate, typically in the form "CN=..., O=..., C=...".
	Subject string

	// Version is the version number of the CSR (typically 0 for PKCS#10).
	Version int

	// PublicKeyAlgorithm is the algorithm used for the CSR's public key,
	// e.g. "RSA", "ECDSA", or "Ed25519".
	PublicKeyAlgorithm string

	// SignatureAlgorithm is the algorithm used to sign the CSR,
	// e.g. "SHA256-RSA" or "ECDSA-SHA384".
	SignatureAlgorithm string

	// SignatureValid reports whether the CSR's self-signature has been
	// successfully verified.
	SignatureValid bool
}

CertificateRequest holds the parsed fields from an X.509 certificate signing request (CSR), including the subject identity, version, cryptographic algorithms used, and whether the request's signature has been verified.

func LoadRequest

func LoadRequest(filePath string) (CertificateRequest, error)

LoadRequest parses a PEM-encoded certificate signing request (CSR) at the given filePath using OpenSSL and returns a CertificateRequest populated with the extracted fields. The following fields are extracted from the OpenSSL text output via regular expressions:

  • Version: the PKCS#10 version number.
  • Subject: the distinguished name (DN), with whitespace trimmed.
  • PublicKeyAlgorithm: the public key algorithm, e.g. "rsaEncryption" or "id-ecPublicKey".
  • SignatureAlgorithm: the signature algorithm, e.g. "ecdsa-with-SHA256".
  • SignatureValid: true if OpenSSL reports "self-signature verify OK".
  • Name: the value of the last RDN component of the subject (e.g. the CN value).

Returns an empty CertificateRequest and an error if OpenSSL fails, any regex fails to compile, or the expected fields are not found in the output.

type CertificateType

type CertificateType string

CertificateType represents the intended purpose or profile of an X.509 certificate. It determines which OpenSSL extensions and key usages are applied during issuance.

const (
	// CertificateTypeServer represents a certificate intended for TLS server authentication.
	CertificateTypeServer CertificateType = "server"

	// CertificateTypeClient represents a certificate intended for client authentication.
	CertificateTypeClient CertificateType = "client"
)

func (*CertificateType) Set

func (e *CertificateType) Set(v string) error

Set validates and assigns a CertificateType from a string value. Accepted values are "server" and "client". Any other value returns an error. It satisfies the pflag.Value interface.

func (*CertificateType) String

func (e *CertificateType) String() string

String returns the string representation of the CertificateType. It satisfies the fmt.Stringer and pflag.Value interfaces.

func (*CertificateType) Type

func (e *CertificateType) Type() string

Type returns the type name used in pflag usage messages. It satisfies the pflag.Value interface.

type KeyType

type KeyType string

KeyType represents the cryptographic algorithm used when generating a private key.

const (
	// DefaultKeyType is the key type used when none is explicitly specified.
	// It is set to Elliptic (EC secp521r1).
	DefaultKeyType KeyType = Elliptic

	// Edwards generates an Ed25519 private key encrypted with AES-256-CFB.
	Edwards KeyType = "edwards"

	// Elliptic generates an EC private key using the secp521r1 curve,
	// encrypted with AES-256-CFB.
	Elliptic KeyType = "elliptic"

	// RSA generates an RSA private key using a configurable bit length.
	RSA KeyType = "rsa"
)

func (*KeyType) Set

func (e *KeyType) Set(v string) error

Set parses and assigns a KeyType from the provided string value. Returns an error if the value is not one of "edwards", "elliptic", or "rsa".

func (*KeyType) String

func (e *KeyType) String() string

String returns the string representation of the KeyType value.

func (*KeyType) Type

func (e *KeyType) Type() string

Type returns the type name "KeyType", used for pflag/cobra flag registration.

type RequestData

type RequestData struct {
	// Name is the primary subject name. For client certificates this becomes
	// the email address (SAN/CN); for server certificates it is the primary DNS name.
	Name string

	// Country is the two-letter ISO 3166-1 country code for the subject.
	// If empty, the value from the application settings is used.
	Country string

	// State is the state or province name (ST) for the certificate subject.
	State string

	// Locality is the locality or city name (L) for the certificate subject.
	Locality string

	// Organization is the O field of the subject DN.
	// If empty, the value from the application settings is used.
	Organization string

	// OrganizationalUnit is the organizational unit (OU) for the certificate subject.
	OrganizationalUnit string

	// AdditionalNames lists extra Subject Alternative Names (SANs) to include
	// in a server certificate request.
	AdditionalNames []string

	// RequestType distinguishes the intended usage of the certificate
	// (e.g. CertificateTypeServer or CertificateTypeClient).
	RequestType CertificateType
}

RequestData carries the subject and extension fields needed to generate an OpenSSL certificate signing request (CSR) configuration file.

type RevokeType

type RevokeType string

RevokeType represents the reason a certificate is being revoked, as defined by RFC 5280 CRL reason codes.

const (
	// Unspecified indicates no specific revocation reason was given.
	Unspecified RevokeType = "unspecified"

	// KeyCompromise indicates the private key associated with the certificate
	// has been compromised.
	KeyCompromise RevokeType = "keyCompromise"

	// CACompromise indicates the CA's private key has been compromised.
	CACompromise RevokeType = "CACompromise"

	// AffiliationChanged indicates the subject's affiliation has changed.
	AffiliationChanged RevokeType = "affiliationChanged"

	// Superseded indicates the certificate has been replaced by a new one.
	Superseded RevokeType = "superseded"

	// CessationOfOperation indicates the subject no longer operates the service
	// for which the certificate was issued.
	CessationOfOperation RevokeType = "cessationOfOperation"

	// CertificateHold indicates the certificate is temporarily suspended.
	CertificateHold RevokeType = "certificateHold"

	// RemoveFromCRL indicates a previously held certificate should be reinstated.
	RemoveFromCRL RevokeType = "removeFromCRL"
)

func (*RevokeType) Set

func (e *RevokeType) Set(v string) error

Set validates and assigns a RevokeType from the provided string value. Returns an error if the value is not one of the recognized revocation reason strings.

func (*RevokeType) String

func (e *RevokeType) String() string

String returns the string representation of the RevokeType value.

func (*RevokeType) Type

func (e *RevokeType) Type() string

Type returns the type name "RevokeType", used by flag/cobra parsing.

type Subordinate

type Subordinate struct {
	// ID is the hexadecimal number used to identify the subordinate CA.
	ID string `yaml:"id"`

	// Name is the label of the subordinate CA.
	Name string `yaml:"name"`
}

Subordinate represents a reference to a subordinate certificate authority managed under a root CA. It is stored in the root CA's configuration file.

func AddSubordinate

func AddSubordinate(authority Authority, name, serial string) ([]Subordinate, error)

AddSubordinate appends a new Subordinate with the given name and serial to the authority's Subordinates list. If a subordinate with the same name already exists, it returns nil and an error. Returns the updated slice of Subordinates on success.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL