1295367Sdes/* $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 20295367Sdes#ifdef WITH_OPENSSL 21295367Sdes 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 31295367Sdes#include "sshbuf.h" 32263635Sdes#include "digest.h" 33295367Sdes#include "ssherr.h" 34263635Sdes 35295367Sdes#ifndef HAVE_EVP_RIPEMD160 36295367Sdes# define EVP_ripemd160 NULL 37295367Sdes#endif /* HAVE_EVP_RIPEMD160 */ 38295367Sdes#ifndef HAVE_EVP_SHA256 39295367Sdes# define EVP_sha256 NULL 40295367Sdes# define EVP_sha384 NULL 41295367Sdes# define EVP_sha512 NULL 42295367Sdes#endif /* HAVE_EVP_SHA256 */ 43295367Sdes 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; 74295367Sdes if (digests[alg].mdfunc == NULL) 75295367Sdes return NULL; 76263635Sdes return &(digests[alg]); 77263635Sdes} 78263635Sdes 79295367Sdesint 80295367Sdesssh_digest_alg_by_name(const char *name) 81295367Sdes{ 82295367Sdes int alg; 83295367Sdes 84295367Sdes for (alg = 0; digests[alg].id != -1; alg++) { 85295367Sdes if (strcasecmp(name, digests[alg].name) == 0) 86295367Sdes return digests[alg].id; 87295367Sdes } 88295367Sdes return -1; 89295367Sdes} 90295367Sdes 91295367Sdesconst char * 92295367Sdesssh_digest_alg_name(int alg) 93295367Sdes{ 94295367Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 95295367Sdes 96295367Sdes return digest == NULL ? NULL : digest->name; 97295367Sdes} 98295367Sdes 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{ 133295367Sdes if (from->alg != to->alg) 134295367Sdes 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)) 137295367Sdes 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) 145295367Sdes return SSH_ERR_LIBCRYPTO_ERROR; 146263635Sdes return 0; 147263635Sdes} 148263635Sdes 149263635Sdesint 150295367Sdesssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b) 151263635Sdes{ 152295367Sdes 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) 162295367Sdes return SSH_ERR_INVALID_ARGUMENT; 163263635Sdes if (dlen < digest->digest_len) /* No truncation allowed */ 164295367Sdes return SSH_ERR_INVALID_ARGUMENT; 165263635Sdes if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) 166295367Sdes return SSH_ERR_LIBCRYPTO_ERROR; 167263635Sdes if (l != digest->digest_len) /* sanity */ 168295367Sdes 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{ 185295367Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 186295367Sdes u_int mdlen; 187263635Sdes 188295367Sdes if (digest == NULL) 189295367Sdes return SSH_ERR_INVALID_ARGUMENT; 190295367Sdes if (dlen > UINT_MAX) 191295367Sdes return SSH_ERR_INVALID_ARGUMENT; 192295367Sdes if (dlen < digest->digest_len) 193295367Sdes return SSH_ERR_INVALID_ARGUMENT; 194295367Sdes mdlen = dlen; 195295367Sdes if (!EVP_Digest(m, mlen, d, &mdlen, digest->mdfunc(), NULL)) 196295367Sdes return SSH_ERR_LIBCRYPTO_ERROR; 197263635Sdes return 0; 198263635Sdes} 199263635Sdes 200263635Sdesint 201295367Sdesssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen) 202263635Sdes{ 203295367Sdes return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen); 204263635Sdes} 205295367Sdes#endif /* WITH_OPENSSL */ 206