forked from bougou/go-ipmi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cmd_get_channel_cipher_suites.go
147 lines (126 loc) · 4.23 KB
/
cmd_get_channel_cipher_suites.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package ipmi
import (
"fmt"
)
const (
MaxCipherSuiteListIndex uint8 = 0x3f
)
// 22.15 Get Channel Cipher Suites Command
type GetChannelCipherSuitesRequest struct {
ChannelNumber uint8 // Eh = retrieve information for channel this request was issued on
PayloadType PayloadType
ListIndex uint8
}
type GetChannelCipherSuitesResponse struct {
ChannelNumber uint8
CipherSuiteRecords []byte
}
func (req *GetChannelCipherSuitesRequest) Command() Command {
return CommandGetChannelCipherSuites
}
func (req *GetChannelCipherSuitesRequest) Pack() []byte {
var msg = make([]byte, 3)
packUint8(req.ChannelNumber, msg, 0)
packUint8(uint8(req.PayloadType), msg, 1)
packUint8(LIST_ALGORITHMS_BY_CIPHER_SUITE|req.ListIndex, msg, 2)
return msg
}
func (res *GetChannelCipherSuitesResponse) Unpack(msg []byte) error {
if len(msg) < 1 {
return ErrUnpackedDataTooShort
}
res.ChannelNumber, _, _ = unpackUint8(msg, 0)
if len(msg) > 1 {
res.CipherSuiteRecords, _, _ = unpackBytesMost(msg, 1, 16)
}
return nil
}
func (*GetChannelCipherSuitesResponse) CompletionCodes() map[uint8]string {
// no command-specific cc
return map[uint8]string{}
}
func (res *GetChannelCipherSuitesResponse) Format() string {
return fmt.Sprintf("%v", res)
}
// This command can be executed prior to establishing a session with the BMC.
// The command is used to look up what authentication, integrity, and confidentiality algorithms are supported.
// The algorithms are used in combination as 'Cipher Suites'.
// This command only applies to implementations that support IPMI v2.0/RMCP+ sessions.
func (c *Client) GetChannelCipherSuites(channelNumber uint8, index uint8) (response *GetChannelCipherSuitesResponse, err error) {
request := &GetChannelCipherSuitesRequest{
ChannelNumber: channelNumber,
PayloadType: PayloadTypeIPMI,
ListIndex: index,
}
response = &GetChannelCipherSuitesResponse{}
err = c.Exchange(request, response)
return
}
// GetAllChannelCipherSuites initiates 64 (MaxCipherSuiteListIndex) requests
func (c *Client) GetAllChannelCipherSuites(channelNumber uint8) ([]CipherSuiteRecord, error) {
var index uint8 = 0
var cipherSuitesData = make([]byte, 0)
for ; index < MaxCipherSuiteListIndex; index++ {
res, err := c.GetChannelCipherSuites(channelNumber, index)
if err != nil {
return nil, fmt.Errorf("cmd GetChannelCipherSuites failed, err: %s", err)
}
cipherSuitesData = append(cipherSuitesData, res.CipherSuiteRecords...)
if len(res.CipherSuiteRecords) < 16 {
break
}
}
c.DebugBytes("cipherSuitesData", cipherSuitesData, 16)
return parseCipherSuitesData(cipherSuitesData)
}
func parseCipherSuitesData(cipherSuitesData []byte) ([]CipherSuiteRecord, error) {
offset := 0
records := []CipherSuiteRecord{}
for offset < len(cipherSuitesData) {
csRecord := CipherSuiteRecord{}
startOfRecord := cipherSuitesData[offset]
csRecord.StartOfRecord = startOfRecord
switch startOfRecord {
case StandardCipherSuite:
// id + 3 algs (4 bytes)
if offset+4 > len(cipherSuitesData)-1 {
return records, fmt.Errorf("incomplete cipher suite data")
}
offset++
csRecord.CipherSuitID = cipherSuitesData[offset]
case OEMCipherSuite:
// id + iana (3) + 3 algs (7 bytes)
if offset+7 > len(cipherSuitesData)-1 {
return records, fmt.Errorf("incomplete cipher suite data")
}
offset++
csRecord.CipherSuitID = cipherSuitesData[offset]
offset++
csRecord.OEMIanaID, _, _ = unpackUint24L(cipherSuitesData, offset)
default:
return records, fmt.Errorf("bad start of record byte in the cipher suite data, vlalue %x", startOfRecord)
}
for {
offset++
if offset > len(cipherSuitesData)-1 {
break
}
algByte := cipherSuitesData[offset]
if algByte == StandardCipherSuite || algByte == OEMCipherSuite {
break
}
algTag := algByte & CipherAlgTagBitMask // clear lowerest 6 bits
algNumber := algByte & CipherAlgMask // clear highest 2 bits
switch algTag {
case CipherAlgTagBitAuthMask:
csRecord.AuthAlg = algNumber
case CipherAlgTagBitInegrityMask:
csRecord.IntegrityAlgs = append(csRecord.IntegrityAlgs, algNumber)
case CipherAlgTagBitEncryptionMask:
csRecord.CryptAlgs = append(csRecord.CryptAlgs, algNumber)
}
}
records = append(records, csRecord)
}
return records, nil
}