1294332Sdes/* $OpenBSD: digest-openssl.c,v 1.5 2014/12/21 22:27:56 djm Exp $ */ 2263635Sdes/* 3263635Sdes * Copyright (c) 2013 Damien Miller <djm@mindrot.org> 4263635Sdes * 5263635Sdes * Permission to use, copy, modify, and distribute this software for any 6263635Sdes * purpose with or without fee is hereby granted, provided that the above 7263635Sdes * copyright notice and this permission notice appear in all copies. 8263635Sdes * 9263635Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10263635Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11263635Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12263635Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13263635Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14263635Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15263635Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16263635Sdes */ 17263635Sdes 18263635Sdes#include "includes.h" 19263635Sdes 20294332Sdes#ifdef WITH_OPENSSL 21294332Sdes 22263635Sdes#include <sys/types.h> 23263635Sdes#include <limits.h> 24263635Sdes#include <stdlib.h> 25263635Sdes#include <string.h> 26263635Sdes 27263635Sdes#include <openssl/evp.h> 28263635Sdes 29263635Sdes#include "openbsd-compat/openssl-compat.h" 30263635Sdes 31294328Sdes#include "sshbuf.h" 32263635Sdes#include "digest.h" 33294328Sdes#include "ssherr.h" 34263635Sdes 35294328Sdes#ifndef HAVE_EVP_RIPEMD160 36294328Sdes# define EVP_ripemd160 NULL 37294328Sdes#endif /* HAVE_EVP_RIPEMD160 */ 38294328Sdes#ifndef HAVE_EVP_SHA256 39294328Sdes# define EVP_sha256 NULL 40294328Sdes# define EVP_sha384 NULL 41294328Sdes# define EVP_sha512 NULL 42294328Sdes#endif /* HAVE_EVP_SHA256 */ 43294328Sdes 44263635Sdesstruct ssh_digest_ctx { 45263635Sdes int alg; 46263635Sdes EVP_MD_CTX mdctx; 47263635Sdes}; 48263635Sdes 49263635Sdesstruct ssh_digest { 50263635Sdes int id; 51263635Sdes const char *name; 52263635Sdes size_t digest_len; 53263635Sdes const EVP_MD *(*mdfunc)(void); 54263635Sdes}; 55263635Sdes 56263635Sdes/* NB. Indexed directly by algorithm number */ 57263635Sdesconst struct ssh_digest digests[] = { 58263635Sdes { SSH_DIGEST_MD5, "MD5", 16, EVP_md5 }, 59263635Sdes { SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 }, 60263635Sdes { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 }, 61263635Sdes { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 }, 62263635Sdes { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 }, 63263635Sdes { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 }, 64263635Sdes { -1, NULL, 0, NULL }, 65263635Sdes}; 66263635Sdes 67263635Sdesstatic const struct ssh_digest * 68263635Sdesssh_digest_by_alg(int alg) 69263635Sdes{ 70263635Sdes if (alg < 0 || alg >= SSH_DIGEST_MAX) 71263635Sdes return NULL; 72263635Sdes if (digests[alg].id != alg) /* sanity */ 73263635Sdes return NULL; 74294328Sdes if (digests[alg].mdfunc == NULL) 75294328Sdes return NULL; 76263635Sdes return &(digests[alg]); 77263635Sdes} 78263635Sdes 79294332Sdesint 80294332Sdesssh_digest_alg_by_name(const char *name) 81294332Sdes{ 82294332Sdes int alg; 83294332Sdes 84294332Sdes for (alg = 0; digests[alg].id != -1; alg++) { 85294332Sdes if (strcasecmp(name, digests[alg].name) == 0) 86294332Sdes return digests[alg].id; 87294332Sdes } 88294332Sdes return -1; 89294332Sdes} 90294332Sdes 91294332Sdesconst char * 92294332Sdesssh_digest_alg_name(int alg) 93294332Sdes{ 94294332Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 95294332Sdes 96294332Sdes return digest == NULL ? NULL : digest->name; 97294332Sdes} 98294332Sdes 99263635Sdessize_t 100263635Sdesssh_digest_bytes(int alg) 101263635Sdes{ 102263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 103263635Sdes 104263635Sdes return digest == NULL ? 0 : digest->digest_len; 105263635Sdes} 106263635Sdes 107263635Sdessize_t 108263635Sdesssh_digest_blocksize(struct ssh_digest_ctx *ctx) 109263635Sdes{ 110263635Sdes return EVP_MD_CTX_block_size(&ctx->mdctx); 111263635Sdes} 112263635Sdes 113263635Sdesstruct ssh_digest_ctx * 114263635Sdesssh_digest_start(int alg) 115263635Sdes{ 116263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 117263635Sdes struct ssh_digest_ctx *ret; 118263635Sdes 119263635Sdes if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL)) 120263635Sdes return NULL; 121263635Sdes ret->alg = alg; 122263635Sdes EVP_MD_CTX_init(&ret->mdctx); 123263635Sdes if (EVP_DigestInit_ex(&ret->mdctx, digest->mdfunc(), NULL) != 1) { 124263635Sdes free(ret); 125263635Sdes return NULL; 126263635Sdes } 127263635Sdes return ret; 128263635Sdes} 129263635Sdes 130263635Sdesint 131263635Sdesssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) 132263635Sdes{ 133294328Sdes if (from->alg != to->alg) 134294328Sdes return SSH_ERR_INVALID_ARGUMENT; 135263635Sdes /* we have bcopy-style order while openssl has memcpy-style */ 136263635Sdes if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx)) 137294328Sdes return SSH_ERR_LIBCRYPTO_ERROR; 138263635Sdes return 0; 139263635Sdes} 140263635Sdes 141263635Sdesint 142263635Sdesssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) 143263635Sdes{ 144263635Sdes if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1) 145294328Sdes return SSH_ERR_LIBCRYPTO_ERROR; 146263635Sdes return 0; 147263635Sdes} 148263635Sdes 149263635Sdesint 150294328Sdesssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b) 151263635Sdes{ 152294328Sdes return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b)); 153263635Sdes} 154263635Sdes 155263635Sdesint 156263635Sdesssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) 157263635Sdes{ 158263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); 159263635Sdes u_int l = dlen; 160263635Sdes 161263635Sdes if (dlen > UINT_MAX) 162294328Sdes return SSH_ERR_INVALID_ARGUMENT; 163263635Sdes if (dlen < digest->digest_len) /* No truncation allowed */ 164294328Sdes return SSH_ERR_INVALID_ARGUMENT; 165263635Sdes if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) 166294328Sdes return SSH_ERR_LIBCRYPTO_ERROR; 167263635Sdes if (l != digest->digest_len) /* sanity */ 168294328Sdes return SSH_ERR_INTERNAL_ERROR; 169263635Sdes return 0; 170263635Sdes} 171263635Sdes 172263635Sdesvoid 173263635Sdesssh_digest_free(struct ssh_digest_ctx *ctx) 174263635Sdes{ 175263635Sdes if (ctx != NULL) { 176263635Sdes EVP_MD_CTX_cleanup(&ctx->mdctx); 177263635Sdes explicit_bzero(ctx, sizeof(*ctx)); 178263635Sdes free(ctx); 179263635Sdes } 180263635Sdes} 181263635Sdes 182263635Sdesint 183263635Sdesssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) 184263635Sdes{ 185294328Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 186294328Sdes u_int mdlen; 187263635Sdes 188294328Sdes if (digest == NULL) 189294328Sdes return SSH_ERR_INVALID_ARGUMENT; 190294328Sdes if (dlen > UINT_MAX) 191294328Sdes return SSH_ERR_INVALID_ARGUMENT; 192294328Sdes if (dlen < digest->digest_len) 193294328Sdes return SSH_ERR_INVALID_ARGUMENT; 194294328Sdes mdlen = dlen; 195294328Sdes if (!EVP_Digest(m, mlen, d, &mdlen, digest->mdfunc(), NULL)) 196294328Sdes return SSH_ERR_LIBCRYPTO_ERROR; 197263635Sdes return 0; 198263635Sdes} 199263635Sdes 200263635Sdesint 201294328Sdesssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen) 202263635Sdes{ 203294328Sdes return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen); 204263635Sdes} 205294332Sdes#endif /* WITH_OPENSSL */ 206