Blame src/lib/crypto/openssl/hmac.c

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/* lib/crypto/openssl/hmac.c */
Packit fd8b60
/*
Packit fd8b60
 * Copyright (C) 2009 by the Massachusetts Institute of Technology.
Packit fd8b60
 * All rights reserved.
Packit fd8b60
 *
Packit fd8b60
 * Export of this software from the United States of America may
Packit fd8b60
 *   require a specific license from the United States Government.
Packit fd8b60
 *   It is the responsibility of any person or organization contemplating
Packit fd8b60
 *   export to obtain such a license before exporting.
Packit fd8b60
 *
Packit fd8b60
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
Packit fd8b60
 * distribute this software and its documentation for any purpose and
Packit fd8b60
 * without fee is hereby granted, provided that the above copyright
Packit fd8b60
 * notice appear in all copies and that both that copyright notice and
Packit fd8b60
 * this permission notice appear in supporting documentation, and that
Packit fd8b60
 * the name of M.I.T. not be used in advertising or publicity pertaining
Packit fd8b60
 * to distribution of the software without specific, written prior
Packit fd8b60
 * permission.  Furthermore if you modify this software you must label
Packit fd8b60
 * your software as modified software and not distribute it in such a
Packit fd8b60
 * fashion that it might be confused with the original M.I.T. software.
Packit fd8b60
 * M.I.T. makes no representations about the suitability of
Packit fd8b60
 * this software for any purpose.  It is provided "as is" without express
Packit fd8b60
 * or implied warranty.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Copyright (C) 1998 by the FundsXpress, INC.
Packit fd8b60
 *
Packit fd8b60
 * All rights reserved.
Packit fd8b60
 *
Packit fd8b60
 * Export of this software from the United States of America may require
Packit fd8b60
 * a specific license from the United States Government.  It is the
Packit fd8b60
 * responsibility of any person or organization contemplating export to
Packit fd8b60
 * obtain such a license before exporting.
Packit fd8b60
 *
Packit fd8b60
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
Packit fd8b60
 * distribute this software and its documentation for any purpose and
Packit fd8b60
 * without fee is hereby granted, provided that the above copyright
Packit fd8b60
 * notice appear in all copies and that both that copyright notice and
Packit fd8b60
 * this permission notice appear in supporting documentation, and that
Packit fd8b60
 * the name of FundsXpress. not be used in advertising or publicity pertaining
Packit fd8b60
 * to distribution of the software without specific, written prior
Packit fd8b60
 * permission.  FundsXpress makes no representations about the suitability of
Packit fd8b60
 * this software for any purpose.  It is provided "as is" without express
Packit fd8b60
 * or implied warranty.
Packit fd8b60
 *
Packit fd8b60
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
Packit fd8b60
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
Packit fd8b60
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
Packit fd8b60
#include "crypto_int.h"
Packit fd8b60
#include <openssl/hmac.h>
Packit fd8b60
#include <openssl/evp.h>
Packit fd8b60
Packit fd8b60
#if OPENSSL_VERSION_NUMBER < 0x10100000L
Packit fd8b60
Packit fd8b60
/* OpenSSL 1.1 makes HMAC_CTX opaque, while 1.0 does not have pointer
Packit fd8b60
 * constructors or destructors. */
Packit fd8b60
Packit fd8b60
#define HMAC_CTX_new compat_hmac_ctx_new
Packit fd8b60
static HMAC_CTX *
Packit fd8b60
compat_hmac_ctx_new()
Packit fd8b60
{
Packit fd8b60
    HMAC_CTX *ctx;
Packit fd8b60
Packit fd8b60
    ctx = calloc(1, sizeof(*ctx));
Packit fd8b60
    if (ctx != NULL)
Packit fd8b60
        HMAC_CTX_init(ctx);
Packit fd8b60
    return ctx;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
#define HMAC_CTX_free compat_hmac_ctx_free
Packit fd8b60
static void
Packit fd8b60
compat_hmac_ctx_free(HMAC_CTX *ctx)
Packit fd8b60
{
Packit fd8b60
    HMAC_CTX_cleanup(ctx);
Packit fd8b60
    free(ctx);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * the HMAC transform looks like:
Packit fd8b60
 *
Packit fd8b60
 * H(K XOR opad, H(K XOR ipad, text))
Packit fd8b60
 *
Packit fd8b60
 * where H is a cryptographic hash
Packit fd8b60
 * K is an n byte key
Packit fd8b60
 * ipad is the byte 0x36 repeated blocksize times
Packit fd8b60
 * opad is the byte 0x5c repeated blocksize times
Packit fd8b60
 * and text is the data being protected
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
static const EVP_MD *
Packit fd8b60
map_digest(const struct krb5_hash_provider *hash)
Packit fd8b60
{
Packit fd8b60
    if (!strncmp(hash->hash_name, "SHA1",4))
Packit fd8b60
        return EVP_sha1();
Packit fd8b60
    else if (!strncmp(hash->hash_name, "SHA-256",7))
Packit fd8b60
        return EVP_sha256();
Packit fd8b60
    else if (!strncmp(hash->hash_name, "SHA-384",7))
Packit fd8b60
        return EVP_sha384();
Packit Service e737ee
    else if (!strncmp(hash->hash_name, "MD5", 3))
Packit fd8b60
        return EVP_md5();
Packit fd8b60
    else if (!strncmp(hash->hash_name, "MD4", 3))
Packit fd8b60
        return EVP_md4();
Packit fd8b60
    else
Packit fd8b60
        return NULL;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
krb5_error_code
Packit fd8b60
krb5int_hmac_keyblock(const struct krb5_hash_provider *hash,
Packit fd8b60
                      const krb5_keyblock *keyblock,
Packit fd8b60
                      const krb5_crypto_iov *data, size_t num_data,
Packit fd8b60
                      krb5_data *output)
Packit fd8b60
{
Packit fd8b60
    unsigned int i = 0, md_len = 0, ok;
Packit fd8b60
    unsigned char md[EVP_MAX_MD_SIZE];
Packit fd8b60
    HMAC_CTX *ctx;
Packit fd8b60
    size_t hashsize, blocksize;
Packit fd8b60
Packit fd8b60
    hashsize = hash->hashsize;
Packit fd8b60
    blocksize = hash->blocksize;
Packit fd8b60
Packit fd8b60
    if (keyblock->length > blocksize)
Packit fd8b60
        return(KRB5_CRYPTO_INTERNAL);
Packit fd8b60
    if (output->length < hashsize)
Packit fd8b60
        return(KRB5_BAD_MSIZE);
Packit fd8b60
Packit fd8b60
    if (!map_digest(hash))
Packit fd8b60
        return(KRB5_CRYPTO_INTERNAL); // unsupported alg
Packit fd8b60
Packit fd8b60
    ctx = HMAC_CTX_new();
Packit fd8b60
    if (ctx == NULL)
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    ok = HMAC_Init_ex(ctx, keyblock->contents, keyblock->length,
Packit fd8b60
                      map_digest(hash), NULL);
Packit fd8b60
    for (i = 0; ok && i < num_data; i++) {
Packit fd8b60
        const krb5_crypto_iov *iov = &data[i];
Packit fd8b60
Packit fd8b60
        if (SIGN_IOV(iov))
Packit fd8b60
            ok = HMAC_Update(ctx, (uint8_t *)iov->data.data, iov->data.length);
Packit fd8b60
    }
Packit fd8b60
    if (ok)
Packit fd8b60
        ok = HMAC_Final(ctx, md, &md_len);
Packit fd8b60
    if (ok && md_len <= output->length) {
Packit fd8b60
        output->length = md_len;
Packit fd8b60
        memcpy(output->data, md, output->length);
Packit fd8b60
    }
Packit fd8b60
    HMAC_CTX_free(ctx);
Packit fd8b60
    return ok ? 0 : KRB5_CRYPTO_INTERNAL;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
krb5_error_code
Packit fd8b60
krb5int_hmac(const struct krb5_hash_provider *hash, krb5_key key,
Packit fd8b60
             const krb5_crypto_iov *data, size_t num_data,
Packit fd8b60
             krb5_data *output)
Packit fd8b60
{
Packit fd8b60
    return krb5int_hmac_keyblock(hash, &key->keyblock, data, num_data, output);
Packit fd8b60
}