2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * Copyright 1993 by OpenVision Technologies, Inc.
2N/A *
2N/A * Permission to use, copy, modify, distribute, and sell this software
2N/A * and its documentation for any purpose is hereby granted without fee,
2N/A * provided that the above copyright notice appears in all copies and
2N/A * that both that copyright notice and this permission notice appear in
2N/A * supporting documentation, and that the name of OpenVision not be used
2N/A * in advertising or publicity pertaining to distribution of the software
2N/A * without specific, written prior permission. OpenVision makes no
2N/A * representations about the suitability of this software for any
2N/A * purpose. It is provided "as is" without express or implied warranty.
2N/A *
2N/A * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2N/A * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
2N/A * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2N/A * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
2N/A * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
2N/A * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2N/A * PERFORMANCE OF THIS SOFTWARE.
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include "gssapiP_krb5.h"
2N/A#ifdef HAVE_MEMORY_H
2N/A#include <memory.h>
2N/A#endif
2N/A
2N/A/* Checksumming the channel bindings always uses plain MD5. */
2N/Akrb5_error_code
2N/Akg_checksum_channel_bindings(context, cb, cksum, bigend)
2N/A krb5_context context;
2N/A gss_channel_bindings_t cb;
2N/A krb5_checksum *cksum;
2N/A int bigend;
2N/A{
2N/A size_t len;
2N/A char *buf = 0;
2N/A char *ptr;
2N/A size_t sumlen;
2N/A krb5_data plaind;
2N/A krb5_error_code code;
2N/A void *temp;
2N/A
2N/A /* initialize the the cksum */
2N/A code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen);
2N/A if (code)
2N/A return(code);
2N/A
2N/A cksum->checksum_type = CKSUMTYPE_RSA_MD5;
2N/A cksum->length = sumlen;
2N/A
2N/A /* generate a buffer full of zeros if no cb specified */
2N/A
2N/A if (cb == GSS_C_NO_CHANNEL_BINDINGS) {
2N/A if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
2N/A return(ENOMEM);
2N/A }
2N/A memset(cksum->contents, '\0', cksum->length);
2N/A return(0);
2N/A }
2N/A
2N/A /* create the buffer to checksum into */
2N/A
2N/A len = (sizeof(krb5_int32)*5+
2N/A cb->initiator_address.length+
2N/A cb->acceptor_address.length+
2N/A cb->application_data.length);
2N/A
2N/A if ((buf = (char *) xmalloc(len)) == NULL)
2N/A return(ENOMEM);
2N/A
2N/A /* helper macros. This code currently depends on a long being 32
2N/A bits, and htonl dtrt. */
2N/A
2N/A ptr = buf;
2N/A
2N/A TWRITE_INT(ptr, cb->initiator_addrtype, bigend);
2N/A TWRITE_BUF(ptr, cb->initiator_address, bigend);
2N/A TWRITE_INT(ptr, cb->acceptor_addrtype, bigend);
2N/A TWRITE_BUF(ptr, cb->acceptor_address, bigend);
2N/A TWRITE_BUF(ptr, cb->application_data, bigend);
2N/A
2N/A /* checksum the data */
2N/A
2N/A plaind.length = len;
2N/A plaind.data = buf;
2N/A
2N/A#if 0 /************** Begin IFDEF'ed OUT *******************************/
2N/A /*
2N/A * Solaris Kerberos
2N/A * MIT 1.5-6 seems/is wrong here in 2 ways
2N/A * - why free then alloc contents again?
2N/A * - calling krb5_free_checksum_contents results in cksum->length
2N/A * getting set to 0 which causes ftp to fail
2N/A * so lets stick w/oldey-but-goodey code.
2N/A */
2N/A code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0,
2N/A &plaind, cksum);
2N/A if (code)
2N/A goto cleanup;
2N/A
2N/A if ((temp = xmalloc(cksum->length)) == NULL) {
2N/A krb5_free_checksum_contents(context, cksum);
2N/A code = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A
2N/A memcpy(temp, cksum->contents, cksum->length);
2N/A krb5_free_checksum_contents(context, cksum);
2N/A cksum->contents = (krb5_octet *)temp;
2N/A#else
2N/A /* Solaris Kerberos */
2N/A if (code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0,
2N/A &plaind, cksum)) {
2N/A /* Solaris Kerberos just in case not already free */
2N/A xfree(cksum->contents);
2N/A xfree(buf);
2N/A return(code);
2N/A }
2N/A#endif /**************** END IFDEF'ed OUT *******************************/
2N/A
2N/A /* success */
2N/Acleanup:
2N/A if (buf)
2N/A xfree(buf);
2N/A return code;
2N/A}
2N/A
2N/A/* Solaris Kerberos: not supported yet */
2N/A#if 0 /************** Begin IFDEF'ed OUT *******************************/
2N/Akrb5_error_code
2N/Akg_make_checksum_iov_v1(krb5_context context,
2N/A krb5_cksumtype type,
2N/A size_t cksum_len,
2N/A krb5_key seq,
2N/A krb5_key enc,
2N/A krb5_keyusage sign_usage,
2N/A gss_iov_buffer_desc *iov,
2N/A int iov_count,
2N/A int toktype,
2N/A krb5_checksum *checksum)
2N/A{
2N/A krb5_error_code code;
2N/A gss_iov_buffer_desc *header;
2N/A krb5_crypto_iov *kiov;
2N/A size_t kiov_count;
2N/A int i = 0, j;
2N/A size_t conf_len = 0, token_header_len;
2N/A
2N/A header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
2N/A assert(header != NULL);
2N/A
2N/A kiov_count = 3 + iov_count;
2N/A kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov));
2N/A if (kiov == NULL)
2N/A return ENOMEM;
2N/A
2N/A /* Checksum over ( Header | Confounder | Data | Pad ) */
2N/A if (toktype == KG_TOK_WRAP_MSG)
2N/A conf_len = kg_confounder_size(context, enc->keyblock.enctype);
2N/A
2N/A /* Checksum output */
2N/A kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
2N/A kiov[i].data.length = checksum->length;
2N/A kiov[i].data.data = xmalloc(checksum->length);
2N/A if (kiov[i].data.data == NULL) {
2N/A xfree(kiov);
2N/A return ENOMEM;
2N/A }
2N/A i++;
2N/A
2N/A /* Header | SND_SEQ | SGN_CKSUM | Confounder */
2N/A token_header_len = 16 + cksum_len + conf_len;
2N/A
2N/A /* Header (calculate from end because of variable length ASN.1 header) */
2N/A kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
2N/A kiov[i].data.length = 8;
2N/A kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - token_header_len;
2N/A i++;
2N/A
2N/A /* Confounder */
2N/A if (toktype == KG_TOK_WRAP_MSG) {
2N/A kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
2N/A kiov[i].data.length = conf_len;
2N/A kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
2N/A i++;
2N/A }
2N/A
2N/A for (j = 0; j < iov_count; j++) {
2N/A kiov[i].flags = kg_translate_flag_iov(iov[j].type);
2N/A kiov[i].data.length = iov[j].buffer.length;
2N/A kiov[i].data.data = (char *)iov[j].buffer.value;
2N/A i++;
2N/A }
2N/A
2N/A code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, kiov_count);
2N/A if (code == 0) {
2N/A checksum->length = kiov[0].data.length;
2N/A checksum->contents = (unsigned char *)kiov[0].data.data;
2N/A } else
2N/A free(kiov[0].data.data);
2N/A
2N/A xfree(kiov);
2N/A
2N/A return code;
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Achecksum_iov_v3(krb5_context context,
2N/A krb5_cksumtype type,
2N/A size_t rrc,
2N/A krb5_key key,
2N/A krb5_keyusage sign_usage,
2N/A gss_iov_buffer_desc *iov,
2N/A int iov_count,
2N/A krb5_boolean verify,
2N/A krb5_boolean *valid)
2N/A{
2N/A krb5_error_code code;
2N/A gss_iov_buffer_desc *header;
2N/A gss_iov_buffer_desc *trailer;
2N/A krb5_crypto_iov *kiov;
2N/A size_t kiov_count;
2N/A int i = 0, j;
2N/A unsigned int k5_checksumlen;
2N/A
2N/A if (verify)
2N/A *valid = FALSE;
2N/A
2N/A code = krb5_c_crypto_length(context, key->keyblock.enctype, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen);
2N/A if (code != 0)
2N/A return code;
2N/A
2N/A header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
2N/A assert(header != NULL);
2N/A
2N/A trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
2N/A assert(rrc != 0 || trailer != NULL);
2N/A
2N/A if (trailer == NULL) {
2N/A if (rrc != k5_checksumlen)
2N/A return KRB5_BAD_MSIZE;
2N/A if (header->buffer.length != 16 + k5_checksumlen)
2N/A return KRB5_BAD_MSIZE;
2N/A } else if (trailer->buffer.length != k5_checksumlen)
2N/A return KRB5_BAD_MSIZE;
2N/A
2N/A kiov_count = 2 + iov_count;
2N/A kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov));
2N/A if (kiov == NULL)
2N/A return ENOMEM;
2N/A
2N/A /* Checksum over ( Data | Header ) */
2N/A
2N/A /* Data */
2N/A for (j = 0; j < iov_count; j++) {
2N/A kiov[i].flags = kg_translate_flag_iov(iov[j].type);
2N/A kiov[i].data.length = iov[j].buffer.length;
2N/A kiov[i].data.data = (char *)iov[j].buffer.value;
2N/A i++;
2N/A }
2N/A
2N/A /* Header */
2N/A kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
2N/A kiov[i].data.length = 16;
2N/A kiov[i].data.data = (char *)header->buffer.value;
2N/A i++;
2N/A
2N/A /* Checksum */
2N/A kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
2N/A if (trailer == NULL) {
2N/A kiov[i].data.length = header->buffer.length - 16;
2N/A kiov[i].data.data = (char *)header->buffer.value + 16;
2N/A } else {
2N/A kiov[i].data.length = trailer->buffer.length;
2N/A kiov[i].data.data = (char *)trailer->buffer.value;
2N/A }
2N/A i++;
2N/A
2N/A if (verify)
2N/A code = krb5_k_verify_checksum_iov(context, type, key, sign_usage, kiov, kiov_count, valid);
2N/A else
2N/A code = krb5_k_make_checksum_iov(context, type, key, sign_usage, kiov, kiov_count);
2N/A
2N/A xfree(kiov);
2N/A
2N/A return code;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Akg_make_checksum_iov_v3(krb5_context context,
2N/A krb5_cksumtype type,
2N/A size_t rrc,
2N/A krb5_key key,
2N/A krb5_keyusage sign_usage,
2N/A gss_iov_buffer_desc *iov,
2N/A int iov_count)
2N/A{
2N/A return checksum_iov_v3(context, type, rrc, key,
2N/A sign_usage, iov, iov_count, 0, NULL);
2N/A}
2N/A
2N/Akrb5_error_code
2N/Akg_verify_checksum_iov_v3(krb5_context context,
2N/A krb5_cksumtype type,
2N/A size_t rrc,
2N/A krb5_key key,
2N/A krb5_keyusage sign_usage,
2N/A gss_iov_buffer_desc *iov,
2N/A int iov_count,
2N/A krb5_boolean *valid)
2N/A{
2N/A return checksum_iov_v3(context, type, rrc, key,
2N/A sign_usage, iov, iov_count, 1, valid);
2N/A}
2N/A#endif /**************** END IFDEF'ed OUT *******************************/