Skip to content

Commit

Permalink
Merge pull request #2 from spbkaizo/main
Browse files Browse the repository at this point in the history
added RFC 5280, 4.2.2.1 AIA support
  • Loading branch information
ps-spb authored Apr 27, 2023
2 parents cfd106a + eab2c57 commit d46ab0a
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 81 deletions.
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
include: VERSION

all:
go build -v -ldflags "-X main.buildstamp=`date -u '+%Y-%m-%d_%I:%M:%S%p'` -X main.githash=`git rev-parse HEAD`" || exit

Expand Down
3 changes: 3 additions & 0 deletions config.json.sample
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"Country": "UK",
"CaName": "PortSwigger CA",
"CaVersion": "2023",
"CaAiaUrl": "",
"CaAiaRootUrl": "",
"CaAiaIssuerUrl": "",
"OrgUnit": "SecEng",
"City": "Knutsford",
"County": "Cheshire",
Expand Down
5 changes: 4 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type Config struct {
Country string `json:""`
CaName string `json:""`
CaVersion string `json:""`
CaAiaIssuerUrl string `json:""`
CaAiaRootUrl string `json:""`
OrgUnit string `json:""`
City string `json:""`
County string `json:""`
Expand Down Expand Up @@ -177,8 +179,9 @@ func main() {
if err != nil {
log.Printf("FATAL: Could not not configure p11 - did you create or specify the configuration file, ")
log.Printf("FATAL: as detailed at https://pkg.go.dev/github.com/ThalesIgnite/crypto11#ConfigureFromFile ?")
log.Fatalf("FATAL: %v", err)
log.Printf("FATAL: Starting at Layer 1, if you are using a yubikey or hardware token, is it plugged in??")
log.Printf("FATAL: *** Check if the configured pkcs11 library (%v) is accessible?", config.Path)
log.Fatalf("FATAL: %v", err)
}
crtBytes, err := signCSR(signer, csr)
if err != nil {
Expand Down
170 changes: 92 additions & 78 deletions x509.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import (
"github.com/sethvargo/go-password/password"
)

// TODO - we should implement a CRL function
func revokeCRT(crt *x509.Certificate) {
// func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error)
// https://pkg.go.dev/crypto/x509#CreateRevocationList
}

// GenerateSubjectKeyID generates Subject Key Identifier (SKI) using SHA-256
// hash of the public key bytes according to RFC 7093 section 2.
func GenerateSubjectKeyID(pub crypto.PublicKey) ([]byte, error) {
Expand Down Expand Up @@ -94,6 +100,78 @@ func newSerialNumber() (*big.Int, error) {
return rand.Int(rand.Reader, serialNumberLimit)
}

// This function call should be executed precisely once, to generate the root CA.
// This is effectively creating a 'self-signed' cert.
func createRootCA(signer crypto11.Signer) bool {
id, err := GenerateSubjectKeyID(signer.Public())
if err != nil {
log.Fatalf("fatal: %v", err)
}
// this should only ever be used once, well maybe twice.
// but definately we should have another solution by then.
name := &pkix.Name{}
name.Country = []string{config.Country}
name.Organization = []string{config.Organisation}
name.OrganizationalUnit = []string{config.OrgUnit}
name.CommonName = config.CaName + " - " + config.CaVersion

tmpl := &x509.Certificate{
IsCA: true,
BasicConstraintsValid: true,
SerialNumber: big.NewInt(31337),
Subject: *name,
NotBefore: time.Now().Add(time.Second * -600).UTC(),
NotAfter: time.Now().AddDate(0, 0, 3650).UTC(),
SubjectKeyId: id,
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
// according to https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-1.8.7.pdf
// we shouldn't set this. See 7.1.2.1.b Root CA Certificate for details
//ExtKeyUsage: []x509.ExtKeyUsage{
// x509.ExtKeyUsageOCSPSigning,
//},
SignatureAlgorithm: x509.SHA512WithRSA,
// as above, should not be set 7.1.2.1.a for details
//MaxPathLen: 1,
// TODO?
//OCSPServer: []string{"https://ocsp.security.portswigger.internal"},
}
if config.CaAiaRootUrl != "" {
tmpl.IssuingCertificateURL = append(tmpl.IssuingCertificateURL, config.CaAiaRootUrl)
}
// chomp chomp.
crtBytes, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, signer.Public().(*rsa.PublicKey), signer)
if err != nil {
log.Fatalf("FATAL: while trying to sign certificate (%v)", err)
}
pemBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: crtBytes,
}
file, err := os.OpenFile(name.CommonName+".pem", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
log.Fatalf("FATAL: trying to write %v.pem file (%v)", name.CommonName, err)
}
defer file.Close()
out := pem.EncodeToMemory(pemBlock)
if _, err := file.Write(out); err != nil {
file.Close()
os.Remove(name.CommonName + ".pem")
log.Fatalf("FATAL: trying to write %v.pem file (%v)", name.CommonName, err)
}
log.Printf("INFO: Successfully wrote out pem cert to %v.pem", name.CommonName)
// now write out the DER bytes to a crt file
err = os.WriteFile(name.CommonName+".crt", crtBytes, 0644)
if err != nil {
log.Fatalf("FATAL: trying to write %v.crt file (%v)", name.CommonName, err)
}
log.Printf("INFO: Successfully wrote out crt file to %v.crt", name.CommonName)
err = addDbRecord(crtBytes)
if err != nil {
log.Printf("ERROR: while adding record to DB (non-fatal, but please investigate!)")
}
return true
}

func createIntermediateCert(signer crypto11.Signer, intpubkey crypto.PublicKey, subjectname string) (caName string, ok bool) {
// need to read in pubkey
id, err := GenerateSubjectKeyID(intpubkey)
Expand Down Expand Up @@ -129,15 +207,20 @@ func createIntermediateCert(signer crypto11.Signer, intpubkey crypto.PublicKey,

// you may want to undefine this - if you do any end user certs signed by this cert will be scoped
// to only those usages below. Of course, this may be what you wish to achieve.
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageOCSPSigning, x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth,
},
// More details here: https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-1.8.7.pdf
// See section 7.1.2.2 Subordinate CA Certificate item g.
//ExtKeyUsage: []x509.ExtKeyUsage{
// x509.ExtKeyUsageOCSPSigning, x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth,
//},
SignatureAlgorithm: x509.SHA512WithRSA,
// According to Andy C maxpathlen only belongs on the root.
// define this here.
MaxPathLen: 0,
// TODO?
//OCSPServer: []string{"https://ocsp.security.portswigger.internal"},
}
if config.CaAiaRootUrl != "" {
tmpl.IssuingCertificateURL = append(tmpl.IssuingCertificateURL, config.CaAiaRootUrl)
}
// we need the upstream cert
if _, err := os.Stat(flCaCertFile); os.IsNotExist(err) {
// path/to/whatever does not exist
Expand All @@ -158,7 +241,7 @@ func createIntermediateCert(signer crypto11.Signer, intpubkey crypto.PublicKey,
Type: "CERTIFICATE",
Bytes: crtBytes,
}
file, err := os.OpenFile(name.CommonName+".pem", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0444)
file, err := os.OpenFile(name.CommonName+".pem", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
log.Fatalf("FATAL: trying to write %v.pem file (%v)", name.CommonName, err)
}
Expand All @@ -171,7 +254,7 @@ func createIntermediateCert(signer crypto11.Signer, intpubkey crypto.PublicKey,
}
log.Printf("INFO: Successfully wrote out pem cert to %v.pem", name.CommonName)
// now write out the DER bytes to a crt file
err = os.WriteFile(name.CommonName+".crt", crtBytes, 0444)
err = os.WriteFile(name.CommonName+".crt", crtBytes, 0644)
if err != nil {
log.Fatalf("FATAL: trying to write %v.crt file (%v)", name.CommonName, err)
}
Expand Down Expand Up @@ -230,6 +313,9 @@ func signCSR(signer crypto11.Signer, csr *x509.CertificateRequest) (crtBytes []b
URIs: csr.URIs,
}
tmpl.ExtraExtensions = []pkix.Extension{bar, foo}
if config.CaAiaIssuerUrl != "" {
tmpl.IssuingCertificateURL = append(tmpl.IssuingCertificateURL, config.CaAiaIssuerUrl)
}

// we need the upstream cert
if _, err := os.Stat(flCaCertFile); os.IsNotExist(err) {
Expand Down Expand Up @@ -299,75 +385,3 @@ func prettyPrintCSR(csr *x509.CertificateRequest) {
log.Printf("INFO: \t\tIPAddresses: %v", csr.IPAddresses)
log.Printf("INFO: \t\tURIs: %v", csr.URIs)
}

// This function call should be executed precisely once, to generate the root CA.
// This is effectively creating a 'self-signed' cert.
func createRootCA(signer crypto11.Signer) bool {
id, err := GenerateSubjectKeyID(signer.Public())
if err != nil {
log.Fatalf("fatal: %v", err)
}
// this should only ever be used once, well maybe twice.
// but definately we should have another solution by then.
name := &pkix.Name{}
name.Country = []string{config.Country}
name.Organization = []string{config.Organisation}
name.OrganizationalUnit = []string{config.OrgUnit}
name.CommonName = config.CaName + " - " + config.CaVersion

tmpl := &x509.Certificate{
IsCA: true,
BasicConstraintsValid: true,
SerialNumber: big.NewInt(31337),
Subject: *name,
NotBefore: time.Now().Add(time.Second * -600).UTC(),
NotAfter: time.Now().AddDate(0, 0, 3650).UTC(),
SubjectKeyId: id,
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageOCSPSigning,
},
SignatureAlgorithm: x509.SHA512WithRSA,
MaxPathLen: 1,
// TODO?
//OCSPServer: []string{"https://ocsp.security.portswigger.internal"},
}
// chomp chomp.
crtBytes, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, signer.Public().(*rsa.PublicKey), signer)
if err != nil {
log.Fatalf("FATAL: while trying to sign certificate (%v)", err)
}
pemBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: crtBytes,
}
file, err := os.OpenFile(name.CommonName+".pem", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0444)
if err != nil {
log.Fatalf("FATAL: trying to write %v.pem file (%v)", name.CommonName, err)
}
defer file.Close()
out := pem.EncodeToMemory(pemBlock)
if _, err := file.Write(out); err != nil {
file.Close()
os.Remove(name.CommonName + ".pem")
log.Fatalf("FATAL: trying to write %v.pem file (%v)", name.CommonName, err)
}
log.Printf("INFO: Successfully wrote out pem cert to %v.pem", name.CommonName)
// now write out the DER bytes to a crt file
err = os.WriteFile(name.CommonName+".crt", crtBytes, 0444)
if err != nil {
log.Fatalf("FATAL: trying to write %v.crt file (%v)", name.CommonName, err)
}
log.Printf("INFO: Successfully wrote out crt file to %v.crt", name.CommonName)
err = addDbRecord(crtBytes)
if err != nil {
log.Printf("ERROR: while adding record to DB (non-fatal, but please investigate!)")
}
return true
}

// TODO - we should implement a CRL function
func revokeCRT(crt *x509.Certificate) {
// func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error)
// https://pkg.go.dev/crypto/x509#CreateRevocationList
}

0 comments on commit d46ab0a

Please sign in to comment.