hcrudolph / ciphersuite.info

A searchable directory of TLS ciphersuites and related security details.
https://ciphersuite.info
MIT License
80 stars 14 forks source link

Mismatch between provided API results. #214

Open SunsparcSolaris opened 7 months ago

SunsparcSolaris commented 7 months ago

I'm hoping this is just user error but I've noticed a mismatch between what information is provided from the "all ciphers" endpoint and the specific cipher endpoint.

I'm attempting to write a script in Powershell that ForEach's through cipher suites from a server and looks up their security rating. Instead of making hundreds of calls to the API, I made a single to call to https://ciphersuite.info/api/cs and stored that output in a variable object so that I can perform lookups locally. The formatting is a little weird, I had to specify the CipherSuites property and then Expand the underlying objects.

$AllCiphers = (Invoke-RestMethod https://ciphersuite.info/api/cs).CipherSuites | Select-Object -ExpandProperty *

If I attempt to look up a cipher suite in the stored object, I get no results:

$AllCiphers | Where-Object {$_.openssl_name -eq "TLS_RSA_WITH_AES_256_GCM_SHA384"}

But if I look up the cipher directly on the api endpoint, I get results:

Invoke-RestMethod https://ciphersuite.info/api/cs/TLS_RSA_WITH_AES_256_GCM_SHA384 | Select-Object -Expand *

Again, it's weirdly formatted. The "friendly name" does not match the gnutls_name nor the openssl_name.

skint007 commented 5 months ago

I did a very similar thing for our environment.

I think the thing that makes it difficult is how PowerShell converts it to a PSCustomObject. Each cipher comes back with a NoteProperty as the name of the cipher, that then is a PSCustomObject itself.

$ApiBase = "https://ciphersuite.info/api/cs"
$response = Invoke-RestMethod $ApiBase
$response.ciphersuites[0] | gm

Will output

   TypeName: System.Management.Automation.PSCustomObject

Name                     MemberType   Definition
----                     ----------   ----------
Equals                   Method       bool Equals(System.Object obj)
GetHashCode              Method       int GetHashCode()
GetType                  Method       type GetType()
ToString                 Method       string ToString()
TLS_AES_128_CCM_8_SHA256 NoteProperty System.Management.Automation.PSCustomObject TLS_AES_128_CCM_8_SHA256=@{gnutls_...

I'm not sure if this is the most efficient way to do this, but you could try doing something like this

$response.ciphersuites | Where-Object { $_.PSObject.Properties.Name -eq 'TLS_RSA_WITH_AES_256_GCM_SHA384' } | Select-Object -ExpandProperty *

You will get the resulting PSCustomObject

gnutls_name      : TLS_RSA_AES_256_GCM_SHA384
openssl_name     : AES256-GCM-SHA384
hex_byte_1       : 0x00
hex_byte_2       : 0x9D
protocol_version : TLS
kex_algorithm    : RSA
auth_algorithm   : RSA
enc_algorithm    : AES 256 GCM
hash_algorithm   : SHA384
security         : weak
tls_version      : {TLS1.2, TLS1.3}

Hope this helps.

SunsparcSolaris commented 5 months ago

I did a very similar thing for our environment.

I think the thing that makes it difficult is how PowerShell converts it to a PSCustomObject. Each cipher comes back with a NoteProperty as the name of the cipher, that then is a PSCustomObject itself.

$ApiBase = "https://ciphersuite.info/api/cs"
$response = Invoke-RestMethod $ApiBase
$response.ciphersuites[0] | gm

Will output

   TypeName: System.Management.Automation.PSCustomObject

Name                     MemberType   Definition
----                     ----------   ----------
Equals                   Method       bool Equals(System.Object obj)
GetHashCode              Method       int GetHashCode()
GetType                  Method       type GetType()
ToString                 Method       string ToString()
TLS_AES_128_CCM_8_SHA256 NoteProperty System.Management.Automation.PSCustomObject TLS_AES_128_CCM_8_SHA256=@{gnutls_...

I'm not sure if this is the most efficient way to do this, but you could try doing something like this

$response.ciphersuites | Where-Object { $_.PSObject.Properties.Name -eq 'TLS_RSA_WITH_AES_256_GCM_SHA384' } | Select-Object -ExpandProperty *

You will get the resulting PSCustomObject

gnutls_name      : TLS_RSA_AES_256_GCM_SHA384
openssl_name     : AES256-GCM-SHA384
hex_byte_1       : 0x00
hex_byte_2       : 0x9D
protocol_version : TLS
kex_algorithm    : RSA
auth_algorithm   : RSA
enc_algorithm    : AES 256 GCM
hash_algorithm   : SHA384
security         : weak
tls_version      : {TLS1.2, TLS1.3}

Hope this helps.

I ended up creating something incredibly hackish but serves the purposes I needed it to, which was get the server cipher, look it up, and provide the strength.

$ServerOutput = invoke-command -ComputerName $allservers -ErrorAction SilentlyContinue -ScriptBlock {
    $get = Get-TlsCipherSuite 
    [PSCustomObject] $get
}

$output = @()
$get = Get-TlsCipherSuite 
$CipherOutput = [PSCustomObject] $get
ForEach ($entry in $CipherOutput) {
    If ($entry.Name -like "*SHA*_P*") {
        $BuildString = ($($entry.name).substring(0, $($entry.name).lastindexof("_"))).Replace("WITH_","")
        $CipherLookup = $AllCiphers | Where {$_.gnutls_name -like $BuildString}
    }
    ElseIf ($entry.Name -like "*_SHA") {
        $BuildString = ($($entry.name).substring(0, $($entry.name).lastindexof("_"))+"_SHA1").Replace("WITH_","")
        $CipherLookup = $AllCiphers | Where {$_.gnutls_name -like $BuildString}
    }
    ElseIf ($entry.Name -like "*WITH*") {
        $CipherLookup = $AllCiphers | Where {$_.gnutls_name -like $($entry.name).Replace("WITH_","")}
    }
    Else {
        $CipherLookup = $AllCiphers | Where {$_.gnutls_name -like $($entry.name) -or $_.openssl_name -like $($entry.name)}
    }
    $output += [PSCustomObject] @{
        Server = $env:computername
        CipherServerName = $entry.name
        CipherOpenSSLName = If ($CipherLookup.gnutls_name) { $CipherLookup.gnutls_name } Else {$CipherLookup.openssl_name}
        Security = $CipherLookup.security
    }
}
foreach ($line in $ServerOutput) {
    If ($line.Name -like "*SHA*_P*") {
        $BuildString = ($($line.name).substring(0, $($line.name).lastindexof("_"))).Replace("WITH_","")
        $CipherLookup = $AllCiphers | Where {$_.gnutls_name -like $BuildString}
    }
    ElseIf ($line.Name -like "*_SHA") {
        $BuildString = ($($line.name).substring(0, $($line.name).lastindexof("_"))+"_SHA1").Replace("WITH_","")
        $CipherLookup = $AllCiphers | Where {$_.gnutls_name -like $BuildString}
    }
    ElseIf ($line.Name -like "*WITH*") {
        $CipherLookup = $AllCiphers | Where {$_.gnutls_name -like $($line.name).Replace("WITH_","")}
    }
    Else {
        $CipherLookup = $AllCiphers | Where {$_.gnutls_name -like $($line.name) -or $_.openssl_name -like $($line.name)}
    }
    $output += [PSCustomObject] @{
        Server = $line.pscomputername
        CipherServerName = $line.name
        CipherOpenSSLName = If ($CipherLookup.gnutls_name) { $CipherLookup.gnutls_name } Else {$CipherLookup.openssl_name}
        Security = $CipherLookup.security
    }
}