● Notice //GitHub (@shehzade) is temporarily suspended pending an automated false-positive review. All tools are hosted on this Code Mirror and available on request (contact); GitHub links will return once reinstated.
PUBLIC MIRRORGo v1.0

Multi-protocol network egress assessment and DLP verification framework featuring automated L4 sweeps, corporate proxy traversal, and covert protocol smuggling across 20+ channels.

$ git clone https://shehzade.io/repos/contraband.git Copy
Source ZIP (1.93 MB)
Code 174 Commits 1
contraband / pkg / server / certgen / ca.go
← Back to directory
196 lines · 5.8 KB
Raw
1package certgen
2
3import (
4 "crypto"
5 "crypto/ecdsa"
6 "crypto/elliptic"
7 "crypto/rand"
8 "crypto/x509"
9 "crypto/x509/pkix"
10 "encoding/pem"
11 "errors"
12 "fmt"
13 "math/big"
14 "net"
15 "time"
16)
17
18// CertificateAuthority represents an ephemeral dynamic in-memory Root CA.
19type CertificateAuthority struct {
20 Certificate *x509.Certificate
21 PrivateKey crypto.Signer
22 CertPEM []byte
23 KeyPEM []byte
24}
25
26// NewCA generates a self-signed ephemeral root CA with ECDSA P-256.
27func NewCA(commonName string) (*CertificateAuthority, error) {
28 if commonName == "" {
29 commonName = "Contraband Dynamic Root CA"
30 }
31
32 privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
33 if err != nil {
34 return nil, fmt.Errorf("failed to generate CA private key: %w", err)
35 }
36
37 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
38 serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
39 if err != nil {
40 return nil, fmt.Errorf("failed to generate CA serial number: %w", err)
41 }
42
43 now := time.Now().UTC()
44 template := x509.Certificate{
45 SerialNumber: serialNumber,
46 Subject: pkix.Name{
47 CommonName: commonName,
48 Organization: []string{"Contraband Security Framework"},
49 },
50 NotBefore: now.Add(-1 * time.Hour), // Clock skew buffer
51 NotAfter: now.Add(365 * 24 * time.Hour),
52 KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageDigitalSignature,
53 BasicConstraintsValid: true,
54 IsCA: true,
55 MaxPathLen: 1,
56 }
57
58 certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
59 if err != nil {
60 return nil, fmt.Errorf("failed to create self-signed CA certificate: %w", err)
61 }
62
63 cert, err := x509.ParseCertificate(certDER)
64 if err != nil {
65 return nil, fmt.Errorf("failed to parse generated CA cert: %w", err)
66 }
67
68 certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
69 keyDER, err := x509.MarshalECPrivateKey(privKey)
70 if err != nil {
71 return nil, fmt.Errorf("failed to marshal CA private key: %w", err)
72 }
73 keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER})
74
75 return &CertificateAuthority{
76 Certificate: cert,
77 PrivateKey: privKey,
78 CertPEM: certPEM,
79 KeyPEM: keyPEM,
80 }, nil
81}
82
83// LoadCA parses existing PEM-encoded certificate and private key blocks.
84func LoadCA(certPEM, keyPEM []byte) (*CertificateAuthority, error) {
85 certBlock, _ := pem.Decode(certPEM)
86 if certBlock == nil || certBlock.Type != "CERTIFICATE" {
87 return nil, errors.New("failed to decode valid CERTIFICATE PEM block")
88 }
89
90 cert, err := x509.ParseCertificate(certBlock.Bytes)
91 if err != nil {
92 return nil, fmt.Errorf("failed to parse certificate: %w", err)
93 }
94
95 keyBlock, _ := pem.Decode(keyPEM)
96 if keyBlock == nil {
97 return nil, errors.New("failed to decode private key PEM block")
98 }
99
100 var privKey crypto.Signer
101 if keyBlock.Type == "EC PRIVATE KEY" {
102 ecKey, err := x509.ParseECPrivateKey(keyBlock.Bytes)
103 if err != nil {
104 return nil, fmt.Errorf("failed to parse EC private key: %w", err)
105 }
106 privKey = ecKey
107 } else if keyBlock.Type == "PRIVATE KEY" {
108 pk, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes)
109 if err != nil {
110 return nil, fmt.Errorf("failed to parse PKCS#8 private key: %w", err)
111 }
112 signer, ok := pk.(crypto.Signer)
113 if !ok {
114 return nil, errors.New("parsed private key is not a crypto.Signer")
115 }
116 privKey = signer
117 } else {
118 return nil, fmt.Errorf("unsupported private key PEM type: %s", keyBlock.Type)
119 }
120
121 return &CertificateAuthority{
122 Certificate: cert,
123 PrivateKey: privKey,
124 CertPEM: certPEM,
125 KeyPEM: keyPEM,
126 }, nil
127}
128
129// CertPool returns an x509 CertPool containing this CA cert for client verification.
130func (ca *CertificateAuthority) CertPool() *x509.CertPool {
131 pool := x509.NewCertPool()
132 pool.AddCert(ca.Certificate)
133 return pool
134}
135
136// SignServerCert issues and signs a leaf TLS certificate for the specified hosts.
137func (ca *CertificateAuthority) SignServerCert(hosts []string, validFor time.Duration) ([]byte, []byte, error) {
138 if validFor <= 0 {
139 validFor = 30 * 24 * time.Hour
140 }
141
142 privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
143 if err != nil {
144 return nil, nil, fmt.Errorf("failed to generate server private key: %w", err)
145 }
146
147 serialLimit := new(big.Int).Lsh(big.NewInt(1), 128)
148 serial, err := rand.Int(rand.Reader, serialLimit)
149 if err != nil {
150 return nil, nil, fmt.Errorf("failed to generate server serial: %w", err)
151 }
152
153 now := time.Now().UTC()
154 cn := "localhost"
155 if len(hosts) > 0 && hosts[0] != "" {
156 cn = hosts[0]
157 }
158
159 template := x509.Certificate{
160 SerialNumber: serial,
161 Subject: pkix.Name{
162 CommonName: cn,
163 Organization: []string{"Contraband Dynamic Server"},
164 },
165 NotBefore: now.Add(-1 * time.Hour),
166 NotAfter: now.Add(validFor),
167 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
168 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
169 }
170
171 // Categorize DNS names vs IP addresses in SANs
172 for _, h := range hosts {
173 if ip := net.ParseIP(h); ip != nil {
174 template.IPAddresses = append(template.IPAddresses, ip)
175 } else {
176 template.DNSNames = append(template.DNSNames, h)
177 }
178 }
179 // Always include loopback SANs
180 template.IPAddresses = append(template.IPAddresses, net.ParseIP("127.0.0.1"), net.ParseIP("::1"))
181 template.DNSNames = append(template.DNSNames, "localhost")
182
183 certDER, err := x509.CreateCertificate(rand.Reader, &template, ca.Certificate, &privKey.PublicKey, ca.PrivateKey)
184 if err != nil {
185 return nil, nil, fmt.Errorf("failed to sign server cert with CA: %w", err)
186 }
187
188 certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
189 keyDER, err := x509.MarshalECPrivateKey(privKey)
190 if err != nil {
191 return nil, nil, fmt.Errorf("failed to marshal server private key: %w", err)
192 }
193 keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER})
194
195 return certPEM, keyPEM, nil
196}