c-hive.psm1

function Test-IsNumeric {
    <#
    .SYNOPSIS
    Returns if a specific value is numeric or not
    .EXAMPLE
    Test-IsNumeric -Value "1" # Returns $true
    Test-IsNumeric -Value "a" # Returns $false
    #>

    param(
        [Parameter(Mandatory = $true)]
        [string]$Value
    )

    Write-Verbose "Executing: Test-IsNumeric"
    return $Value.Trim() -match '^-?\d+$'
}
function Get-IsValidCsr{
    param($base64Csr)
    $pemHeader = "-----BEGIN CERTIFICATE REQUEST-----`n"
    $pemFooter = "`n-----END CERTIFICATE REQUEST-----"
    
    # Insert line breaks every 64 chars (optional but recommended)
    $wrappedCsr = ($base64Csr -split '(.{64})' | Where-Object {$_ -ne ''}) -join "`n"
    $pem = $pemHeader + $wrappedCsr + $pemFooter
   
    $stringReader = New-Object Org.BouncyCastle.Utilities.IO.Pem.PemReader([System.IO.StringReader]::new($pem))
    try {
        $csr = $stringReader.ReadPemObject()
        if ($csr.Type -eq "CERTIFICATE REQUEST") {
            return $true
        } else {
            return $false
        }
    } catch {
        return $false
    }
}

function Convert-CSR2Object{
    param($CSR)
     add-type -path ".\BouncyCastle.Cryptography.dll"
     $base64 = ($CSR -replace "-----.*-----", "") -replace "\s", ""
     $bytes = [Convert]::FromBase64String($base64)
     return [Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest]::new($bytes)
}

function Get-Subject{
    param($csr_object)
    $subject = $csr_object.GetCertificationRequestInfo().Subject
    $oids = $subject.GetOidList()
    $values = $subject.GetValueList()

    # Initialize empty hashtable
    $subjectHash = @{}

    for ($i = 0; $i -lt $oids.Count; $i++) {
        $oid = $oids[$i].Id
        $value = $values[$i].ToString()

        switch ($oid) {
            "2.5.4.3"                       { $subjectHash["CommonName"]                = $value }
            "2.5.4.10"                      { $subjectHash["Organization"]              = $value }
            "2.5.4.11"                      { $subjectHash["OrganizationalUnit"]        = $value }
            "2.5.4.6"                       { $subjectHash["Country"]                   = $value }
            "2.5.4.7"                       { $subjectHash["Locality"]                  = $value }
            "2.5.4.8"                       { $subjectHash["StateOrProvince"]           = $value }
            "2.5.4.9"                       { $subjectHash["StreetAddress"]             = $value }
            "1.2.840.113549.1.9.1"          { $subjectHash["EmailAddress"]              = $value }
            "0.9.2342.19200300.100.1.25"    { $subjectHash["DomainComponent"]           = $value }
            "0.9.2342.19200300.100.1.1"     { $subjectHash["UserID"]                    = $value }
            "2.5.4.12"                      { $subjectHash["Title"]                     = $value }
            "2.5.4.15"                      { $subjectHash["BusinessCategory"]          = $value }
            "2.5.4.17"                      { $subjectHash["PostalCode"]                = $value }
            "2.5.4.5"                       { $subjectHash["SerialNumber"]              = $value }
            "2.5.4.44"                      { $subjectHash["GenerationQualifier"]       = $value }
            "2.5.4.42"                      { $subjectHash["GivenName"]                 = $value }
            "2.5.4.4"                       { $subjectHash["Surname"]                   = $value }
            "2.5.4.43"                      { $subjectHash["Initials"]                  = $value }
            "2.5.4.65"                      { $subjectHash["Pseudonym"]                 = $value }
            "1.2.840.113549.1.9.2"          { $subjectHash["UnstructuredName"]          = $value }
            default                         { $subjectHash["OID_$oid"]                  = $value }
        }
    }

    # Create a clean output object
    $subjectObject = [pscustomobject]$subjectHash      
    return $subjectObject
}
 
function Get-SAN{
    param($csr_object)

    $extRequestOidString = "1.2.840.113549.1.9.14"
    $csr_object_attributes = $csr_object.GetCertificationRequestInfo().Attributes
    $sanEntries = @()
    foreach ($attr in $csr_object_attributes) {
        $oid = $attr[0] # DerObjectIdentifier
        if ($oid.Id -eq $extRequestOidString) {
            $values = $attr[1] # DerSet
            $extAsn1 = $values[0] # Extensions ASN.1 object
            $extensions = [Org.BouncyCastle.Asn1.X509.X509Extensions]::GetInstance($extAsn1)

            $sanOid = [Org.BouncyCastle.Asn1.X509.X509Extensions]::SubjectAlternativeName
            $sanExtension = $extensions.GetExtension($sanOid)

            if ($sanExtension -ne $null) {
                $generalNames = [Org.BouncyCastle.Asn1.X509.GeneralNames]::GetInstance($sanExtension.GetParsedValue())
                foreach ($generalName in $generalNames.GetNames()) {
                    $entry = [PSCustomObject]@{
                        TagNo = $generalName.TagNo
                        Type  = ""
                        Value = $null
                    }
                    switch ($generalName.TagNo) {
                        1 { # Email (RFC822Name)
                            $entry.Type = "Email"
                            $entry.Value = [string]$generalName.Name
                        }
                        2 { # DNS Name
                            $entry.Type = "DNS"
                            $entry.Value = [string]$generalName.Name
                        }
                        3 { # X400Address
                            $entry.Type = "X400Address"
                            $entry.Value = [string]$generalName.Name
                        }
                        4 { # DirectoryName
                            $entry.Type = "DirectoryName"
                            $entry.Value = [string]$generalName.Name
                        }
                        5 { # EdiPartyName
                            $entry.Type = "EdiPartyName"
                            $entry.Value = [string]$generalName.Name
                        }
                        6 { # UniformResourceIdentifier
                            $entry.Type = "URI"
                            $entry.Value = [string]$generalName.Name
                        }
                        7 { # IP Address
                            $entry.Type = "IPAddress"
                            $ipBytes = $generalName.Name.GetOctets()
                            $entry.Value = [System.Net.IPAddress]::new($ipBytes).ToString()
                        }
                        8 { # RegisteredID
                            $entry.Type = "RegisteredID"
                            $entry.Value = [string]$generalName.Name
                        }
                        default {
                            $entry.Type = "Other"
                            $entry.Value = [string]$generalName.Name
                        }
                    }
                    $sanEntries += $entry
                }
            }
        }
    }

    return ,@($sanEntries)


}




function Get-Key{
    param($csr_object)

    if ($Null -ne $csr_object.GetPublicKey().modulus)
    {
        #RSA
        $key = [PSCustomObject]@{
            Type = "RSA"
            Len  = $csr_object.GetPublicKey().modulus.bitlength
        }
    }
    else
    {
        #EC
        $key = [PSCustomObject]@{
            Type = "EC"
            Len  = $csr_object.GetPublicKey().parameters.curve.fieldSize
        }
    }
    return $key
}

function Get-KeyUsage{
    param($csr_object)
    $extRequestOidString = "1.2.840.113549.1.9.14"
    $csrAttributes = $csr_object.GetCertificationRequestInfo().Attributes
    $keyUsageResult = @()

    foreach ($attr in $csrAttributes) {
        $oid = $attr[0] # DerObjectIdentifier
        if ($oid.Id -eq $extRequestOidString) {
            $values = $attr[1] # DerSet
            $extAsn1 = $values[0] # ASN.1 encoded extensions
            $extensions = [Org.BouncyCastle.Asn1.X509.X509Extensions]::GetInstance($extAsn1)

            $keyUsageOid = [Org.BouncyCastle.Asn1.X509.X509Extensions]::KeyUsage
            $keyUsageExt = $extensions.GetExtension($keyUsageOid)

            if ($keyUsageExt -ne $null) {
                $keyUsage = [Org.BouncyCastle.Asn1.X509.KeyUsage]::GetInstance($keyUsageExt.GetParsedValue())
                $flags = $keyUsage.IntValue

                if ($flags -band [Org.BouncyCastle.Asn1.X509.KeyUsage]::DigitalSignature)    { $keyUsageResult += "DigitalSignature" }
                if ($flags -band [Org.BouncyCastle.Asn1.X509.KeyUsage]::NonRepudiation)      { $keyUsageResult += "NonRepudiation" }
                if ($flags -band [Org.BouncyCastle.Asn1.X509.KeyUsage]::KeyEncipherment)     { $keyUsageResult += "KeyEncipherment" }
                if ($flags -band [Org.BouncyCastle.Asn1.X509.KeyUsage]::DataEncipherment)    { $keyUsageResult += "DataEncipherment" }
                if ($flags -band [Org.BouncyCastle.Asn1.X509.KeyUsage]::KeyAgreement)        { $keyUsageResult += "KeyAgreement" }
                if ($flags -band [Org.BouncyCastle.Asn1.X509.KeyUsage]::KeyCertSign)         { $keyUsageResult += "KeyCertSign" }
                if ($flags -band [Org.BouncyCastle.Asn1.X509.KeyUsage]::CrlSign)             { $keyUsageResult += "CrlSign" }
                if ($flags -band [Org.BouncyCastle.Asn1.X509.KeyUsage]::EncipherOnly)        { $keyUsageResult += "EncipherOnly" }
                if ($flags -band [Org.BouncyCastle.Asn1.X509.KeyUsage]::DecipherOnly)        { $keyUsageResult += "DecipherOnly" }
            }
        }
    }




    return $keyUsageResult 
}
    
function Get-EnhancedKeyUsage{
    param ($csr_object)

    $ekuList = @()

    $extRequestOidString = "1.2.840.113549.1.9.14"
    $csrAttributes = $csr_object.GetCertificationRequestInfo().Attributes

     foreach ($attr in $csrAttributes) {
        $oid = $attr[0]
        if ($oid.Id -eq $extRequestOidString) {
            $values = $attr[1]
            $extAsn1 = $values[0]
            $extensions = [Org.BouncyCastle.Asn1.X509.X509Extensions]::GetInstance($extAsn1)

            $ekuOid = [Org.BouncyCastle.Asn1.X509.X509Extensions]::ExtendedKeyUsage
            $ekuExtension = $extensions.GetExtension($ekuOid)

            if ($ekuExtension -ne $null) {
                $eku = [Org.BouncyCastle.Asn1.X509.ExtendedKeyUsage]::GetInstance($ekuExtension.GetParsedValue())
                foreach ($keyPurposeId in $eku.GetAllUsages()) {
                    $oidString = $keyPurposeId.Id
                    $friendlyName = switch ($oidString) {
                        "1.3.6.1.5.5.7.3.1" { "Server Authentication" }
                        "1.3.6.1.5.5.7.3.2" { "Client Authentication" }
                        "1.3.6.1.5.5.7.3.3" { "Code Signing" }
                        "1.3.6.1.5.5.7.3.4" { "Email Protection" }
                        "1.3.6.1.5.5.7.3.8" { "Time Stamping" }
                        "1.3.6.1.5.5.7.3.9" { "OCSP Signing" }
                        "1.3.6.1.4.1.311.10.3.4" { "Encrypting File System" }
                        default { "Unknown EKU: $oidString" }
                    }
                    $ekuList += $friendlyName
                }
            }
        }
    }

    return $ekuList
}

function Get-CryptographicServiceProvider{
    param($csr_object)
    $cspList = @()
    $attributes = $csr_object.GetCertificationRequestInfo().Attributes
    $msCspOid = "1.3.6.1.4.1.311.13.2.2"

    foreach ($attr in $attributes) {
        $oid = $attr.AttrType
        if ($oid.Id -eq $msCspOid) {
            $attrValues = $attr.AttrValues

            foreach ($val in $attrValues) {
                $asn1Str = [Org.BouncyCastle.Asn1.DerUtf8String]::GetInstance($val)
                if ($asn1Str.GetString() -match "Provider\s*=") {
                    $provider = $asn1Str.GetString().Split("=")[1].Trim()
                    $cspList += $provider
                }
            }
        }
    }

    return $csrList

}

function Get-CertExtensions{
    param ($csr_object)

    $extensionsList = @()

    $attrs = $csr_object.GetCertificationRequestInfo().Attributes
    $extRequestOid = "1.2.840.113549.1.9.14"  # PKCS #9 extensionRequest OID

    foreach ($attr in $attrs) {
        if ($attr.AttrType.Id -eq $extRequestOid) {
            $attrValues = $attr.AttrValues
            foreach ($val in $attrValues) {
                # Get X509Extensions object from ASN1
                $exts = [Org.BouncyCastle.Asn1.X509.X509Extensions]::GetInstance($val)

                # Extract all extensions from X509Extensions
                $oids = $exts.GetExtensionOids()
                foreach ($oid in $oids) {
                    $extension = $exts.GetExtension($oid)
                    $oidStr = $oid.Id
                    try {
                        $extName = [Org.BouncyCastle.Asn1.X509.X509ExtensionUtilities]::GetExtensionName($oid)
                    } catch {
                        $extName = "Unknown"
                    }

                    $obj = [PSCustomObject]@{
                        ExtensionOID   = $oidStr
                        ExtensionName  = $extName
                        ExtensionValue = $extension
                    }
                    $extensionsList += $obj
                }
            }
        }
    }

    return $extensionsList

}


function Test-CSR {
    param (
        $csr
    )


    $result = [PSCustomObject]@{
            isValid = $false
            subject  = @()
            san = @()
            key = @()
            keyusage = @()
            EnhancedKeyUsage = @()
            CryptographicServiceProvider = @()
            CertExtensions = @()
            csr = $csr 
        }


    
    $result.isValid = Get-IsValidCsr -base64Csr $csr
   
    if ($result.isValid)
    {
        $csr_object = Convert-CSR2Object -CSR $csr
        $result.subject = get-subject $csr_object
        $result.san = get-san $csr_object
        $result.key = get-key -csr_object $csr_object
        $result.keyusage = get-keyusage -csr_object $csr_object
        $result.EnhancedKeyUsage = Get-EnhancedKeyUsage -csr_object $csr_object
        $result.CryptographicServiceProvider = Get-CryptographicServiceProvider -csr_object $csr_object
        $result.CertExtensions = Get-CertExtensions -csr_object $csr_object
    }
   
    return $result


}



Export-ModuleMember *


# SIG # Begin signature block
# MIIFfwYJKoZIhvcNAQcCoIIFcDCCBWwCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDRJGPsoBLWT59s
# 9IgGICeR70fUBIA52fAxx18oZCcNWqCCAvwwggL4MIIB4KADAgECAhARXeApLbab
# i0U384S48TtIMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCHZpdmFYaXRlMCAX
# DTI1MDUyNjA5NTEyN1oYDzIxMjQwNTI2MTAwMTI4WjATMREwDwYDVQQDDAh2aXZh
# WGl0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL65W+H9E82gU7ZH
# /XSJbAxPvFtzHVRoUHA045konf474KBkaDc4ztYlgRvkZldzFykjg8jeuSa0ANlm
# VX1HoObUVYagSax/fWPSOkqDN4aTolX8GaI98ZOey9a9OYUI3F5mznkeksWUqbT7
# cgCX2Y/Qtnh557nSuplxmmtTGEzrDzj5evvnAyGGH1mcJxD3DeJGv3olsK9J982q
# 0s+t9bCSSWPx2vapiR9VmCTKZJMi4YlNXrM+UFEd7R1KQR5M/KPY+rg5UJ0kU8Hz
# q0z9z6L3mbk+b28uI9EwGbvuXPtqUCi5P9YrdpKjOR16kaBJ9Od1+mphUaxNfc75
# eb8Uzd0CAwEAAaNGMEQwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUF
# BwMDMB0GA1UdDgQWBBQjLXXsxxmYhIvcsrZywbsrsjn9ajANBgkqhkiG9w0BAQsF
# AAOCAQEAtVY7rYwe8G/F+95Lc47UpZD1ICAg/sS/yRZjKhoos/iufKV478RsZyDX
# dAj5unm7XqGZSAyW4hHOdWYQdF//emNpXyOmNSkPuwpebhKtAwddvUwlGzFbsh4g
# 5ULVgmvnf2J3eqKQpOulecCH8MJqCrRAi8pgBjl5/cmr6ZMULLAswmEkCTNgvx7g
# qVFvJ+Zcbxu2gOiA9EzTzMWM8thrkOGWYYu/i0b63BxKXAenkBKJtjugFb2iefGb
# mhfcelCGo/Gx7XD7AdYM3ov5YTYpnTDmCCTch9dR8vz7FPgwV0HPYfIZ1b1INC4y
# C6I3Hf8ZXMzquofQpd9zlu7qqnKF/DGCAdkwggHVAgEBMCcwEzERMA8GA1UEAwwI
# dml2YVhpdGUCEBFd4CkttpuLRTfzhLjxO0gwDQYJYIZIAWUDBAIBBQCggYQwGAYK
# KwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIB
# BDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQg
# UJFUUTfEroe+IoHjA9kQPfyCJLONG0n9h8JnrvNiw6wwDQYJKoZIhvcNAQEBBQAE
# ggEASAYf8iel3eEl800nCOEJIHZqxYl8bfwm2wpl0nN42zLQ428JCG48SoydVMxS
# +vihJa20VhrwyFe1qGxV8NQealb6AJodu83HBfA+nLgbx4d2RyaYYLCjz86OfLzj
# XizlVPepJd9raFqqxH2uE9xw0H3uVLQr2C8frO3+IWnSEI/FLKyKt3KATSeRCXP4
# OYrACCLyHF0BBOG9r0g7Ajhwqvn2eSQwXsErDQdV7oikNI4bEwontJQSMaAinzAd
# WPqWa+Jv6O1lf4ZO0p15zoIo3Ha8LyDVf82tZg6i/gIHvB12myiteOrS42FgucRg
# pU3Z65Dj/2vUiu/7zLznj0tQog==
# SIG # End signature block