Annotation of src/usr.bin/ssh/digest-openssl.c, Revision 1.1
1.1 ! markus 1: /* $OpenBSD: digest.c,v 1.4 2014/01/27 18:58:14 markus Exp $ */
! 2: /*
! 3: * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: #include <sys/types.h>
! 19: #include <limits.h>
! 20: #include <stdlib.h>
! 21: #include <string.h>
! 22:
! 23: #include <openssl/evp.h>
! 24:
! 25: #include "buffer.h"
! 26: #include "digest.h"
! 27:
! 28: struct ssh_digest_ctx {
! 29: int alg;
! 30: EVP_MD_CTX mdctx;
! 31: };
! 32:
! 33: struct ssh_digest {
! 34: int id;
! 35: const char *name;
! 36: size_t digest_len;
! 37: const EVP_MD *(*mdfunc)(void);
! 38: };
! 39:
! 40: /* NB. Indexed directly by algorithm number */
! 41: const struct ssh_digest digests[] = {
! 42: { SSH_DIGEST_MD5, "MD5", 16, EVP_md5 },
! 43: { SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 },
! 44: { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 },
! 45: { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 },
! 46: { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 },
! 47: { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 },
! 48: { -1, NULL, 0, NULL },
! 49: };
! 50:
! 51: static const struct ssh_digest *
! 52: ssh_digest_by_alg(int alg)
! 53: {
! 54: if (alg < 0 || alg >= SSH_DIGEST_MAX)
! 55: return NULL;
! 56: if (digests[alg].id != alg) /* sanity */
! 57: return NULL;
! 58: return &(digests[alg]);
! 59: }
! 60:
! 61: size_t
! 62: ssh_digest_bytes(int alg)
! 63: {
! 64: const struct ssh_digest *digest = ssh_digest_by_alg(alg);
! 65:
! 66: return digest == NULL ? 0 : digest->digest_len;
! 67: }
! 68:
! 69: size_t
! 70: ssh_digest_blocksize(struct ssh_digest_ctx *ctx)
! 71: {
! 72: return EVP_MD_CTX_block_size(&ctx->mdctx);
! 73: }
! 74:
! 75: struct ssh_digest_ctx *
! 76: ssh_digest_start(int alg)
! 77: {
! 78: const struct ssh_digest *digest = ssh_digest_by_alg(alg);
! 79: struct ssh_digest_ctx *ret;
! 80:
! 81: if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL))
! 82: return NULL;
! 83: ret->alg = alg;
! 84: EVP_MD_CTX_init(&ret->mdctx);
! 85: if (EVP_DigestInit_ex(&ret->mdctx, digest->mdfunc(), NULL) != 1) {
! 86: free(ret);
! 87: return NULL;
! 88: }
! 89: return ret;
! 90: }
! 91:
! 92: int
! 93: ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
! 94: {
! 95: /* we have bcopy-style order while openssl has memcpy-style */
! 96: if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx))
! 97: return -1;
! 98: return 0;
! 99: }
! 100:
! 101: int
! 102: ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
! 103: {
! 104: if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1)
! 105: return -1;
! 106: return 0;
! 107: }
! 108:
! 109: int
! 110: ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b)
! 111: {
! 112: return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b));
! 113: }
! 114:
! 115: int
! 116: ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
! 117: {
! 118: const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
! 119: u_int l = dlen;
! 120:
! 121: if (dlen > UINT_MAX)
! 122: return -1;
! 123: if (dlen < digest->digest_len) /* No truncation allowed */
! 124: return -1;
! 125: if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1)
! 126: return -1;
! 127: if (l != digest->digest_len) /* sanity */
! 128: return -1;
! 129: return 0;
! 130: }
! 131:
! 132: void
! 133: ssh_digest_free(struct ssh_digest_ctx *ctx)
! 134: {
! 135: if (ctx != NULL) {
! 136: EVP_MD_CTX_cleanup(&ctx->mdctx);
! 137: memset(ctx, 0, sizeof(*ctx));
! 138: free(ctx);
! 139: }
! 140: }
! 141:
! 142: int
! 143: ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
! 144: {
! 145: struct ssh_digest_ctx *ctx = ssh_digest_start(alg);
! 146:
! 147: if (ctx == NULL)
! 148: return -1;
! 149: if (ssh_digest_update(ctx, m, mlen) != 0 ||
! 150: ssh_digest_final(ctx, d, dlen) != 0)
! 151: return -1;
! 152: ssh_digest_free(ctx);
! 153: return 0;
! 154: }
! 155:
! 156: int
! 157: ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen)
! 158: {
! 159: return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen);
! 160: }