Skip to content

Commit

Permalink
Merge pull request #224 from pzaino/develop
Browse files Browse the repository at this point in the history
Added check for certificate revoked and improved SSLInfo data collection
  • Loading branch information
pzaino authored Apr 25, 2024
2 parents 70f60fa + 3a2081b commit 945c3b6
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ config.sh
# Testing environments
sonar-project.properties
.scannerwork/**
AllCertificatesRecordReport.csv
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ require (
github.com/stretchr/testify v1.9.0
)

require golang.org/x/crypto v0.22.0 // indirect

require (
github.com/Ullaakut/nmap v2.0.2+incompatible
github.com/kr/pretty v0.3.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
Expand Down
7 changes: 6 additions & 1 deletion pkg/httpinfo/httpinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func ExtractHTTPInfo(config Config, re *ruleset.RuleEngine) (*HTTPDetails, error
}

// Retrieve SSL Info (if it's HTTPS)
cmn.DebugMsg(cmn.DbgLvlDebug1, "Collecting SSL/TLS information for URL: %s", config.URL)
sslInfo, err := getSSLInfo(config.URL)
if err != nil {
cmn.DebugMsg(cmn.DbgLvlDebug1, "Error retrieving SSL information: %v", err)
Expand All @@ -83,6 +84,7 @@ func ExtractHTTPInfo(config Config, re *ruleset.RuleEngine) (*HTTPDetails, error
httpClient := createHTTPClient(config)

// Send HTTP request
cmn.DebugMsg(cmn.DbgLvlDebug1, "Collecting HTTP Header information for URL: %s", config.URL)
resp, err := sendHTTPRequest(httpClient, config)
if err != nil {
return nil, err
Expand All @@ -104,7 +106,10 @@ func ExtractHTTPInfo(config Config, re *ruleset.RuleEngine) (*HTTPDetails, error
info.URL = config.URL
info.CustomHeaders = config.CustomHeader
info.FollowRedirects = config.FollowRedirects
info.SSLInfo = ConvertSSLInfoToDetails(*sslInfo)
info.SSLInfo, err = ConvertSSLInfoToDetails(*sslInfo)
if err != nil {
cmn.DebugMsg(cmn.DbgLvlDebug1, "Error converting SSL info to details: %v", err)
}

// Analyze response body for additional information
detectedItems, err := analyzeResponse(resp, info, re)
Expand Down
44 changes: 36 additions & 8 deletions pkg/httpinfo/sslinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package httpinfo

import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/csv"
Expand All @@ -28,6 +29,8 @@ import (
"strconv"
"strings"
"time"

"golang.org/x/crypto/ocsp"
)

// Globals:
Expand Down Expand Up @@ -160,7 +163,7 @@ func (ssl *SSLInfo) ValidateCertificate() error {
}

// Check if the certificate is revoked:
ssl.IsCertRevoked, err = checkCertificateRevocation(ssl.CertChain)
ssl.IsCertRevoked, err = checkCertificateRevocation(ssl.CertChain[0], ssl.CertChain[1])
if err != nil {
return err
}
Expand Down Expand Up @@ -380,11 +383,36 @@ func checkCertificateRevocationList(certChain []*x509.Certificate) ([]string, er
}
*/

func checkCertificateRevocation(certChain []*x509.Certificate) (bool, error) {
// Check if the certificate is revoked:
isCertRevoked := certChain[0] != nil && certChain[0].OCSPServer != nil && certChain[0].OCSPServer[0] != ""
//certChain[0].OCSPServer[0] == "http://ocsp.digicert.com"
return isCertRevoked, nil
// Check if the certificate has been revoked, using OCSP
func checkCertificateRevocation(cert *x509.Certificate, issuerCert *x509.Certificate) (bool, error) {
if len(cert.OCSPServer) == 0 {
return false, nil // No OCSP servers listed, can't check revocation via OCSP
}

ocspURL := cert.OCSPServer[0] // Get the first OCSP server in the list
req, err := ocsp.CreateRequest(cert, issuerCert, nil)
if err != nil {
return false, err // Error creating OCSP request
}

// Send the OCSP request and get the response
httpResponse, err := http.Post(ocspURL, "application/ocsp-request", bytes.NewReader(req))
if err != nil {
return false, err // Error sending the OCSP request
}
defer httpResponse.Body.Close()

responseBytes, err := io.ReadAll(httpResponse.Body)
if err != nil {
return false, err // Error reading the OCSP response
}

ocspResponse, err := ocsp.ParseResponse(responseBytes, issuerCert)
if err != nil {
return false, err // Error parsing the OCSP response
}

return ocspResponse.Status == ocsp.Revoked, nil
}

func checkCertificateTechnicalConstraints(certChain []*x509.Certificate) (bool, error) {
Expand Down Expand Up @@ -678,8 +706,8 @@ func checkTrustworthyRoot(certChain []*x509.Certificate) (bool, error) {
// Check if the root certificate is trustworthy
rootCert := certChain[len(certChain)-1]
//fmt.Println("Root Authority found:", rootCert)
fmt.Println("- Root Authority: ", rootCert.Subject.CommonName)
fmt.Println("- Root Issuer: ", rootCert.Issuer.CommonName)
//fmt.Println("- Root Authority: ", rootCert.Subject.CommonName)
//fmt.Println("- Root Issuer: ", rootCert.Issuer.CommonName)

RootAuthVerified := isRootAuthorityVerified(rootCert)
issuerVerified := isIssuerVerified(rootCert)
Expand Down
59 changes: 47 additions & 12 deletions pkg/httpinfo/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"encoding/pem"
"fmt"
"net/http"
"sort"
"strings"
"time"
)

Expand Down Expand Up @@ -166,11 +168,17 @@ type SSLInfo struct {
// from/to JSON, so it's used to store data on the DB and return data from requests.
type SSLDetails struct {
URL string `json:"url"`
Issuers []string `json:"issuers"` // List of issuers
FQDNs []string `json:"fqdns"` // List of FQDNs the certificate is valid for
PublicKeys []string `json:"public_keys"` // Public key info, possibly base64-encoded
SignatureAlgorithms []string `json:"signature_algorithms"` // Signature algorithms used
CertChains []CertChain `json:"cert_chain"` // Base64-encoded certificates
Issuers []string `json:"issuers"` // List of issuers
OwnerOrganizations []string `json:"owner_organizations"` // Organizations
OwnerOrganizationalUnits []string `json:"owner_organizational_units"` // Organizational Units
OwnerCountries []string `json:"owner_countries"` // Countries
OwnerStates []string `json:"owner_states"` // States
OwnerLocalities []string `json:"owner_localities"` // Localities
OwnerCommonNames []string `json:"owner_common_names"` // Common Names
FQDNs []string `json:"fqdns"` // List of FQDNs the certificate is valid for
PublicKeys []string `json:"public_keys"` // Public key info, possibly base64-encoded
SignatureAlgorithms []string `json:"signature_algorithms"` // Signature algorithms used
CertChains []CertChain `json:"cert_chain"` // Base64-encoded certificates
IsCertChainOrderValid bool `json:"is_cert_chain_order_valid"`
IsRootTrustworthy bool `json:"is_root_trustworthy"`
IsCertValid bool `json:"is_cert_valid"`
Expand All @@ -193,13 +201,19 @@ type CertChain struct {
}

// ConvertSSLInfoToDetails converts SSLInfo to SSLDetails
func ConvertSSLInfoToDetails(info SSLInfo) SSLDetails {
func ConvertSSLInfoToDetails(info SSLInfo) (SSLDetails, error) {
certChainBase64 := make([]CertChain, len(info.CertChain))
issuers := make([]string, len(info.CertChain))
fqdns := make([]string, 0)
publicKeys := make([]string, len(info.CertChain))
signatureAlgorithms := make([]string, len(info.CertChain))
ownerOrganizations := make([]string, len(info.CertChain))
ownerOrganizationalUnits := make([]string, len(info.CertChain))
ownerCountries := make([]string, len(info.CertChain))
ownerStates := make([]string, len(info.CertChain))
ownerLocalities := make([]string, len(info.CertChain))
ownerCommonNames := make([]string, len(info.CertChain))

fqdnSet := make(map[string]struct{}) // Let's use a map to avoid duplicates
for i, cert := range info.CertChain {
// Base64 encode the certificate
block := &pem.Block{
Expand All @@ -213,12 +227,20 @@ func ConvertSSLInfoToDetails(info SSLInfo) SSLDetails {
// Get issuer details
issuers[i] = cert.Issuer.CommonName

// Get FQDNs
fqdns = append(fqdns, cert.DNSNames...)
// Get owner details
ownerOrganizations[i] = strings.Join(cert.Subject.Organization, ", ")
ownerOrganizationalUnits[i] = strings.Join(cert.Subject.OrganizationalUnit, ", ")
ownerCountries[i] = strings.Join(cert.Subject.Country, ", ")
ownerStates[i] = strings.Join(cert.Subject.Province, ", ")
ownerLocalities[i] = strings.Join(cert.Subject.Locality, ", ")
ownerCommonNames[i] = cert.Subject.CommonName

// Get IP addresses if needed
// Get FQDNs
for _, name := range cert.DNSNames {
fqdnSet[name] = struct{}{}
}
for _, ip := range cert.IPAddresses {
fqdns = append(fqdns, ip.String())
fqdnSet[ip.String()] = struct{}{}
}

// Get public key info (encoded or detailed as needed)
Expand All @@ -231,10 +253,23 @@ func ConvertSSLInfoToDetails(info SSLInfo) SSLDetails {
signatureAlgorithms[i] = cert.SignatureAlgorithm.String()
}

// Convert the FQDN map to a slice
fqdns := make([]string, 0, len(fqdnSet))
for name := range fqdnSet {
fqdns = append(fqdns, name)
}
sort.Strings(fqdns)

return SSLDetails{
URL: info.URL,
CertChains: certChainBase64,
Issuers: issuers,
OwnerOrganizations: ownerOrganizations,
OwnerOrganizationalUnits: ownerOrganizationalUnits,
OwnerCountries: ownerCountries,
OwnerStates: ownerStates,
OwnerLocalities: ownerLocalities,
OwnerCommonNames: ownerCommonNames,
FQDNs: fqdns,
PublicKeys: publicKeys,
SignatureAlgorithms: signatureAlgorithms,
Expand All @@ -252,7 +287,7 @@ func ConvertSSLInfoToDetails(info SSLInfo) SSLDetails {
IsCertEV: info.IsCertEV,
IsCertEVSSL: info.IsCertEVSSL,
CertExpiration: info.CertExpiration.Format("2006-01-02"),
}
}, nil
}

// DecodeCert decodes a base64-encoded certificate stored in SSLDetails
Expand Down

0 comments on commit 945c3b6

Please sign in to comment.