/* * md5.c * * MontaVista RMCP+ code for doing MD5 without HMAC. * * Author: MontaVista Software, Inc. * Corey Minyard * source@mvista.com * * Copyright 2004 MontaVista Software Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include /* Not strictly necessary, but ths is pointless if we don't have ssl */ #ifdef HAVE_OPENSSL #include #include #include #include #include /* We use our own internal vesion of MD5 over openssl's because ours does scatter/gather. */ #include typedef struct md5_info_s { ipmi_authdata_t authdata; } md5_info_t; static void * auth_alloc(void *info, int size) { return ipmi_mem_alloc(size); } static void auth_free(void *info, void *data) { ipmi_mem_free(data); } static int md5_init(ipmi_con_t *ipmi, ipmi_rmcpp_auth_t *ainfo, void **integ_data) { md5_info_t *info; unsigned int klen; const unsigned char *k; int rv; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; k = ipmi_rmcpp_auth_get_password(ainfo, &klen); if (klen < 20) return EINVAL; rv = ipmi_md5_authcode_initl(k, 20, &info->authdata, NULL, auth_alloc, auth_free); if (rv) { ipmi_mem_free(info); return rv; } *integ_data = info; return 0; } static void md5_free(ipmi_con_t *ipmi, void *integ_data) { md5_info_t *info = integ_data; ipmi_md5_authcode_cleanup(info->authdata); ipmi_mem_free(integ_data); } static int md5_pad(ipmi_con_t *ipmi, void *integ_data, unsigned char *payload, unsigned int *payload_len, unsigned int max_payload_len) { unsigned char *p = payload; unsigned int l = *payload_len; unsigned int count = 0; /* Pad so that when we add two bytes (the pad length and the next header) the result is on a multiple of 4 boundary. */ while (((l+2) % 4) != 0) { if (l == max_payload_len) return E2BIG; p[l] = 0xff; l++; count++; } /* Add the padding length. The next header gets added later. */ if (l == max_payload_len) return E2BIG; p[l] = count; l++; *payload_len = l; return 0; } static int md5_add(ipmi_con_t *ipmi, void *integ_data, unsigned char *payload, unsigned int *payload_len, unsigned int max_payload_len) { md5_info_t *info = integ_data; unsigned char *p = payload; unsigned int l = *payload_len; ipmi_auth_sg_t data[2]; int rv; if (l+17 > max_payload_len) return E2BIG; if (l < 4) return E2BIG; p[l] = 0x07; /* Next header */ l++; data[0].data = p+4; data[0].len = l-4; data[1].data = NULL; rv = ipmi_md5_authcode_gen(info->authdata, data, p+l); if (rv) return rv; l += 16; *payload_len = l; return 0; } static int md5_check(ipmi_con_t *ipmi, void *integ_data, unsigned char *payload, unsigned int payload_len, unsigned int total_len) { md5_info_t *info = integ_data; unsigned char *p = payload; unsigned int l = payload_len; ipmi_auth_sg_t data[2]; int rv; /* We don't authenticate this part of the header. */ p += 4; l -= 4; if ((total_len - payload_len) < 17) return EINVAL; /* We add 1 to the length because we also check the next header field. */ data[0].data = p; data[0].len = l+1; data[1].data = NULL; rv = ipmi_md5_authcode_check(info->authdata, data, p+l+1); if (rv) return rv; return 0; } static ipmi_rmcpp_integrity_t md5_integ = { .integ_init = md5_init, .integ_free = md5_free, .integ_pad = md5_pad, .integ_add = md5_add, .integ_check = md5_check }; #endif /* HAVE_OPENSSL */ int i_ipmi_md5_init(void) { #ifdef HAVE_OPENSSL int rv = 0; rv = ipmi_rmcpp_register_integrity (IPMI_LANP_INTEGRITY_ALGORITHM_MD5_128, &md5_integ); if (rv) return rv; #endif return 0; } void i_ipmi_md5_shutdown(void) { #ifdef HAVE_OPENSSL ipmi_rmcpp_register_integrity (IPMI_LANP_INTEGRITY_ALGORITHM_MD5_128, NULL); #endif }