bmc icon indicating copy to clipboard operation
bmc copied to clipboard

Issues with RetrieveSupportedCipherSuites

Open lukeyeager opened this issue 2 years ago • 4 comments

I noticed today that I was failing to scrape a lot of nodes with errors like this:

create session error: none of the provided cipher suite options were supported by the BMC

When I switched from NewSesssion to NewV2Session explicitly setting CipherSuites: []ipmi.CipherSuite{ipmi.CipherSuite17}, things got much better! I can now scrape ~260 nodes intead of ~180 nodes. image

  1. That shouldn't have helped. The default suite list is [17,3], so RetrieveSupportedCipherSuites should have successfully determined that suite 17 was ok to use.
  2. After using the exporter in the new mode (explicitly setting cipher suite 17) for a few minutes, I reverted the code back to the old code and now those 80 nodes are still working properly. I'm saying that when I skip the RetrieveSupportedCipherSuites once, it puts the BMC into a new state where your library can now run RetrieveSupportedCipherSuites without errors. I don't understand that.
  3. Annoyingly, whenever I use RetrieveSupportedCipherSuites, useful error messages such as RAKP2 HMAC fail (this indicates the BMC is using a different password) are masked, and the library prints an error about unsupported cipher suites intead

lukeyeager avatar Aug 29 '23 19:08 lukeyeager

1 and 2 will need more work. 3 sounds fixable, but can I clarify: RetrieveSupportedCipherSuites() is by definition a sessionless operation; is it that you're getting the RAKP2 HMAC fail after using the result(s) returned by RetrieveSupportedCipherSuites()?

gebn avatar Sep 16 '23 18:09 gebn

Does this example answer your question? I'm noticing today that I sometimes get other errors, too, when I fail to specify the CipherSuite - not only "none of the provided cipher suite options were supported by the BMC".

$ go run ./... "${host}" "${ipmiuser}" "${ipmipw}"
2023/09/18 08:26:22 Connecting with CipherSuites=[]ipmi.CipherSuite{} ...
2023/09/18 08:26:22 new session: none of the provided cipher suite options were supported by the BMC
2023/09/18 08:26:22 Connecting with CipherSuites=[]ipmi.CipherSuite{ipmi.CipherSuite{AuthenticationAlgorithm:0x3, IntegrityAlgorithm:0x4, ConfidentialityAlgorithm:0x1}} ...
2023/09/18 08:26:22 Success.

$ go run ./... "${host}" "${ipmiuser}" "${ipmipw}"
2023/09/18 08:29:09 Connecting with CipherSuites=[]ipmi.CipherSuite{} ...
2023/09/18 08:29:09 new session: expected start of record, got 0x0
2023/09/18 08:29:09 Connecting with CipherSuites=[]ipmi.CipherSuite{ipmi.CipherSuite{AuthenticationAlgorithm:0x3, IntegrityAlgorithm:0x4, ConfidentialityAlgorithm:0x1}} ...
2023/09/18 08:29:09 Success.
package main

import (
        "context"
        "log"
        "os"
        "time"

        "github.com/gebn/bmc"
        "github.com/gebn/bmc/pkg/ipmi"
)

func connect(transport *bmc.V2SessionlessTransport, user, pw string, cipherSuites []ipmi.CipherSuite) {
        log.Printf("Connecting with CipherSuites=%#v ...", cipherSuites)
        ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
        defer cancel()
        session, err := transport.NewV2Session(ctx, &bmc.V2SessionOpts{
                SessionOpts: bmc.SessionOpts{
                        Username:          user,
                        Password:          []byte(pw),
                        MaxPrivilegeLevel: ipmi.PrivilegeLevelUser,
                },
                CipherSuites: cipherSuites,
        })
        if err != nil {
                log.Printf("new session: %v", err)
        } else {
                log.Printf("Success.")
                ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
                defer cancel()
                if err := session.Close(ctx); err != nil {
                        log.Printf("close session: %v", err)
                }
        }
}

func main() {
        host := os.Args[1]
        user := os.Args[2]
        pw := os.Args[3]

        transport, err := bmc.DialV2(host)
        if err != nil {
                log.Fatalf("dial: %v", err)
        }
        defer transport.Close()

        connect(transport, user, pw, []ipmi.CipherSuite{})
        connect(transport, user, pw, []ipmi.CipherSuite{ipmi.CipherSuite17})
}

lukeyeager avatar Sep 18 '23 15:09 lukeyeager

I'm very willing to believe that (1) and (2) are just badly-behaved BMCs. Happy to send a ipmitool -v trace to you if there's anything I can run which would help you verify that this library is working fine (possibly ipmitool channel getciphers ipmi 1?).

lukeyeager avatar Sep 18 '23 16:09 lukeyeager

The ipmitool output for both would be interesting, however I'm not sure 1 is the correct channel value. Does it accept channel 14 (present interface)? The first response breaks the spec in that suite 3 is essential, and the second should never return 0x00 as the first byte of a cipher suite record. I'll try to reproduce this and see what's going on.

If only one suite is passed when creating the session, we bypass Get Channel Cipher Suites entirely, which will be why those are working. If ipmitool is making some assumptions, or being more aggressive with discovery, we should probably emulate that to ensure compatibility - it's more important to be useful than correct. I'll try to reproduce this and see what's going on.

For 3, can you provide a code sample - I'm still confused how RetrieveSupportedCipherSuites() could lead to RAKP2 HMAC fail, unless it's suggesting the BMC supports something it doesn't, which is then causing the HMAC error during session establishment.

gebn avatar Sep 22 '23 22:09 gebn