mitm/cert_utils.go

269 lines
11 KiB
Go

package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/pem"
"fmt"
"math/big"
"net"
"strings"
"time"
"software.sslmate.com/src/go-pkcs12"
)
// Hardcoded certificate data - users need to replace these placeholders with actual certificate data
const (
// Base64 encoded data of P12 certificate - users need to replace with actual cert.p12 file content
hardcodedP12Data = `-----BEGIN CERTIFICATE-----
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
BBTOPefdAsbPZURS9djPzGhmw0NCbQICJxA=
-----END CERTIFICATE-----`
// PEM format data of CA certificate - users need to replace with actual CA.crt file content
hardcodedCACert = `-----BEGIN CERTIFICATE-----
MIIFOTCCBCGgAwIBAgIGAZi8TmIsMA0GCSqGSIb3DQEBCwUAMIGgMTEwLwYDVQQDDChDaGFybGVz
IFByb3h5IENBICgxOCBBdWcgMjAyNSwgQkxBQ0stUEMpMSUwIwYDVQQLDBxodHRwczovL2NoYXJs
ZXNwcm94eS5jb20vc3NsMREwDwYDVQQKDAhYSzcyIEx0ZDERMA8GA1UEBwwIQXVja2xhbmQxETAP
BgNVBAgMCEF1Y2tsYW5kMQswCQYDVQQGEwJOWjAeFw0yNTA4MTcwODMxNTBaFw0yNjA4MTcwODMx
NTBaMIGgMTEwLwYDVQQDDChDaGFybGVzIFByb3h5IENBICgxOCBBdWcgMjAyNSwgQkxBQ0stUEMp
MSUwIwYDVQQLDBxodHRwczovL2NoYXJsZXNwcm94eS5jb20vc3NsMREwDwYDVQQKDAhYSzcyIEx0
ZDERMA8GA1UEBwwIQXVja2xhbmQxETAPBgNVBAgMCEF1Y2tsYW5kMQswCQYDVQQGEwJOWjCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKEmwh2Lk0017ak2c+3eKUGRsZVc5TSfcFaaiAk5
kKMWj0pIXNKo2G8eERo4BYNqZi+icHGWBwmhAuUDJqpZMji2Qzv0jvuFDw0+UVVtp30RU/92GZYV
C44df+qPTYqUuD+ZPKdlo2RZ38Jbru/VT7AQQ53cvcBJ6s7WzY9QQVui1Rd3jHRXnyb9/duccw22
vo6f2/OX2mVEKpXd5/3g8d+D8EuoiTUKDbgM39diOYuelh8Xybf0Zy1ZU4nkYeaVwzf9djlgxa1E
2Qb9SscxddGBJxyTrqtoG4ZLwzuwz3DX6KOEPX73I0Q8L+TBf7KQhBYkHSOa6HygE0Vgi3HoM4UC
AwEAAaOCAXUwggFxMA8GA1UdEwEB/wQFMAMBAf8wggEtBglghkgBhvhCAQ0EggEeE4IBGlRoaXMg
cm9vdCBjZXJ0aWZpY2F0ZSB3YXMgZ2VuZXJhdGVkIGJ5IENoYXJsZXMgUHJveHkgZm9yIFNTTCBQ
cm94eWluZy4gSWYgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBwYXJ0IG9mIGEgY2VydGlmaWNhdGUgY2hh
aW4sIHRoaXMgbWVhbnMgdGhhdCB5b3UncmUgYnJvd3NpbmcgdGhyb3VnaCBDaGFybGVzIFByb3h5
IHdpdGggU1NMIFByb3h5aW5nIGVuYWJsZWQgZm9yIHRoaXMgd2Vic2l0ZS4gUGxlYXNlIHNlZSBo
dHRwczovL2NoYXJsZXNwcm94eS5jb20vc3NsIGZvciBtb3JlIGluZm9ybWF0aW9uLjAOBgNVHQ8B
Af8EBAMCAgQwHQYDVR0OBBYEFKBf+QLehq0dc4s7YMIUUFJdgWBfMA0GCSqGSIb3DQEBCwUAA4IB
AQBc+K3gGnz00yv2XMYRMbeYLr3SD15Tx3NAPri08EY1wyyufkBCaI81tZSCMy4PkGAYN+zODrQ6
MRj0tbABTNZHdzFCuazE+B2ce2Ka3PcQ1DNpGf60NYk9qBHpOxak+5XxrECFYjStYW3gLZ7mZSnI
YX9doSujRpzSbVZFvVh4J1zCzF1NuD6VxxfFjppJ6EnvnSSQOly0e32NzibQi3akFb4E5hn58py/
Eth3xl7mzWjcdKeKd30TAeg98PA+drJ8JsunIc2sICcNuAoVSKQEX4ihZHMhFLXl0MNdyWQtqHPR
beQU9SvWF3DVmilrNO1neetL2TCZK5iMyIAHvqPo
-----END CERTIFICATE-----`
// P12 certificate password - users need to modify to actual password
hardcodedP12Password = "Admin!23"
)
// loadHardcodedCertificate loads hardcoded P12 certificate
func loadHardcodedCertificate() (*tls.Config, error) {
// If hardcoded data is empty or placeholder, generate self-signed certificate
if len(hardcodedP12Data) < 100 {
fmt.Println("Warning: No valid P12 certificate data provided, generating self-signed certificate for testing")
return generateSelfSignedCert()
}
// Decode base64 data
p12Data, err := decodeBase64String(hardcodedP12Data)
if err != nil {
fmt.Printf("Warning: Unable to decode P12 data (%v), generating self-signed certificate\n", err)
return generateSelfSignedCert()
}
// Parse P12 data
privateKey, cert, caCerts, err := pkcs12.DecodeChain(p12Data, hardcodedP12Password)
if err != nil {
fmt.Printf("Warning: Unable to parse P12 certificate (%v), generating self-signed certificate\n", err)
return generateSelfSignedCert()
}
// Create certificate chain
certificates := []tls.Certificate{
{
Certificate: [][]byte{cert.Raw},
PrivateKey: privateKey,
},
}
// Create CA certificate pool
caCertPool := x509.NewCertPool()
for _, caCert := range caCerts {
caCertPool.AddCert(caCert)
}
// If there's a hardcoded CA certificate, add it to the pool
if len(hardcodedCACert) > 100 {
block, _ := pem.Decode([]byte(hardcodedCACert))
if block != nil {
if caCert, err := x509.ParseCertificate(block.Bytes); err == nil {
caCertPool.AddCert(caCert)
}
}
}
return &tls.Config{
Certificates: certificates,
RootCAs: caCertPool,
InsecureSkipVerify: true,
}, nil
}
// decodeBase64String decodes base64 string, ignoring whitespace and comments
func decodeBase64String(data string) ([]byte, error) {
// Remove comment lines and whitespace
var cleanData strings.Builder
lines := strings.SplitSeq(data, "\n")
for line := range lines {
line = strings.TrimSpace(line)
if len(line) > 0 && !strings.HasPrefix(line, "--") {
cleanData.WriteString(line)
}
}
if cleanData.Len() == 0 {
return nil, fmt.Errorf("no valid base64 data")
}
// Use standard base64 decoding
return base64.StdEncoding.DecodeString(cleanData.String())
}
// generateSelfSignedCert generates self-signed certificate for testing
func generateSelfSignedCert() (*tls.Config, error) {
// Generate private key
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
}
// Create certificate template
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
Organization: []string{"MITM Proxy"},
OrganizationalUnit: []string{"MITM Proxy CA"},
Country: []string{"US"},
Province: []string{""},
Locality: []string{""},
StreetAddress: []string{""},
PostalCode: []string{""},
CommonName: "MITM Proxy Root CA",
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(365 * 24 * time.Hour),
// Proper key usage for CA certificate
KeyUsage: x509.KeyUsageKeyEncipherment |
x509.KeyUsageDigitalSignature |
x509.KeyUsageCertSign |
x509.KeyUsageCRLSign,
// Extended key usage for server authentication
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageServerAuth,
x509.ExtKeyUsageClientAuth,
},
BasicConstraintsValid: true,
IsCA: true,
MaxPathLen: 0,
MaxPathLenZero: true,
// Add Subject Alternative Names for flexibility
DNSNames: []string{
"localhost",
"*.localhost",
"127.0.0.1",
},
IPAddresses: []net.IP{
net.IPv4(127, 0, 0, 1),
net.IPv6loopback,
},
}
// Generate certificate
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
if err != nil {
return nil, err
}
// Create TLS certificate
cert := tls.Certificate{
Certificate: [][]byte{certDER},
PrivateKey: privateKey,
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
InsecureSkipVerify: true,
}, nil
}
// getHardcodedCACert returns hardcoded CA certificate
func getHardcodedCACert() string {
return hardcodedCACert
}