~ubuntu-branches/ubuntu/karmic/openipmi/karmic

« back to all changes in this revision

Viewing changes to lib/rakp.c

  • Committer: Bazaar Package Importer
  • Author(s): Noèl Köthe
  • Date: 2005-07-04 21:29:17 UTC
  • Revision ID: james.westby@ubuntu.com-20050704212917-igddk5jawjmhrlay
Tags: upstream-2.0.1
Import upstream version 2.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * rakp.c
 
3
 *
 
4
 * MontaVista RMCP+ code for handling RAKP algorithms
 
5
 *
 
6
 * Author: MontaVista Software, Inc.
 
7
 *         Corey Minyard <minyard@mvista.com>
 
8
 *         source@mvista.com
 
9
 *
 
10
 * Copyright 2004 MontaVista Software Inc.
 
11
 *
 
12
 *  This program is free software; you can redistribute it and/or
 
13
 *  modify it under the terms of the GNU Lesser General Public License
 
14
 *  as published by the Free Software Foundation; either version 2 of
 
15
 *  the License, or (at your option) any later version.
 
16
 *
 
17
 *
 
18
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
19
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
20
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
21
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
22
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 
23
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 
24
 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
25
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 
26
 *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 
27
 *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
28
 *
 
29
 *  You should have received a copy of the GNU Lesser General Public
 
30
 *  License along with this program; if not, write to the Free
 
31
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
32
 */
 
33
 
 
34
#include <string.h>
 
35
 
 
36
#include <OpenIPMI/ipmi_conn.h>
 
37
#include <OpenIPMI/ipmi_msgbits.h>
 
38
#include <OpenIPMI/ipmi_auth.h>
 
39
#include <OpenIPMI/ipmi_err.h>
 
40
#include <OpenIPMI/ipmi_lan.h>
 
41
 
 
42
#include <OpenIPMI/internal/ipmi_int.h>
 
43
 
 
44
typedef struct rakp_info_s rakp_info_t;
 
45
 
 
46
typedef int (*init_cb)(rakp_info_t *info);
 
47
typedef void (*cleanup_cb)(rakp_info_t *info);
 
48
typedef int (*check_cb)(rakp_info_t   *info,
 
49
                        unsigned char *data,
 
50
                        unsigned int  data_len);
 
51
typedef int (*set_cb)(rakp_info_t   *info,
 
52
                      unsigned char *data,
 
53
                      unsigned int  *data_len,
 
54
                      unsigned int  total_len);
 
55
 
 
56
struct rakp_info_s
 
57
{
 
58
    ipmi_rmcpp_auth_t *ainfo;
 
59
 
 
60
    ipmi_rmcpp_set_info_cb    set;
 
61
    ipmi_rmcpp_finish_auth_cb done;
 
62
    void                      *cb_data;
 
63
 
 
64
    unsigned int  hacks;
 
65
 
 
66
    unsigned char msg_tag;
 
67
 
 
68
    void *key_data;
 
69
 
 
70
    /* Check an set the auth keys for the various rakp messages.  The
 
71
       data passed in is the whole message.  For set3, the data_len
 
72
       points to the current message size and total_len is the
 
73
       total_len available.  It should update data_len to the actual
 
74
       length.  These functions may be NULL and will not be used. */
 
75
    cleanup_cb cleanup;
 
76
    check_cb   check2;
 
77
    set_cb     set3;
 
78
    check_cb   check4;
 
79
};
 
80
 
 
81
static void
 
82
rakp_done(rakp_info_t *info,
 
83
          ipmi_con_t  *ipmi,
 
84
          int         addr_num,
 
85
          int         err)
 
86
{
 
87
    info->done(ipmi, err, addr_num, info->cb_data);
 
88
    if (info->cleanup)
 
89
        info->cleanup(info);
 
90
    ipmi_mem_free(info);
 
91
}
 
92
 
 
93
static int
 
94
check_rakp_rsp(ipmi_con_t   *ipmi,
 
95
               rakp_info_t  *info,
 
96
               ipmi_msg_t   *msg,
 
97
               char         *caller,
 
98
               unsigned int min_length,
 
99
               int          addr_num)
 
100
{
 
101
    if (!ipmi) {
 
102
        return ECANCELED;
 
103
    }
 
104
 
 
105
    if (msg->data_len < 2) {
 
106
        ipmi_log(IPMI_LOG_ERR_INFO,
 
107
                 "rakp.c(%s): Message data too short: %d",
 
108
                 caller, msg->data_len);
 
109
        return EINVAL;
 
110
    }
 
111
 
 
112
    if (msg->data[1]) {
 
113
        /* Got an RMCP+ error. */
 
114
        return IPMI_RMCPP_ERR_VAL(msg->data[1]);
 
115
    }
 
116
 
 
117
    if (msg->data_len < min_length) {
 
118
        ipmi_log(IPMI_LOG_ERR_INFO,
 
119
                 "rakp.c(%s): Message data too short: %d",
 
120
                 caller, msg->data_len);
 
121
        return EINVAL;
 
122
    }
 
123
 
 
124
    return 0;
 
125
}
 
126
 
 
127
static int
 
128
handle_rakp4(ipmi_con_t *ipmi, ipmi_msgi_t *rspi)
 
129
{
 
130
    ipmi_msg_t  *msg = &rspi->msg;
 
131
    rakp_info_t *info = rspi->data1;
 
132
    int         addr_num = (long) rspi->data4;
 
133
    int         rv;
 
134
    uint32_t    session_id;
 
135
 
 
136
    /* In this function, there's not way to report the error to the
 
137
       managed system, just report it locally. */
 
138
 
 
139
    rv = check_rakp_rsp(ipmi, info, msg, "handle_rakp4", 8, addr_num);
 
140
    if (rv)
 
141
        goto out;
 
142
 
 
143
    if (info->check4) {
 
144
        rv = info->check4(info, msg->data, msg->data_len);
 
145
        if (rv)
 
146
            goto out;
 
147
    }
 
148
 
 
149
    session_id = ipmi_get_uint32(msg->data+4);
 
150
    if (session_id != ipmi_rmcpp_auth_get_my_session_id(info->ainfo)) {
 
151
        ipmi_log(IPMI_LOG_ERR_INFO,
 
152
                 "rakp.c(handle_rakp4): "
 
153
                 " Got wrong session id: 0x%x",
 
154
                 session_id);
 
155
        rv = EINVAL;
 
156
        goto out;
 
157
    }
 
158
 
 
159
    rakp_done(info, ipmi, addr_num, 0);
 
160
    return IPMI_MSG_ITEM_NOT_USED;
 
161
 
 
162
 out:
 
163
    rakp_done(info, ipmi, addr_num, rv);
 
164
    return IPMI_MSG_ITEM_NOT_USED;
 
165
}
 
166
 
 
167
static int
 
168
send_rakp3(ipmi_con_t *ipmi, rakp_info_t *info,
 
169
           ipmi_msgi_t *rspi, int addr_num, int err)
 
170
{
 
171
    int                 rv;
 
172
    unsigned char       data[64];
 
173
    ipmi_msg_t          msg;
 
174
    ipmi_rmcpp_addr_t   addr;
 
175
 
 
176
    memset(data, 0, sizeof(data));
 
177
    data[0] = info->msg_tag;
 
178
    data[1] = err;
 
179
    ipmi_set_uint32(data+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
 
180
 
 
181
    msg.netfn = IPMI_RMCPP_DUMMY_NETFN;
 
182
    msg.cmd = 0;
 
183
    msg.data = data;
 
184
    msg.data_len = 8;
 
185
    addr.addr_type = IPMI_RMCPP_ADDR_START + IPMI_RMCPP_PAYLOAD_TYPE_RAKP_3;
 
186
    rspi->data1 = info;
 
187
 
 
188
    if (info->set3) {
 
189
        unsigned int len;
 
190
        len = msg.data_len;
 
191
        rv = info->set3(info, data, &len, sizeof(data));
 
192
        if (rv)
 
193
            return rv;
 
194
        msg.data_len = len;
 
195
    }
 
196
 
 
197
    if (err)
 
198
        /* Don't handle the responst (if one comes back) on an error. */
 
199
        rv = ipmi_lan_send_command_forceip(ipmi, addr_num,
 
200
                                           (ipmi_addr_t *) &addr, sizeof(addr),
 
201
                                           &msg, NULL, rspi);
 
202
    else
 
203
        rv = ipmi_lan_send_command_forceip(ipmi, addr_num,
 
204
                                           (ipmi_addr_t *) &addr, sizeof(addr),
 
205
                                           &msg, handle_rakp4, rspi);
 
206
    return rv;
 
207
}
 
208
 
 
209
static int
 
210
handle_rakp2(ipmi_con_t *ipmi, ipmi_msgi_t *rspi)
 
211
{
 
212
    ipmi_msg_t    *msg = &rspi->msg;
 
213
    rakp_info_t   *info = rspi->data1;
 
214
    int           addr_num = (long) rspi->data4;
 
215
    int           rv;
 
216
    uint32_t      session_id;
 
217
    int           err = 0;
 
218
    unsigned char *p;
 
219
    unsigned int  plen;
 
220
 
 
221
    rv = check_rakp_rsp(ipmi, info, msg, "handle_rakp2", 40, addr_num);
 
222
    if (rv) {
 
223
        err = IPMI_RMCPP_ILLEGAL_PARAMETER;
 
224
        goto out;
 
225
    }
 
226
 
 
227
    p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
 
228
    if (plen < 16)
 
229
        return EINVAL;
 
230
    memcpy(p, msg->data+8, 16);
 
231
    ipmi_rmcpp_auth_set_mgsys_rand_len(info->ainfo, 16);
 
232
 
 
233
    p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen);
 
234
    if (plen < 16)
 
235
        return EINVAL;
 
236
    memcpy(p, msg->data+24, 16);
 
237
    ipmi_rmcpp_auth_set_mgsys_guid_len(info->ainfo, 16);
 
238
 
 
239
    session_id = ipmi_get_uint32(msg->data+4);
 
240
    if (session_id != ipmi_rmcpp_auth_get_my_session_id(info->ainfo)) {
 
241
        ipmi_log(IPMI_LOG_ERR_INFO,
 
242
                 "rakp.c(handle_rakp2): "
 
243
                 " Got wrong session id: 0x%x",
 
244
                 session_id);
 
245
        err = IPMI_RMCPP_INVALID_SESSION_ID;
 
246
        goto out;
 
247
    }
 
248
 
 
249
    if (info->check2) {
 
250
        rv = info->check2(info, msg->data, msg->data_len);
 
251
        if (rv) {
 
252
            if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
 
253
                ipmi_log(IPMI_LOG_DEBUG, "Integrity check fail for rakp 2");
 
254
            err = IPMI_RMCPP_INVALID_INTEGRITY_CHECK_VALUE;
 
255
            goto out;
 
256
        }
 
257
    }
 
258
 
 
259
    rv = info->set(ipmi, addr_num, info->ainfo, info->cb_data);
 
260
    if (rv) {
 
261
        if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
 
262
            ipmi_log(IPMI_LOG_DEBUG, "Error setting values from rakp 2");
 
263
        err = IPMI_RMCPP_INSUFFICIENT_RESOURCES_FOR_SESSION;
 
264
        goto out;
 
265
    }
 
266
 
 
267
    rv = send_rakp3(ipmi, info, rspi, addr_num, 0);
 
268
    if (rv) {
 
269
        if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
 
270
            ipmi_log(IPMI_LOG_DEBUG, "Error sending rakp 3");
 
271
        err = IPMI_RMCPP_INSUFFICIENT_RESOURCES_FOR_SESSION;
 
272
        goto out;
 
273
    }
 
274
 
 
275
    return IPMI_MSG_ITEM_USED;
 
276
 
 
277
 out:
 
278
    rv = send_rakp3(ipmi, info, rspi, addr_num, err);
 
279
    rakp_done(info, ipmi, addr_num, rv);
 
280
    if (rv)
 
281
        return IPMI_MSG_ITEM_NOT_USED;
 
282
    else
 
283
        /* Yes, we use it to send the error response. */
 
284
        return IPMI_MSG_ITEM_USED;
 
285
}
 
286
 
 
287
static int
 
288
send_rakp1(ipmi_con_t *ipmi, rakp_info_t *info,
 
289
           ipmi_msgi_t *rspi, int addr_num)
 
290
{
 
291
    int                 rv;
 
292
    unsigned char       data[44];
 
293
    ipmi_msg_t          msg;
 
294
    ipmi_rmcpp_addr_t   addr;
 
295
    const unsigned char *p;
 
296
    unsigned int        plen;
 
297
 
 
298
    memset(data, 0, sizeof(data));
 
299
    data[0] = info->msg_tag;
 
300
    ipmi_set_uint32(data+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
 
301
 
 
302
    p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
 
303
    if (plen < 16)
 
304
        return EINVAL;
 
305
    memcpy(data+8, p, 16);
 
306
 
 
307
    data[24] = ipmi_rmcpp_auth_get_role(info->ainfo);
 
308
    data[27] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
 
309
    p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
 
310
    if (plen < 16)
 
311
        return EINVAL;
 
312
    memcpy(data+28, p, data[27]);
 
313
 
 
314
    msg.netfn = IPMI_RMCPP_DUMMY_NETFN;
 
315
    msg.cmd = 0;
 
316
    msg.data = data;
 
317
    msg.data_len = 28 + data[27];
 
318
    addr.addr_type = IPMI_RMCPP_ADDR_START + IPMI_RMCPP_PAYLOAD_TYPE_RAKP_1;
 
319
    rspi->data1 = info;
 
320
 
 
321
    rv = ipmi_lan_send_command_forceip(ipmi, addr_num,
 
322
                                       (ipmi_addr_t *) &addr, sizeof(addr),
 
323
                                       &msg, handle_rakp2, rspi);
 
324
    return rv;
 
325
}
 
326
 
 
327
static int
 
328
start_rakp(ipmi_con_t                *ipmi,
 
329
           int                       addr_num,
 
330
           unsigned char             msg_tag,
 
331
           ipmi_rmcpp_auth_t         *ainfo,
 
332
           init_cb                   init,
 
333
           cleanup_cb                cleanup,
 
334
           check_cb                  check2,
 
335
           set_cb                    set3,
 
336
           check_cb                  check4,
 
337
           ipmi_rmcpp_set_info_cb    set,
 
338
           ipmi_rmcpp_finish_auth_cb done,
 
339
           void                      *cb_data)
 
340
{
 
341
    rakp_info_t   *info;
 
342
    ipmi_msgi_t   *rspi;
 
343
    int           rv;
 
344
    unsigned char *p;
 
345
    unsigned int  plen;
 
346
 
 
347
    info = ipmi_mem_alloc(sizeof(*info));
 
348
    if (!info)
 
349
        return ENOMEM;
 
350
    memset(info, 0, sizeof(*info));
 
351
 
 
352
    rspi = ipmi_alloc_msg_item();
 
353
    if (!rspi) {
 
354
        ipmi_mem_free(info);
 
355
        return ENOMEM;
 
356
    }
 
357
 
 
358
    info->msg_tag = msg_tag;
 
359
    info->ainfo = ainfo;
 
360
    info->cleanup = cleanup;
 
361
    info->set = set;
 
362
    info->done = done;
 
363
    info->cb_data = cb_data;
 
364
    info->check2 = check2;
 
365
    info->set3 = set3;
 
366
    info->check4 = check4;
 
367
    info->hacks = ipmi->hacks;
 
368
 
 
369
    p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
 
370
    if (plen < 16)
 
371
        return EINVAL;
 
372
    ipmi_rmcpp_auth_set_my_rand_len(info->ainfo, 16);
 
373
    rv = ipmi->os_hnd->get_random(ipmi->os_hnd, p, 16);
 
374
    if (rv) {
 
375
        ipmi_free_msg_item(rspi);
 
376
        ipmi_mem_free(info);
 
377
        return rv;
 
378
    }
 
379
 
 
380
    if (init) {
 
381
        rv = init(info);
 
382
        if (rv) {
 
383
            ipmi_free_msg_item(rspi);
 
384
            ipmi_mem_free(info);
 
385
            return rv;
 
386
        }
 
387
    }
 
388
 
 
389
    rv = send_rakp1(ipmi, info, rspi, addr_num);
 
390
    if (rv) {
 
391
        if (cleanup)
 
392
            cleanup(info);
 
393
        ipmi_free_msg_item(rspi);
 
394
        ipmi_mem_free(info);
 
395
        return rv;
 
396
    }
 
397
 
 
398
    return 0;
 
399
}
 
400
 
 
401
 
 
402
static int
 
403
start_rakp_none(ipmi_con_t                *ipmi,
 
404
                int                       addr_num,
 
405
                unsigned char             msg_tag,
 
406
                ipmi_rmcpp_auth_t         *ainfo,
 
407
                ipmi_rmcpp_set_info_cb    set,
 
408
                ipmi_rmcpp_finish_auth_cb done,
 
409
                void                      *cb_data)
 
410
{
 
411
    return start_rakp(ipmi, addr_num, msg_tag, ainfo,
 
412
                      NULL, NULL, NULL, NULL, NULL,
 
413
                      set, done, cb_data);
 
414
}
 
415
 
 
416
static ipmi_rmcpp_authentication_t rakp_none_auth =
 
417
{
 
418
    start_rakp_none
 
419
};
 
420
 
 
421
/***********************************************************************
 
422
 *
 
423
 * cipher handling
 
424
 *
 
425
 ***********************************************************************/
 
426
#ifdef HAVE_OPENSSL
 
427
#include <openssl/hmac.h>
 
428
 
 
429
typedef struct rakp_hmac_key_s
 
430
{
 
431
    unsigned int key_len;
 
432
    unsigned int integ_len;
 
433
    const EVP_MD *evp_md;
 
434
} rakp_hmac_key_t;
 
435
 
 
436
static int
 
437
rakp_hmac_c2(rakp_info_t   *info,
 
438
             unsigned char *data,
 
439
             unsigned int  data_len)
 
440
{
 
441
    unsigned char       idata[74];
 
442
    unsigned int        ilen;
 
443
    unsigned char       integ_data[20];
 
444
    rakp_hmac_key_t     *rinfo = info->key_data;
 
445
    const unsigned char *p;
 
446
    unsigned char       *s;
 
447
    unsigned char       *k;
 
448
    unsigned int        plen;
 
449
 
 
450
    if (data_len < 40+rinfo->key_len)
 
451
        return E2BIG;
 
452
 
 
453
    ipmi_set_uint32(idata+0, ipmi_rmcpp_auth_get_my_session_id(info->ainfo));
 
454
    ipmi_set_uint32(idata+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
 
455
    p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
 
456
    memcpy(idata+8, p, 16);
 
457
    p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
 
458
    memcpy(idata+24, p, 16);
 
459
    p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen);
 
460
    memcpy(idata+40, p, 16);
 
461
    idata[56] = ipmi_rmcpp_auth_get_role(info->ainfo);
 
462
    idata[57] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
 
463
    if (idata[57] > 16)
 
464
        return EINVAL;
 
465
    p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
 
466
    memcpy(idata+58, p, idata[57]);
 
467
 
 
468
    p = ipmi_rmcpp_auth_get_password(info->ainfo, &plen);
 
469
    if (plen < rinfo->key_len)
 
470
        return EINVAL;
 
471
    HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 58+idata[57], integ_data, &ilen);
 
472
    if (memcmp(data+40, integ_data, rinfo->key_len) != 0)
 
473
        return EINVAL;
 
474
 
 
475
    /* Now generate the SIK */
 
476
    p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
 
477
    memcpy(idata+0, p, 16);
 
478
    p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
 
479
    memcpy(idata+16, p, 16);
 
480
    idata[32] = ipmi_rmcpp_auth_get_role(info->ainfo);
 
481
    idata[33] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
 
482
    p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
 
483
    memcpy(idata+34, p, idata[33]);
 
484
    p = ipmi_rmcpp_auth_get_bmc_key(info->ainfo, &plen);
 
485
    if (plen < rinfo->key_len)
 
486
        return EINVAL;
 
487
    s = ipmi_rmcpp_auth_get_sik(info->ainfo, &plen);
 
488
    if (plen < rinfo->key_len)
 
489
        return EINVAL;
 
490
    HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 34+idata[33], s, &ilen);
 
491
    ipmi_rmcpp_auth_set_sik_len(info->ainfo, rinfo->key_len);
 
492
 
 
493
    /* Now generate k1 and k2. */
 
494
    k = ipmi_rmcpp_auth_get_k1(info->ainfo, &plen);
 
495
    if (plen < rinfo->key_len)
 
496
        return EINVAL;
 
497
    memset(idata, 1, rinfo->key_len);
 
498
    HMAC(rinfo->evp_md, s, rinfo->key_len, idata, rinfo->key_len, k, &ilen);
 
499
    ipmi_rmcpp_auth_set_k2_len(info->ainfo, rinfo->key_len);
 
500
    k = ipmi_rmcpp_auth_get_k2(info->ainfo, &plen);
 
501
    if (plen < rinfo->key_len)
 
502
        return EINVAL;
 
503
    memset(idata, 2, rinfo->key_len);
 
504
    HMAC(rinfo->evp_md, s, rinfo->key_len, idata, rinfo->key_len, k, &ilen);
 
505
    ipmi_rmcpp_auth_set_k2_len(info->ainfo, rinfo->key_len);
 
506
 
 
507
    return 0;
 
508
}
 
509
 
 
510
static int
 
511
rakp_hmac_s3(rakp_info_t   *info,
 
512
             unsigned char *data,
 
513
             unsigned int  *data_len,
 
514
             unsigned int  total_len)
 
515
{
 
516
    unsigned char       idata[38];
 
517
    unsigned int        ilen;
 
518
    rakp_hmac_key_t     *rinfo = info->key_data;
 
519
    const unsigned char *p;
 
520
    unsigned int        plen;
 
521
 
 
522
    if (((*data_len)+rinfo->key_len) > total_len)
 
523
        return E2BIG;
 
524
 
 
525
    p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen);
 
526
    memcpy(idata+0, p, 16);
 
527
    ipmi_set_uint32(idata+16, ipmi_rmcpp_auth_get_my_session_id(info->ainfo));
 
528
    idata[20] = ipmi_rmcpp_auth_get_role(info->ainfo);
 
529
    if (info->hacks & IPMI_CONN_HACK_RAKP3_WRONG_ROLEM)
 
530
        /* For the RAKP4 message, the Intel BMC only uses the bottom 4
 
531
           nibbles. */
 
532
        idata[20] &= 0xf;
 
533
    idata[21] = ipmi_rmcpp_auth_get_username_len(info->ainfo);
 
534
    if (idata[21] > 16)
 
535
        return EINVAL;
 
536
    p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen);
 
537
    memcpy(idata+22, p, idata[21]);
 
538
 
 
539
    p = ipmi_rmcpp_auth_get_password(info->ainfo, &plen);
 
540
    if (plen < rinfo->key_len)
 
541
        return EINVAL;
 
542
 
 
543
    HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 22+idata[21],
 
544
         data+*data_len, &ilen);
 
545
    *data_len += rinfo->key_len;
 
546
    return 0;
 
547
}
 
548
 
 
549
static int
 
550
rakp_hmac_c4(rakp_info_t   *info,
 
551
             unsigned char *data,
 
552
             unsigned int  data_len)
 
553
{
 
554
    unsigned char       idata[36];
 
555
    unsigned int        ilen;
 
556
    unsigned char       integ_data[20];
 
557
    rakp_hmac_key_t     *rinfo = info->key_data;
 
558
    const unsigned char *p;
 
559
    unsigned int        plen;
 
560
 
 
561
    if (data_len < 8+rinfo->integ_len)
 
562
        return E2BIG;
 
563
 
 
564
    p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
 
565
    memcpy(idata+0, p, 16);
 
566
    ipmi_set_uint32(idata+16, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo));
 
567
    p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen);
 
568
    if (plen < 16)
 
569
        return EINVAL;
 
570
    memcpy(idata+20, p, 16);
 
571
 
 
572
    p = ipmi_rmcpp_auth_get_sik(info->ainfo, &plen);
 
573
    HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 36, integ_data, &ilen);
 
574
    if (memcmp(data+8, integ_data, rinfo->integ_len) != 0)
 
575
        return EINVAL;
 
576
 
 
577
    return 0;
 
578
}
 
579
 
 
580
static void
 
581
rakp_hmac_cleanup(rakp_info_t *info)
 
582
{
 
583
    rakp_hmac_key_t *key_data = info->key_data;
 
584
 
 
585
    ipmi_mem_free(key_data);
 
586
}
 
587
 
 
588
static int
 
589
rakp_sha1_init(rakp_info_t *info)
 
590
{
 
591
    rakp_hmac_key_t *key_data;
 
592
 
 
593
    key_data = ipmi_mem_alloc(sizeof(*key_data));
 
594
    if (!key_data)
 
595
        return ENOMEM;
 
596
    key_data->evp_md = EVP_sha1();
 
597
    key_data->key_len = 20;
 
598
    key_data->integ_len = 12;
 
599
    info->key_data = key_data;
 
600
    return 0;
 
601
}
 
602
 
 
603
static int
 
604
start_rakp_hmac_sha1(ipmi_con_t                *ipmi,
 
605
                     int                       addr_num,
 
606
                     unsigned char             msg_tag,
 
607
                     ipmi_rmcpp_auth_t         *ainfo,
 
608
                     ipmi_rmcpp_set_info_cb    set,
 
609
                     ipmi_rmcpp_finish_auth_cb done,
 
610
                     void                      *cb_data)
 
611
{
 
612
    return start_rakp(ipmi, addr_num, msg_tag, ainfo,
 
613
                      rakp_sha1_init, rakp_hmac_cleanup,
 
614
                      rakp_hmac_c2, rakp_hmac_s3, rakp_hmac_c4,
 
615
                      set, done, cb_data);
 
616
}
 
617
 
 
618
static ipmi_rmcpp_authentication_t rakp_hmac_sha1_auth =
 
619
{
 
620
    start_rakp_hmac_sha1
 
621
};
 
622
 
 
623
static int
 
624
rakp_md5_init(rakp_info_t *info)
 
625
{
 
626
    rakp_hmac_key_t *key_data;
 
627
 
 
628
    key_data = ipmi_mem_alloc(sizeof(*key_data));
 
629
    if (!key_data)
 
630
        return ENOMEM;
 
631
    key_data->evp_md = EVP_md5();
 
632
    key_data->key_len = 16;
 
633
    key_data->integ_len = 16;
 
634
    info->key_data = key_data;
 
635
    return 0;
 
636
}
 
637
 
 
638
static int
 
639
start_rakp_hmac_md5(ipmi_con_t                *ipmi,
 
640
                    int                       addr_num,
 
641
                    unsigned char             msg_tag,
 
642
                    ipmi_rmcpp_auth_t         *ainfo,
 
643
                    ipmi_rmcpp_set_info_cb    set,
 
644
                    ipmi_rmcpp_finish_auth_cb done,
 
645
                    void                      *cb_data)
 
646
{
 
647
    return start_rakp(ipmi, addr_num, msg_tag, ainfo,
 
648
                      rakp_md5_init, rakp_hmac_cleanup,
 
649
                      rakp_hmac_c2, rakp_hmac_s3, rakp_hmac_c4,
 
650
                      set, done, cb_data);
 
651
}
 
652
 
 
653
static ipmi_rmcpp_authentication_t rakp_hmac_md5_auth =
 
654
{
 
655
    start_rakp_hmac_md5
 
656
};
 
657
#endif
 
658
 
 
659
/**********************************************************************
 
660
 *
 
661
 * RAKP message formatting
 
662
 *
 
663
 *********************************************************************/
 
664
 
 
665
static int
 
666
rakp_format_msg(ipmi_con_t    *ipmi,
 
667
                ipmi_addr_t   *addr,
 
668
                unsigned int  addr_len,
 
669
                ipmi_msg_t    *msg,
 
670
                unsigned char *out_data,
 
671
                unsigned int  *out_data_len,
 
672
                int           *out_of_session,
 
673
                unsigned char seq)
 
674
{
 
675
    if (msg->data_len > *out_data_len)
 
676
        return E2BIG;
 
677
 
 
678
    memcpy(out_data, msg->data, msg->data_len);
 
679
    out_data[0] = seq;
 
680
    *out_of_session = 1;
 
681
    *out_data_len = msg->data_len;
 
682
    return 0;
 
683
}
 
684
 
 
685
static int
 
686
rakp_get_recv_seq(ipmi_con_t    *ipmi,
 
687
                  unsigned char *data,
 
688
                  unsigned int  data_len,
 
689
                  unsigned char *seq)
 
690
{
 
691
    if (data_len < 1)
 
692
        return EINVAL;
 
693
 
 
694
    *seq = data[0];
 
695
    return 0;
 
696
}
 
697
 
 
698
static int
 
699
rakp_handle_recv(ipmi_con_t    *ipmi,
 
700
                 ipmi_msgi_t   *rspi,
 
701
                 ipmi_addr_t   *orig_addr,
 
702
                 unsigned int  orig_addr_len,
 
703
                 ipmi_msg_t    *orig_msg,
 
704
                 unsigned char *data,
 
705
                 unsigned int  data_len)
 
706
{
 
707
    ipmi_msg_t *msg = &(rspi->msg);
 
708
    if (data_len > sizeof(rspi->data))
 
709
        return E2BIG;
 
710
    memcpy(rspi->data, data, data_len);
 
711
    msg->data = rspi->data;
 
712
    msg->data_len = data_len;
 
713
    return 0;
 
714
}
 
715
 
 
716
static void
 
717
rakp_handle_recv_async(ipmi_con_t    *ipmi,
 
718
                       unsigned char *tmsg,
 
719
                       unsigned int  data_len)
 
720
{
 
721
}
 
722
 
 
723
static int
 
724
rakp_get_msg_tag(unsigned char *tmsg,
 
725
                 unsigned int  data_len,
 
726
                 unsigned char *tag)
 
727
{
 
728
    if (data_len < 8)
 
729
        return EINVAL;
 
730
    *tag = ipmi_get_uint32(tmsg+4) - 1; /* session id */
 
731
    return 0;
 
732
}
 
733
 
 
734
static ipmi_payload_t rakp_payload =
 
735
{ rakp_format_msg, rakp_get_recv_seq, rakp_handle_recv,
 
736
  rakp_handle_recv_async, rakp_get_msg_tag };
 
737
 
 
738
int
 
739
_ipmi_rakp_init(void)
 
740
{
 
741
    int rv;
 
742
 
 
743
    rv = ipmi_rmcpp_register_authentication
 
744
        (IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_NONE,
 
745
         &rakp_none_auth);
 
746
    if (rv)
 
747
        return rv;
 
748
 
 
749
#ifdef HAVE_OPENSSL
 
750
    rv = ipmi_rmcpp_register_authentication
 
751
        (IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1,
 
752
         &rakp_hmac_sha1_auth);
 
753
    if (rv)
 
754
        return rv;
 
755
 
 
756
    rv = ipmi_rmcpp_register_authentication
 
757
        (IPMI_LANP_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5,
 
758
         &rakp_hmac_md5_auth);
 
759
    if (rv)
 
760
        return rv;
 
761
#endif
 
762
 
 
763
    rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_1,
 
764
                                     &rakp_payload);
 
765
    if (rv)
 
766
        return rv;
 
767
    rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_2,
 
768
                                     &rakp_payload);
 
769
    if (rv)
 
770
        return rv;
 
771
    rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_3,
 
772
                                     &rakp_payload);
 
773
    if (rv)
 
774
        return rv;
 
775
    rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_RAKP_4,
 
776
                                     &rakp_payload);
 
777
    if (rv)
 
778
        return rv;
 
779
 
 
780
    return 0;
 
781
}