-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathclient_auth_code.go
360 lines (298 loc) · 11.2 KB
/
client_auth_code.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
package ipmi
import (
"crypto/md5"
"fmt"
"github.com/bougou/go-ipmi/utils/md2"
)
// When the HMAC-SHA1-96 Integrity Algorithm is used the resulting AuthCode field is 12 bytes (96 bits).
// When the HMAC-SHA256-128 and HMAC-MD5-128 Integrity Algorithms are used the resulting AuthCode field is 16-bytes (128 bits).
func (c *Client) genIntegrityAuthCode(input []byte) ([]byte, error) {
switch c.session.v20.integrityAlg {
case IntegrityAlg_None:
// If the Integrity Algorithm is none the AuthCode value is not calculated and
// the AuthCode field in the message is not present (zero bytes).
return []byte{}, nil
case IntegrityAlg_MD5_128:
data := []byte{}
data = append(data, []byte(c.Password)[:]...)
data = append(data, input...)
data = append(data, []byte(c.Password)[:]...)
h := md5.Sum(data)
return h[:], nil
case IntegrityAlg_HMAC_MD5_128:
b, err := generate_hmac("md5", input, c.session.v20.k1)
if err != nil {
return nil, fmt.Errorf("generate hmac failed")
}
return b[0:16], nil
case IntegrityAlg_HMAC_SHA1_96:
b, err := generate_hmac("sha1", input, c.session.v20.k1)
if err != nil {
return nil, fmt.Errorf("generate hmac failed")
}
return b[0:12], nil
case IntegrityAlg_HMAC_SHA256_128:
b, err := generate_hmac("sha256", input, c.session.v20.k1)
if err != nil {
return nil, fmt.Errorf("generate hmac failed")
}
return b[0:16], nil
default:
return nil, fmt.Errorf("not support for integrity algorithm %x", c.session.v20.integrityAlg)
}
}
func (c *Client) generateAuthCodeForSingleSession() []byte {
authCodeInputLength := 16 +
4 + // temp session od uint32
len(c.session.v15.challenge) +
16
var input = make([]byte, authCodeInputLength)
packBytes(c.passwordPad16, input, 0)
packUint32L(c.session.v15.sessionID, input, 16)
packBytes(c.session.v15.challenge[:], input, 20)
packBytes(c.passwordPad16, input, 20+len(c.session.v15.challenge))
// generate AuthCode carried in IPMI message data for Activate Session Command
// see 22.17.1 AuthCode Algorithms
// Table 22-, AuthCode Algorithms
authCode := []byte{}
switch c.session.authType {
case AuthTypePassword:
authCode = c.passwordPad16
case AuthTypeMD2:
authCode = md2.New().Sum(input)
case AuthTypeMD5:
authCode = md5.New().Sum(input)
}
return authCode
}
// sessionID should be the Temporary Session ID when calculating the AuthCode for the initial Activate Session command.
//
// only be used for ActivateSession (IPMI v1.5)
// see 22.17
//
// generate AuthCode carried in IPMI message data for Activate Session Command
// see 22.17.1 AuthCode Algorithms
// Table 22-, AuthCode Algorithms
func (c *Client) genAuthCodeForMultiSession(ipmiMsg []byte) []byte {
// The Integrity Algorithm Number specifies the algorithm used to generate the contents
// for the AuthCode signature field that accompanies authenticated IPMI v2.0/RMCP+ messages once the session has been
// established.
// Unless otherwise specified, the integrity algorithm is applied to the packet data starting with the
// AuthType/Format field up to and including the field that immediately precedes the AuthCode field itself.
authCodeInputLength := len(c.passwordPad16) +
4 + // session od uint32
len(ipmiMsg) +
4 + // session seq uint32
len(c.passwordPad16)
var input = make([]byte, authCodeInputLength)
packBytes(c.passwordPad16, input, 0)
packUint32L(c.session.v15.sessionID, input, 16)
packBytes(ipmiMsg, input, 48)
packUint32L(c.session.v15.inSeq, input, 48+len(ipmiMsg))
packBytes(c.passwordPad16, input, 48+len(ipmiMsg)+32)
c.DebugBytes("gen authcode input", input, 16)
var authCode []byte
switch c.session.authType {
case AuthTypePassword:
authCode = c.passwordPad16
case AuthTypeMD2:
authCode = md2.New().Sum(input)
authCode = authCode[:16]
case AuthTypeMD5:
c := md5.Sum(input)
authCode = c[:]
}
c.DebugBytes("gen authcode", authCode, 16)
return authCode[:16]
}
// sik (Session Integrite Key)
// both the remote console and the managed system generate sik by using the same hmackey and hmac data.
// so they should be same.
// see 13.31
func (c *Client) generate_sik() ([]byte, error) {
input := make([]byte, 34+len(c.Username))
packBytes(c.session.v20.consoleRand[:], input, 0) // 16 bytes
packBytes(c.session.v20.bmcRand[:], input, 16) // 16 bytes
packUint8(c.session.v20.role, input, 32) // 1 bytes, Requested privilege level (entire byte)
packUint8(uint8(len(c.Username)), input, 33) // 1 bytes, Username length
packBytes([]byte(c.Username), input, 34) // N bytes, Usename (absent for null usernames)
c.DebugBytes("sik mac input", input, 16)
var hmacKey []byte
if len(c.session.v20.bmcKey) != 0 {
hmacKey = c.session.v20.bmcKey
} else {
hmacKey = c.passwordPad20
}
c.DebugBytes("sik mac key", hmacKey, 16)
b, err := generate_auth_hmac(c.session.v20.authAlg, input, hmacKey)
if err != nil {
return nil, fmt.Errorf("generate hmac failed, err: %s", err)
}
c.DebugBytes("sik mac computed by the remote console:", b, 16)
return b, nil
}
// see 13.32 Generating Additional Keying Material
//
// generate K1 key, the session integrity key (SIK) is used as hmac key.
func (c *Client) generate_k1() ([]byte, error) {
var CONST_1 = [20]byte{
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
}
if c.session.v20.sik == nil {
return nil, fmt.Errorf("sik not exists, generate sik first")
}
hmacKey := c.session.v20.sik
b, err := generate_auth_hmac(c.session.v20.authAlg, CONST_1[:], hmacKey)
if err != nil {
return nil, fmt.Errorf("generate hmac failed, err: %s", err)
}
c.DebugBytes("generated k1:", b, 16)
return b, nil
}
// see 13.32 Generating Additional Keying Material
//
// generate K2 key, the session integrity key (SIK) is used as hmac key.
func (c *Client) generate_k2() ([]byte, error) {
var CONST_2 = [20]byte{
0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02,
}
if c.session.v20.sik == nil {
return nil, fmt.Errorf("sik not exists, generate sik first")
}
hmacKey := c.session.v20.sik
b, err := generate_auth_hmac(c.session.v20.authAlg, CONST_2[:], hmacKey)
if err != nil {
return nil, fmt.Errorf("generate hmac failed, err: %s", err)
}
c.DebugBytes("generated k2:", b, 16)
return b, nil
}
// used for verify rakp2
func (c *Client) generate_rakp2_authcode() ([]byte, error) {
c.DebugBytes("bmc rand", c.session.v20.bmcRand[:], 16)
bufferLen := 4 + 4 + 16 + 16 + 16 + 1 + 1 + len(c.Username)
var buffer = make([]byte, bufferLen)
packUint32L(c.session.v20.consoleSessionID, buffer, 0) // 4 bytes, Console session ID (SID)
packUint32L(c.session.v20.bmcSessionID, buffer, 4) // 4 bytes, bmc session ID (SID)
packBytes(c.session.v20.consoleRand[:], buffer, 8) // 16 bytes, Remote console random number
packBytes(c.session.v20.bmcRand[:], buffer, 24) // 16 bytes, BMC random number (RC)
packBytes(c.session.v20.bmcGUID[:], buffer, 40) // 16 bytes, BMC guid
packUint8(c.session.v20.role, buffer, 56) // 1 bytes, entire byte of privilegelevel of rakp1
packUint8(uint8(len(c.Username)), buffer, 57) // 1 bytes, Username length
packBytes([]byte(c.Username), buffer, 58) // N bytes, Usename (absent for null usernames)
c.DebugBytes("rakp2 authcode input", buffer, 16)
// The bmc also use user password to caculate authcode, so if the authcode does not match,
// it may indicates the password is no right.
hmacKey := []byte(c.passwordPad20)
// Todo, pading to 20 bytes
c.DebugBytes("rakp2 authcode key", hmacKey, 16)
b, err := generate_auth_hmac(c.session.v20.authAlg, buffer, hmacKey)
if err != nil {
return nil, fmt.Errorf("generate hmac failed, err: %s", err)
}
c.DebugBytes("rakp2 generated authcode", b, 16)
var out = b
switch c.session.v20.authAlg {
case AuthAlgRAKP_None:
// nothing need to do
case AuthAlgRAKP_HMAC_MD5:
// need to copy 16 bytes
if len(b) < 16 {
err = fmt.Errorf("cc")
}
out = b[0:16]
case AuthAlgRAKP_HMAC_SHA1:
// need to copy 20 bytes
if len(b) < 20 {
err = fmt.Errorf("cc")
}
out = b[0:20]
case AuthAlgRAKP_HMAC_SHA256:
if len(b) < 32 {
err = fmt.Errorf("cc")
}
out = b[0:32]
default:
err = fmt.Errorf("rakp2 message: no support for authentication algorithm 0x%x", c.session.v20.authAlg)
}
c.DebugBytes("rakp2 used authcode", out, 16)
return out, err
}
// 22.17.1 AuthCode Algorithms
func (c *Client) generate_rakp3_authcode() ([]byte, error) {
// The auth code is an HMAC generated with the following content
var input []byte = []byte{}
input = append(input, c.session.v20.bmcRand[:]...) // 16 bytes, BMC random number (RC)
buffer := make([]byte, 4)
packUint32L(c.session.v20.consoleSessionID, buffer, 0)
input = append(input, buffer...) // 4 bytes, Console session ID (SID)
input = append(input, byte(c.session.v20.role)) // 1 bytes, Requested privilege level (entire byte)
input = append(input, byte(len([]byte(c.Username)))) // 1 bytes, Username length
input = append(input, []byte(c.Username)...) // N bytes, Usename (absent for null usernames)
c.DebugBytes("rakp3 auth code input", input, 16)
hmacKey := []byte(c.passwordPad20)
c.DebugBytes("rakp3 auth code key", hmacKey, 16)
b, err := generate_auth_hmac(c.session.v20.authAlg, input, hmacKey)
if err != nil {
return nil, fmt.Errorf("generate hmac failed, err: %s", err)
}
c.DebugBytes("rakp3 generated authcode", b, 16)
var out = b
c.DebugBytes("rakp3 used authcode", out, 16)
return out, err
}
// 13.31 RMCP+ Authenticated Key-Exchange Protocol (RAKP)
// 13.28
// the client use this method to verify the authcode returned in rakp4
func (c *Client) generate_rakp4_authcode() ([]byte, error) {
var input []byte = []byte{}
input = append(input, c.session.v20.consoleRand[:]...) // 16 bytes, Console random number
buffer := make([]byte, 4)
packUint32L(c.session.v20.bmcSessionID, buffer, 0)
input = append(input, buffer...) // 4 bytes, BMC session ID (SID)
input = append(input, c.session.v20.bmcGUID[:]...) // 16 bytes
c.DebugBytes("rakp4 auth code input", input, 16)
hmacKey := c.session.v20.sik
c.DebugBytes("rakp4 auth code key", hmacKey, 16)
b, err := generate_auth_hmac(AuthAlg(c.session.v20.integrityAlg), input, hmacKey)
if err != nil {
return nil, fmt.Errorf("generate hmac failed, err: %s", err)
}
c.DebugBytes("rakp4 generated authcode", b, 16)
var errHmacLen = func(length int, integrityAlg IntegrityAlg) error {
return fmt.Errorf("the length of generated mac is not long enough, should be at least (%d) for integrity algorithm (%0x)", len(b), integrityAlg)
}
var out = b
integrityAlg := c.session.v20.integrityAlg
switch integrityAlg {
case IntegrityAlg_None:
// nothing need to do
case IntegrityAlg_HMAC_MD5_128:
// need to copy 16 bytes
if len(b) < 16 {
err = errHmacLen(len(b), integrityAlg)
}
out = b[0:16]
case IntegrityAlg_HMAC_SHA1_96:
// need to copy 12 bytes
if len(b) < 12 {
err = errHmacLen(len(b), integrityAlg)
}
out = b[0:12]
case IntegrityAlg_HMAC_SHA256_128:
if len(b) < 16 {
err = errHmacLen(len(b), integrityAlg)
}
out = b[0:16]
default:
err = fmt.Errorf("rakp4 message: no support for integrity algorithm %x", c.session.v20.integrityAlg)
}
c.DebugBytes("rakp4 used authcode", out, 16)
return out, err
}