1263635Sdes/* $OpenBSD: digest-openssl.c,v 1.2 2014/02/02 03:44:31 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 20263635Sdes#include <sys/types.h> 21263635Sdes#include <limits.h> 22263635Sdes#include <stdlib.h> 23263635Sdes#include <string.h> 24263635Sdes 25263635Sdes#include <openssl/evp.h> 26263635Sdes 27263635Sdes#include "openbsd-compat/openssl-compat.h" 28263635Sdes 29263635Sdes#include "buffer.h" 30263635Sdes#include "digest.h" 31263635Sdes 32263635Sdesstruct ssh_digest_ctx { 33263635Sdes int alg; 34263635Sdes EVP_MD_CTX mdctx; 35263635Sdes}; 36263635Sdes 37263635Sdesstruct ssh_digest { 38263635Sdes int id; 39263635Sdes const char *name; 40263635Sdes size_t digest_len; 41263635Sdes const EVP_MD *(*mdfunc)(void); 42263635Sdes}; 43263635Sdes 44263635Sdes/* NB. Indexed directly by algorithm number */ 45263635Sdesconst struct ssh_digest digests[] = { 46263635Sdes { SSH_DIGEST_MD5, "MD5", 16, EVP_md5 }, 47263635Sdes { SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 }, 48263635Sdes { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 }, 49263635Sdes#ifdef HAVE_EVP_SHA256 /* XXX replace with local if missing */ 50263635Sdes { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 }, 51263635Sdes { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 }, 52263635Sdes { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 }, 53263635Sdes#endif 54263635Sdes { -1, NULL, 0, NULL }, 55263635Sdes}; 56263635Sdes 57263635Sdesstatic const struct ssh_digest * 58263635Sdesssh_digest_by_alg(int alg) 59263635Sdes{ 60263635Sdes if (alg < 0 || alg >= SSH_DIGEST_MAX) 61263635Sdes return NULL; 62263635Sdes if (digests[alg].id != alg) /* sanity */ 63263635Sdes return NULL; 64263635Sdes return &(digests[alg]); 65263635Sdes} 66263635Sdes 67263635Sdessize_t 68263635Sdesssh_digest_bytes(int alg) 69263635Sdes{ 70263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 71263635Sdes 72263635Sdes return digest == NULL ? 0 : digest->digest_len; 73263635Sdes} 74263635Sdes 75263635Sdessize_t 76263635Sdesssh_digest_blocksize(struct ssh_digest_ctx *ctx) 77263635Sdes{ 78263635Sdes return EVP_MD_CTX_block_size(&ctx->mdctx); 79263635Sdes} 80263635Sdes 81263635Sdesstruct ssh_digest_ctx * 82263635Sdesssh_digest_start(int alg) 83263635Sdes{ 84263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 85263635Sdes struct ssh_digest_ctx *ret; 86263635Sdes 87263635Sdes if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL)) 88263635Sdes return NULL; 89263635Sdes ret->alg = alg; 90263635Sdes EVP_MD_CTX_init(&ret->mdctx); 91263635Sdes if (EVP_DigestInit_ex(&ret->mdctx, digest->mdfunc(), NULL) != 1) { 92263635Sdes free(ret); 93263635Sdes return NULL; 94263635Sdes } 95263635Sdes return ret; 96263635Sdes} 97263635Sdes 98263635Sdesint 99263635Sdesssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) 100263635Sdes{ 101263635Sdes /* we have bcopy-style order while openssl has memcpy-style */ 102263635Sdes if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx)) 103263635Sdes return -1; 104263635Sdes return 0; 105263635Sdes} 106263635Sdes 107263635Sdesint 108263635Sdesssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) 109263635Sdes{ 110263635Sdes if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1) 111263635Sdes return -1; 112263635Sdes return 0; 113263635Sdes} 114263635Sdes 115263635Sdesint 116263635Sdesssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b) 117263635Sdes{ 118263635Sdes return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b)); 119263635Sdes} 120263635Sdes 121263635Sdesint 122263635Sdesssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) 123263635Sdes{ 124263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); 125263635Sdes u_int l = dlen; 126263635Sdes 127263635Sdes if (dlen > UINT_MAX) 128263635Sdes return -1; 129263635Sdes if (dlen < digest->digest_len) /* No truncation allowed */ 130263635Sdes return -1; 131263635Sdes if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) 132263635Sdes return -1; 133263635Sdes if (l != digest->digest_len) /* sanity */ 134263635Sdes return -1; 135263635Sdes return 0; 136263635Sdes} 137263635Sdes 138263635Sdesvoid 139263635Sdesssh_digest_free(struct ssh_digest_ctx *ctx) 140263635Sdes{ 141263635Sdes if (ctx != NULL) { 142263635Sdes EVP_MD_CTX_cleanup(&ctx->mdctx); 143263635Sdes explicit_bzero(ctx, sizeof(*ctx)); 144263635Sdes free(ctx); 145263635Sdes } 146263635Sdes} 147263635Sdes 148263635Sdesint 149263635Sdesssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) 150263635Sdes{ 151263635Sdes struct ssh_digest_ctx *ctx = ssh_digest_start(alg); 152263635Sdes 153263635Sdes if (ctx == NULL) 154263635Sdes return -1; 155263635Sdes if (ssh_digest_update(ctx, m, mlen) != 0 || 156263635Sdes ssh_digest_final(ctx, d, dlen) != 0) 157263635Sdes return -1; 158263635Sdes ssh_digest_free(ctx); 159263635Sdes return 0; 160263635Sdes} 161263635Sdes 162263635Sdesint 163263635Sdesssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) 164263635Sdes{ 165263635Sdes return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen); 166263635Sdes} 167