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

« back to all changes in this revision

Viewing changes to lib/hmac.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
 * hmac.c
 
3
 *
 
4
 * MontaVista RMCP+ code for doing HMAC, both SHA1 and MD5
 
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
#ifdef HAVE_OPENSSL
 
35
 
 
36
#include <errno.h>
 
37
#include <string.h>
 
38
#include <openssl/hmac.h>
 
39
#include <OpenIPMI/ipmi_lan.h>
 
40
#include <OpenIPMI/internal/ipmi_malloc.h>
 
41
 
 
42
typedef struct hmac_info_s
 
43
{
 
44
    const EVP_MD *evp_md;
 
45
    unsigned int  klen;
 
46
    unsigned int  ilen;
 
47
    unsigned char k[20];
 
48
} hmac_info_t;
 
49
 
 
50
static int
 
51
hmac_sha1_init(ipmi_con_t       *ipmi,
 
52
               ipmi_rmcpp_auth_t *ainfo,
 
53
               void             **integ_data)
 
54
{
 
55
    hmac_info_t          *info;
 
56
    static unsigned char *k;
 
57
    unsigned int         klen;
 
58
 
 
59
    info = ipmi_mem_alloc(sizeof(*info));
 
60
    if (!info)
 
61
        return ENOMEM;
 
62
 
 
63
    if (ipmi_rmcpp_auth_get_sik_len(ainfo) < 20)
 
64
        return EINVAL;
 
65
 
 
66
    if (ipmi->hacks & IPMI_CONN_HACK_RMCPP_INTEG_SIK)
 
67
        k = ipmi_rmcpp_auth_get_sik(ainfo, &klen);
 
68
    else
 
69
        k = ipmi_rmcpp_auth_get_k1(ainfo, &klen);
 
70
    if (klen < 20)
 
71
        return EINVAL;
 
72
 
 
73
    memcpy(info->k, k, 20);
 
74
    info->klen = 20;
 
75
    info->ilen = 12;
 
76
 
 
77
    info->evp_md = EVP_sha1();
 
78
    *integ_data = info;
 
79
    return 0;
 
80
}
 
81
 
 
82
static int
 
83
hmac_md5_init(ipmi_con_t       *ipmi,
 
84
              ipmi_rmcpp_auth_t *ainfo,
 
85
              void             **integ_data)
 
86
{
 
87
    hmac_info_t         *info;
 
88
    const unsigned char *k;
 
89
    unsigned int        klen;
 
90
 
 
91
    info = ipmi_mem_alloc(sizeof(*info));
 
92
    if (!info)
 
93
        return ENOMEM;
 
94
 
 
95
    k = ipmi_rmcpp_auth_get_password(ainfo, &klen);
 
96
    if (klen < 16)
 
97
        return EINVAL;
 
98
 
 
99
    memcpy(info->k, k, 16);
 
100
    info->klen = 16;
 
101
    info->ilen = 16;
 
102
 
 
103
    info->evp_md = EVP_md5();
 
104
    *integ_data = info;
 
105
    return 0;
 
106
}
 
107
 
 
108
static void
 
109
hmac_free(ipmi_con_t *ipmi,
 
110
          void       *integ_data)
 
111
{
 
112
    hmac_info_t *info = integ_data;
 
113
 
 
114
    memset(info->k, 0, sizeof(info->k));
 
115
    ipmi_mem_free(integ_data);
 
116
}
 
117
 
 
118
static int
 
119
hmac_pad(ipmi_con_t    *ipmi,
 
120
         void          *integ_data,
 
121
         unsigned char *payload,
 
122
         unsigned int  *payload_len,
 
123
         unsigned int  max_payload_len)
 
124
{
 
125
    unsigned char  *p = payload;
 
126
    unsigned int   l = *payload_len;
 
127
    unsigned int   count = 0;
 
128
 
 
129
    /* Pad so that when we add two bytes (the pad length and the next
 
130
       header) the result is on a multiple of 4 boundary. */
 
131
    while (((l+2) % 4) != 0) {
 
132
        if (l == max_payload_len)
 
133
            return E2BIG;
 
134
        p[l] = 0xff;
 
135
        l++;
 
136
        count++;
 
137
    }
 
138
 
 
139
    /* Add the padding length.  The next header gets added later. */
 
140
    if (l == max_payload_len)
 
141
        return E2BIG;
 
142
    p[l] = count;
 
143
    l++;
 
144
 
 
145
    *payload_len = l;
 
146
    return 0;
 
147
}
 
148
 
 
149
static int
 
150
hmac_add(ipmi_con_t    *ipmi,
 
151
         void          *integ_data,
 
152
         unsigned char *payload,
 
153
         unsigned int  *payload_len,
 
154
         unsigned int  max_payload_len)
 
155
{
 
156
    hmac_info_t   *info = integ_data;
 
157
    unsigned char *p = payload;
 
158
    unsigned int  l = *payload_len;
 
159
    unsigned int  ilen;
 
160
    unsigned char integ[20];
 
161
 
 
162
    if (l+info->ilen+1 > max_payload_len)
 
163
        return E2BIG;
 
164
 
 
165
    if (l < 4)
 
166
        return E2BIG;
 
167
 
 
168
    p[l] = 0x07; /* Add the next header */
 
169
    l++;
 
170
 
 
171
    HMAC(info->evp_md, info->k, info->klen, p+4, l-4, integ, &ilen);
 
172
    memcpy(p+l, integ, ilen);
 
173
    l += info->ilen;
 
174
 
 
175
    *payload_len = l;
 
176
    return 0;
 
177
}
 
178
 
 
179
static int
 
180
hmac_check(ipmi_con_t    *ipmi,
 
181
           void          *integ_data,
 
182
           unsigned char *payload,
 
183
           unsigned int  payload_len,
 
184
           unsigned int  total_len)
 
185
{
 
186
    hmac_info_t   *info = integ_data;
 
187
    unsigned char *p = payload;
 
188
    unsigned int  l = payload_len;
 
189
    unsigned int  ilen;
 
190
    unsigned char new_integ[20];
 
191
 
 
192
    /* We don't authenticate this part of the header. */
 
193
    p += 4;
 
194
    l -= 4;
 
195
 
 
196
    if ((total_len - payload_len) < info->ilen+1)
 
197
        return EINVAL;
 
198
 
 
199
    /* We add 1 to the length because we also check the next header
 
200
       field. */
 
201
    HMAC(info->evp_md, info->k, info->klen, p, l+1, new_integ, &ilen);
 
202
    if (memcmp(new_integ, p+l+1, info->ilen) != 0)
 
203
        return EINVAL;
 
204
 
 
205
    return 0;
 
206
}
 
207
 
 
208
static ipmi_rmcpp_integrity_t hmac_sha1_integ =
 
209
{
 
210
    .integ_init = hmac_sha1_init,
 
211
    .integ_free = hmac_free,
 
212
    .integ_pad = hmac_pad,
 
213
    .integ_add = hmac_add,
 
214
    .integ_check = hmac_check
 
215
};
 
216
 
 
217
static ipmi_rmcpp_integrity_t hmac_md5_integ =
 
218
{
 
219
    .integ_init = hmac_md5_init,
 
220
    .integ_free = hmac_free,
 
221
    .integ_pad = hmac_pad,
 
222
    .integ_add = hmac_add,
 
223
    .integ_check = hmac_check
 
224
};
 
225
#endif /* HAVE_OPENSSL */
 
226
 
 
227
int
 
228
_ipmi_hmac_init(void)
 
229
{
 
230
#ifdef HAVE_OPENSSL
 
231
    int rv = 0;
 
232
 
 
233
    rv = ipmi_rmcpp_register_integrity
 
234
        (IPMI_LANP_INTEGRITY_ALGORITHM_HMAC_SHA1_96, &hmac_sha1_integ);
 
235
    if (rv)
 
236
        return rv;
 
237
 
 
238
    rv = ipmi_rmcpp_register_integrity
 
239
        (IPMI_LANP_INTEGRITY_ALGORITHM_HMAC_MD5_128, &hmac_md5_integ);
 
240
    if (rv)
 
241
        return rv;
 
242
#endif
 
243
 
 
244
    return 0;
 
245
}