cert

package
v1.24.0 Latest Latest
Warning

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

Go to latest
Published: Mar 30, 2026 License: MIT Imports: 12 Imported by: 0

README ¶

cert/ - X.509 Certificate Management

Certificate creation, CA operations, and certificate chain management.

Test Coverage

Overview

X.509 certificate operations with support for:

  • Self-signed certificates
  • CA certificate hierarchies
  • Certificate signing (intermediate and end-entity)
  • Certificate chain verification
  • Subject Alternative Names (DNS, IP, Email)
  • OpenSSL certificate compatibility (100%)

🤖 AI Agent Quick Start

File Structure
cert/
├── cert.go          [Certificate creation and management]
├── ca.go            [Certificate Authority operations]
├── cert_test.go     [Certificate tests]
└── ca_test.go       [CA operation tests]
Key Functions
Function Purpose
CreateSelfSignedCertificate() Create self-signed certificate
CreateCACertificate() Create CA certificate with constraints
SignCertificate() Sign certificate with CA
VerifyCertificate() Verify certificate chain
Common Tasks

Creating CA Hierarchy:

  1. Create root CA with CreateCACertificate()
  2. Create intermediate CA signed by root
  3. Create end-entity certificate signed by intermediate
  4. Verify chain with VerifyCertificate()
Dependencies
  • keypair/ - Key pairs for certificate operations
  • crypto/x509 - Standard library X.509 support

Quick Start

import (
    "crypto/x509/pkix"
    "time"
    "github.com/jasoet/gopki/cert"
    "github.com/jasoet/gopki/keypair/algo"
)

// Create CA certificate
caKeys, _ := algo.GenerateRSAKeyPair(algo.KeySize4096)
caCert, _ := cert.CreateCACertificate(caKeys, cert.CertificateRequest{
    Subject: pkix.Name{CommonName: "My Root CA"},
    ValidFor: 10 * 365 * 24 * time.Hour,
    IsCA: true,
    MaxPathLen: 2,
})

// Create server certificate signed by CA
serverKeys, _ := algo.GenerateRSAKeyPair(algo.KeySize2048)
serverCert, _ := cert.SignCertificate(caCert, caKeys, cert.CertificateRequest{
    Subject: pkix.Name{CommonName: "server.example.com"},
    DNSNames: []string{"server.example.com", "www.example.com"},
    IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)},
    ValidFor: 365 * 24 * time.Hour,
}, serverKeys.PublicKey)

// Verify certificate chain
err := cert.VerifyCertificate(serverCert, caCert)

API Reference

Certificate Creation
// Self-signed certificate
func CreateSelfSignedCertificate[T keypair.KeyPair](keyPair T, request CertificateRequest) (*Certificate, error)

// CA certificate
func CreateCACertificate[T keypair.KeyPair](keyPair T, request CertificateRequest) (*Certificate, error)

// Sign certificate with CA
func SignCertificate[T keypair.KeyPair](caCert *Certificate, caKeyPair T, request CertificateRequest, publicKey crypto.PublicKey) (*Certificate, error)
Certificate Verification
// Verify certificate against CA
func VerifyCertificate(cert *Certificate, caCert *Certificate) error

// Verify certificate chain
func VerifyCertificateChain(cert *Certificate, intermediates []*Certificate, roots []*Certificate) error
Certificate Request
type CertificateRequest struct {
    Subject      pkix.Name        // Certificate subject
    DNSNames     []string         // DNS SANs
    IPAddresses  []net.IP         // IP SANs
    EmailAddress []string         // Email SANs
    ValidFrom    time.Time        // Start time
    ValidFor     time.Duration    // Validity period
    IsCA         bool            // CA certificate flag
    MaxPathLen   int             // CA path length constraint
}

CA Features

Path Length Constraints
// Root CA with path length 2
caCert, _ := cert.CreateCACertificate(rootKeys, cert.CertificateRequest{
    Subject: pkix.Name{CommonName: "Root CA"},
    IsCA: true,
    MaxPathLen: 2,  // Allows 2 intermediate CAs
    ValidFor: 20 * 365 * 24 * time.Hour,
})
Subject Alternative Names
serverCert, _ := cert.SignCertificate(caCert, caKeys, cert.CertificateRequest{
    Subject: pkix.Name{CommonName: "server.example.com"},
    DNSNames: []string{
        "server.example.com",
        "www.server.example.com",
        "*.api.example.com",  // Wildcard supported
    },
    IPAddresses: []net.IP{
        net.IPv4(192, 168, 1, 10),
        net.ParseIP("2001:db8::1"),  // IPv6 supported
    },
    EmailAddress: []string{"admin@example.com"},
}, serverKeys.PublicKey)

Testing

# Run certificate tests
go test ./cert/...

# Specific tests
task test:specific -- TestCreateSelfSignedCertificate
task test:specific -- TestCACertificate
task test:specific -- TestSignCertificate

# OpenSSL compatibility
task test:compatibility

Test Coverage: 74.3%

Best Practices

  1. Use Strong Keys: RSA ≥3072 for CAs, ≥2048 for end-entity
  2. Set Appropriate Validity: Long for CAs (10-20 years), short for servers (1-2 years)
  3. Path Length Constraints: Limit intermediate CA depth
  4. Subject Alternative Names: Always include for web servers
  5. Certificate Chains: Keep full chain for verification

Further Reading


Part of GoPKI - Type-Safe Cryptography for Production

Documentation ¶

Overview ¶

Package cert provides X.509 certificate creation, parsing, and management.

Index ¶

Constants ¶

This section is empty.

Variables ¶

This section is empty.

Functions ¶

func ConvertDERToPEM ¶

func ConvertDERToPEM(derData []byte) ([]byte, error)

ConvertDERToPEM converts DER-encoded (binary) certificate data to PEM format. This function validates the DER certificate data and wraps it in PEM headers with Base64 encoding for text-based storage and transmission.

The resulting PEM format is human-readable and compatible with most certificate management tools and applications.

Example:

pemData, err := ConvertDERToPEM(derBytes)
if err != nil {
	log.Fatal("Conversion failed:", err)
}
fmt.Printf("Certificate in PEM format:\n%s", pemData)

func ConvertPEMToDER ¶

func ConvertPEMToDER(pemData []byte) ([]byte, error)

ConvertPEMToDER converts PEM-encoded certificate data to DER (binary) format. This function extracts the Base64-decoded certificate data from PEM format, removing the headers and returning the raw binary DER data.

The conversion results in a smaller file size (typically 30% reduction) and faster parsing compared to PEM format.

Example:

derData, err := ConvertPEMToDER(pemBytes)
if err != nil {
	log.Fatal("Conversion failed:", err)
}

func VerifyCertificate ¶

func VerifyCertificate(cert *Certificate, caCert *Certificate) error

VerifyCertificate verifies that a certificate was signed by a Certificate Authority (CA). It checks the certificate's signature against the provided CA certificate and validates the certificate chain.

The function performs the following verifications: - Signature verification using the CA's public key - Certificate validity period (not expired) - Certificate chain validation

Example:

err := VerifyCertificate(serverCert, caCert)
if err != nil {
	log.Printf("Certificate verification failed: %v", err)
}

Types ¶

type CSRRequest ¶ added in v1.19.0

type CSRRequest struct {
	Subject      pkix.Name // Certificate subject information (CN, O, OU, etc.)
	DNSNames     []string  // Subject Alternative Names - DNS names
	IPAddresses  []net.IP  // Subject Alternative Names - IP addresses
	EmailAddress []string  // Subject Alternative Names - email addresses

	// CA-specific fields (optional, for intermediate CA CSRs)
	IsCA       bool // Set to true to request a CA certificate
	MaxPathLen int  // Maximum depth of intermediate CAs (for CA CSRs)
}

CSRRequest contains the parameters for creating a Certificate Signing Request (CSR). A CSR is used to request a certificate from a Certificate Authority (CA).

type Certificate ¶

type Certificate struct {
	Certificate *x509.Certificate // The parsed X.509 certificate
	PEMData     []byte            // PEM-encoded certificate data (Base64 text format)
	DERData     []byte            // DER-encoded certificate data (binary format)
}

Certificate represents an X.509 certificate with support for both PEM and DER formats. It contains the parsed certificate and the raw data in both text (PEM) and binary (DER) formats.

func CreateCACertificate ¶

func CreateCACertificate[T keypair.KeyPair](keyPair T, request CertificateRequest) (*Certificate, error)

CreateCACertificate creates a new Certificate Authority (CA) certificate. The certificate is configured with CA-specific extensions and can be used to sign other certificates.

The certificate will have: - BasicConstraints extension with CA=true - KeyUsage extension with CertSign and CRLSign - Configurable path length constraints for intermediate CAs

Type parameter T must be one of: *algo.RSAKeyPair, *algo.ECDSAKeyPair, or *algo.Ed25519KeyPair.

Example:

keyPair, _ := keypair.GenerateKeyPair[algo.KeySize, *algo.RSAKeyPair](4096)
caCert, err := CreateCACertificate(keyPair, CertificateRequest{
	Subject: pkix.Name{CommonName: "My Root CA"},
	ValidFor: 10 * 365 * 24 * time.Hour, // 10 years
	IsCA: true,
	MaxPathLen: 2, // Allow 2 levels of intermediate CAs
})

func CreateSelfSignedCertificate ¶

func CreateSelfSignedCertificate[T keypair.KeyPair](keyPair T, request CertificateRequest) (*Certificate, error)

CreateSelfSignedCertificate creates a new self-signed X.509 certificate using the provided key pair. The certificate is signed by its own private key, making it suitable for testing, development, or as a root CA certificate.

Type parameter T must be one of: *algo.RSAKeyPair, *algo.ECDSAKeyPair, or *algo.Ed25519KeyPair.

The returned Certificate contains both PEM and DER encoded data and can be saved in either format.

Example:

keyPair, _ := keypair.GenerateKeyPair[algo.KeySize, *algo.RSAKeyPair](2048)
cert, err := CreateSelfSignedCertificate(keyPair, CertificateRequest{
	Subject: pkix.Name{CommonName: "example.com"},
	DNSNames: []string{"example.com", "www.example.com"},
	ValidFor: 365 * 24 * time.Hour,
})

func LoadCertificateFromDERFile ¶

func LoadCertificateFromDERFile(filename string) (*Certificate, error)

LoadCertificateFromDERFile loads a certificate from a DER-formatted file. The function reads the binary DER file and creates a Certificate object with both PEM and DER data populated.

Example:

certificate, err := LoadCertificateFromDERFile("certificate.der")

func LoadCertificateFromFile ¶

func LoadCertificateFromFile(filename string) (*Certificate, error)

LoadCertificateFromFile loads a certificate from a PEM-formatted file. The function reads the file and parses the PEM data to create a Certificate object with both PEM and DER data populated.

Example:

certificate, err := LoadCertificateFromFile("certificate.pem")

func ParseCertificateFromDER ¶

func ParseCertificateFromDER(derData []byte) (*Certificate, error)

ParseCertificateFromDER parses a certificate from DER-encoded (binary) data. The function parses the binary ASN.1 data and creates a Certificate object with both PEM and DER data populated.

Example:

certificate, err := ParseCertificateFromDER(derBytes)

func ParseCertificateFromPEM ¶

func ParseCertificateFromPEM(pemData []byte) (*Certificate, error)

ParseCertificateFromPEM parses a certificate from PEM-encoded data. The function decodes the PEM block and creates a Certificate object with both PEM and DER data populated.

The PEM data should contain a "CERTIFICATE" block:

-----BEGIN CERTIFICATE-----
...base64 encoded certificate data...
-----END CERTIFICATE-----

Example:

certificate, err := ParseCertificateFromPEM(pemBytes)

func SignCSR ¶ added in v1.19.0

func SignCSR[T keypair.KeyPair](caCert *Certificate, caKeyPair T, csr *CertificateSigningRequest, request CertificateRequest) (*Certificate, error)

SignCSR signs a Certificate Signing Request using a CA certificate and creates a new certificate. This function processes a CSR and issues a certificate signed by the CA.

Parameters:

  • caCert: The CA certificate used to sign the new certificate
  • caKeyPair: The CA's private key pair for signing
  • csr: The certificate signing request to be signed
  • request: Additional certificate parameters (validity, extensions, etc.)

Example:

// CA signs a CSR
cert, err := SignCSR(caCert, caKeyPair, csr, CertificateRequest{
	ValidFor: 365 * 24 * time.Hour,
})

func SignCertificate ¶

func SignCertificate[T keypair.KeyPair](caCert *Certificate, caKeyPair T, request CertificateRequest, subjectPublicKey crypto.PublicKey) (*Certificate, error)

SignCertificate creates a new certificate signed by a Certificate Authority (CA). This function creates an end-entity or intermediate CA certificate using the provided CA certificate and private key to sign the new certificate.

Parameters:

  • caCert: The CA certificate used to sign the new certificate
  • caKeyPair: The CA's private key pair for signing
  • request: Certificate request containing subject info and extensions
  • subjectPublicKey: The public key to be certified (from the entity requesting the certificate)

The resulting certificate will be signed by the CA and contain the subject's public key.

Example:

// Create CA certificate first
caCert, _ := CreateCACertificate(caKeyPair, caRequest)

// Create end-entity certificate signed by CA
entityKeyPair, _ := keypair.GenerateKeyPair[algo.KeySize, *algo.RSAKeyPair](2048)
cert, err := SignCertificate(caCert, caKeyPair, CertificateRequest{
	Subject: pkix.Name{CommonName: "server.example.com"},
	DNSNames: []string{"server.example.com"},
	ValidFor: 365 * 24 * time.Hour,
}, entityKeyPair.PublicKey)

func (*Certificate) SaveToDERFile ¶

func (c *Certificate) SaveToDERFile(filename string) error

SaveToDERFile saves the certificate to a file in DER (binary) format. The file will be created with 0600 permissions (readable/writable by owner only). DER format is more compact than PEM (typically 30% smaller) and faster to parse.

Example:

err := certificate.SaveToDERFile("certificate.der")

func (*Certificate) SaveToFile ¶

func (c *Certificate) SaveToFile(filename string) error

SaveToFile saves the certificate to a file in PEM format. The file will be created with 0600 permissions (readable/writable by owner only).

Example:

err := certificate.SaveToFile("certificate.pem")

func (*Certificate) ToDER ¶

func (c *Certificate) ToDER() []byte

ToDER returns the DER-encoded (binary) certificate data. DER format is more compact than PEM and suitable for binary storage or transmission.

Example:

derData := certificate.ToDER()
fmt.Printf("Certificate size: %d bytes\n", len(derData))

func (*Certificate) ToPEM ¶

func (c *Certificate) ToPEM() []byte

ToPEM returns the PEM-encoded (Base64 text) certificate data. PEM format is human-readable and widely supported by certificate management tools. The returned data includes the "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" headers.

Example:

pemData := certificate.ToPEM()
fmt.Printf("Certificate in PEM format:\n%s", pemData)

type CertificateRequest ¶

type CertificateRequest struct {
	Subject      pkix.Name     // Certificate subject information (CN, O, OU, etc.)
	DNSNames     []string      // Subject Alternative Names - DNS names
	IPAddresses  []net.IP      // Subject Alternative Names - IP addresses
	EmailAddress []string      // Subject Alternative Names - email addresses
	ValidFrom    time.Time     // Certificate validity start time (defaults to now)
	ValidFor     time.Duration // Certificate validity duration (e.g., 365*24*time.Hour for 1 year)

	// CA-specific fields (optional)
	IsCA           bool // Set to true to create a CA certificate
	MaxPathLen     int  // Maximum depth of intermediate CAs (0 = can only sign end-entity certs, -1 = no limit)
	MaxPathLenZero bool // Set to true to explicitly set MaxPathLen to 0

	// Advanced certificate usage fields (optional)
	KeyUsage    x509.KeyUsage      // Custom key usage flags (if not set, defaults based on IsCA)
	ExtKeyUsage []x509.ExtKeyUsage // Custom extended key usage (if not set, defaults based on IsCA)
}

CertificateRequest contains the parameters for creating a new X.509 certificate. It supports both end-entity and CA certificates with configurable extensions and constraints.

type CertificateSigningRequest ¶ added in v1.19.0

type CertificateSigningRequest struct {
	Request *x509.CertificateRequest // The parsed certificate request
	PEMData []byte                   // PEM-encoded CSR data
	DERData []byte                   // DER-encoded CSR data
}

CertificateSigningRequest represents a parsed CSR with both PEM and DER formats.

func CreateCACSR ¶ added in v1.19.0

func CreateCACSR[T keypair.KeyPair](keyPair T, request CSRRequest) (*CertificateSigningRequest, error)

CreateCACSR creates a Certificate Signing Request for a Certificate Authority certificate. This is used when creating intermediate CA certificates that need to be signed by a root or parent CA.

The CSR will indicate CA capabilities through the request parameters, which the signing CA can use to set appropriate certificate extensions.

Type parameter T must be one of: *algo.RSAKeyPair, *algo.ECDSAKeyPair, or *algo.Ed25519KeyPair.

Example:

keyPair := keypair.Generate(algo.RSA4096)
csr, err := CreateCACSR(keyPair, CSRRequest{
	Subject: pkix.Name{
		CommonName:   "Intermediate CA",
		Organization: []string{"Example Corp"},
	},
	IsCA:       true,
	MaxPathLen: 0, // Can only sign end-entity certificates
})

func CreateCSR ¶ added in v1.19.0

func CreateCSR[T keypair.KeyPair](keyPair T, request CSRRequest) (*CertificateSigningRequest, error)

CreateCSR creates a Certificate Signing Request (CSR) for the provided key pair. The CSR can be submitted to a Certificate Authority to obtain a signed certificate.

Type parameter T must be one of: *algo.RSAKeyPair, *algo.ECDSAKeyPair, or *algo.Ed25519KeyPair.

The returned CertificateSigningRequest contains both PEM and DER encoded data.

Example:

keyPair := keypair.Generate(algo.RSA2048)
csr, err := CreateCSR(keyPair, CSRRequest{
	Subject: pkix.Name{
		CommonName:   "server.example.com",
		Organization: []string{"Example Corp"},
		Country:      []string{"US"},
	},
	DNSNames: []string{"server.example.com", "www.example.com"},
})

func LoadCSRFromFile ¶ added in v1.19.0

func LoadCSRFromFile(filename string) (*CertificateSigningRequest, error)

LoadCSRFromFile loads a CSR from a PEM-formatted file.

Example:

csr, err := LoadCSRFromFile("request.csr")

func ParseCSRFromPEM ¶ added in v1.19.0

func ParseCSRFromPEM(pemData []byte) (*CertificateSigningRequest, error)

ParseCSRFromPEM parses a CSR from PEM-encoded data.

The PEM data should contain a "CERTIFICATE REQUEST" block:

-----BEGIN CERTIFICATE REQUEST-----
...base64 encoded CSR data...
-----END CERTIFICATE REQUEST-----

Example:

csr, err := ParseCSRFromPEM(pemBytes)

func (*CertificateSigningRequest) SaveToFile ¶ added in v1.19.0

func (c *CertificateSigningRequest) SaveToFile(filename string) error

SaveToFile saves the CSR to a file in PEM format. The file will be created with 0600 permissions (readable/writable by owner only).

Example:

err := csr.SaveToFile("request.csr")

Jump to

Keyboard shortcuts

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