Home | History | Annotate | Download | only in openssh
      1 /* $OpenBSD: digest-libc.c,v 1.5 2015/05/05 02:48:17 jsg Exp $ */
      2 /*
      3  * Copyright (c) 2013 Damien Miller <djm (at) mindrot.org>
      4  * Copyright (c) 2014 Markus Friedl.  All rights reserved.
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  */
     18 
     19 #include "includes.h"
     20 
     21 #ifndef WITH_OPENSSL
     22 
     23 #include <sys/types.h>
     24 #include <limits.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 
     28 #if 0
     29 #include <md5.h>
     30 #include <rmd160.h>
     31 #include <sha1.h>
     32 #include <sha2.h>
     33 #endif
     34 
     35 #include "ssherr.h"
     36 #include "sshbuf.h"
     37 #include "digest.h"
     38 
     39 typedef void md_init_fn(void *mdctx);
     40 typedef void md_update_fn(void *mdctx, const u_int8_t *m, size_t mlen);
     41 typedef void md_final_fn(u_int8_t[], void *mdctx);
     42 
     43 struct ssh_digest_ctx {
     44 	int alg;
     45 	void *mdctx;
     46 };
     47 
     48 struct ssh_digest {
     49 	int id;
     50 	const char *name;
     51 	size_t block_len;
     52 	size_t digest_len;
     53 	size_t ctx_len;
     54 	md_init_fn *md_init;
     55 	md_update_fn *md_update;
     56 	md_final_fn *md_final;
     57 };
     58 
     59 /* NB. Indexed directly by algorithm number */
     60 const struct ssh_digest digests[SSH_DIGEST_MAX] = {
     61 	{
     62 		SSH_DIGEST_MD5,
     63 		"MD5",
     64 		MD5_BLOCK_LENGTH,
     65 		MD5_DIGEST_LENGTH,
     66 		sizeof(MD5_CTX),
     67 		(md_init_fn *) MD5Init,
     68 		(md_update_fn *) MD5Update,
     69 		(md_final_fn *) MD5Final
     70 	},
     71 	{
     72 		SSH_DIGEST_RIPEMD160,
     73 		"RIPEMD160",
     74 		RMD160_BLOCK_LENGTH,
     75 		RMD160_DIGEST_LENGTH,
     76 		sizeof(RMD160_CTX),
     77 		(md_init_fn *) RMD160Init,
     78 		(md_update_fn *) RMD160Update,
     79 		(md_final_fn *) RMD160Final
     80 	},
     81 	{
     82 		SSH_DIGEST_SHA1,
     83 		"SHA1",
     84 		SHA1_BLOCK_LENGTH,
     85 		SHA1_DIGEST_LENGTH,
     86 		sizeof(SHA1_CTX),
     87 		(md_init_fn *) SHA1Init,
     88 		(md_update_fn *) SHA1Update,
     89 		(md_final_fn *) SHA1Final
     90 	},
     91 	{
     92 		SSH_DIGEST_SHA256,
     93 		"SHA256",
     94 		SHA256_BLOCK_LENGTH,
     95 		SHA256_DIGEST_LENGTH,
     96 		sizeof(SHA256_CTX),
     97 		(md_init_fn *) SHA256_Init,
     98 		(md_update_fn *) SHA256_Update,
     99 		(md_final_fn *) SHA256_Final
    100 	},
    101 	{
    102 		SSH_DIGEST_SHA384,
    103 		"SHA384",
    104 		SHA384_BLOCK_LENGTH,
    105 		SHA384_DIGEST_LENGTH,
    106 		sizeof(SHA384_CTX),
    107 		(md_init_fn *) SHA384_Init,
    108 		(md_update_fn *) SHA384_Update,
    109 		(md_final_fn *) SHA384_Final
    110 	},
    111 	{
    112 		SSH_DIGEST_SHA512,
    113 		"SHA512",
    114 		SHA512_BLOCK_LENGTH,
    115 		SHA512_DIGEST_LENGTH,
    116 		sizeof(SHA512_CTX),
    117 		(md_init_fn *) SHA512_Init,
    118 		(md_update_fn *) SHA512_Update,
    119 		(md_final_fn *) SHA512_Final
    120 	}
    121 };
    122 
    123 static const struct ssh_digest *
    124 ssh_digest_by_alg(int alg)
    125 {
    126 	if (alg < 0 || alg >= SSH_DIGEST_MAX)
    127 		return NULL;
    128 	if (digests[alg].id != alg) /* sanity */
    129 		return NULL;
    130 	return &(digests[alg]);
    131 }
    132 
    133 int
    134 ssh_digest_alg_by_name(const char *name)
    135 {
    136 	int alg;
    137 
    138 	for (alg = 0; alg < SSH_DIGEST_MAX; alg++) {
    139 		if (strcasecmp(name, digests[alg].name) == 0)
    140 			return digests[alg].id;
    141 	}
    142 	return -1;
    143 }
    144 
    145 const char *
    146 ssh_digest_alg_name(int alg)
    147 {
    148 	const struct ssh_digest *digest = ssh_digest_by_alg(alg);
    149 
    150 	return digest == NULL ? NULL : digest->name;
    151 }
    152 
    153 size_t
    154 ssh_digest_bytes(int alg)
    155 {
    156 	const struct ssh_digest *digest = ssh_digest_by_alg(alg);
    157 
    158 	return digest == NULL ? 0 : digest->digest_len;
    159 }
    160 
    161 size_t
    162 ssh_digest_blocksize(struct ssh_digest_ctx *ctx)
    163 {
    164 	const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
    165 
    166 	return digest == NULL ? 0 : digest->block_len;
    167 }
    168 
    169 struct ssh_digest_ctx *
    170 ssh_digest_start(int alg)
    171 {
    172 	const struct ssh_digest *digest = ssh_digest_by_alg(alg);
    173 	struct ssh_digest_ctx *ret;
    174 
    175 	if (digest == NULL || (ret = calloc(1, sizeof(*ret))) == NULL)
    176 		return NULL;
    177 	if ((ret->mdctx = calloc(1, digest->ctx_len)) == NULL) {
    178 		free(ret);
    179 		return NULL;
    180 	}
    181 	ret->alg = alg;
    182 	digest->md_init(ret->mdctx);
    183 	return ret;
    184 }
    185 
    186 int
    187 ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
    188 {
    189 	const struct ssh_digest *digest = ssh_digest_by_alg(from->alg);
    190 
    191 	if (digest == NULL || from->alg != to->alg)
    192 		return SSH_ERR_INVALID_ARGUMENT;
    193 	memcpy(to->mdctx, from->mdctx, digest->ctx_len);
    194 	return 0;
    195 }
    196 
    197 int
    198 ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
    199 {
    200 	const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
    201 
    202 	if (digest == NULL)
    203 		return SSH_ERR_INVALID_ARGUMENT;
    204 	digest->md_update(ctx->mdctx, m, mlen);
    205 	return 0;
    206 }
    207 
    208 int
    209 ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b)
    210 {
    211 	return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b));
    212 }
    213 
    214 int
    215 ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
    216 {
    217 	const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
    218 
    219 	if (digest == NULL)
    220 		return SSH_ERR_INVALID_ARGUMENT;
    221 	if (dlen > UINT_MAX)
    222 		return SSH_ERR_INVALID_ARGUMENT;
    223 	if (dlen < digest->digest_len) /* No truncation allowed */
    224 		return SSH_ERR_INVALID_ARGUMENT;
    225 	digest->md_final(d, ctx->mdctx);
    226 	return 0;
    227 }
    228 
    229 void
    230 ssh_digest_free(struct ssh_digest_ctx *ctx)
    231 {
    232 	const struct ssh_digest *digest;
    233 
    234 	if (ctx != NULL) {
    235 		digest = ssh_digest_by_alg(ctx->alg);
    236 		if (digest) {
    237 			explicit_bzero(ctx->mdctx, digest->ctx_len);
    238 			free(ctx->mdctx);
    239 			explicit_bzero(ctx, sizeof(*ctx));
    240 			free(ctx);
    241 		}
    242 	}
    243 }
    244 
    245 int
    246 ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
    247 {
    248 	struct ssh_digest_ctx *ctx = ssh_digest_start(alg);
    249 
    250 	if (ctx == NULL)
    251 		return SSH_ERR_INVALID_ARGUMENT;
    252 	if (ssh_digest_update(ctx, m, mlen) != 0 ||
    253 	    ssh_digest_final(ctx, d, dlen) != 0)
    254 		return SSH_ERR_INVALID_ARGUMENT;
    255 	ssh_digest_free(ctx);
    256 	return 0;
    257 }
    258 
    259 int
    260 ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
    261 {
    262 	return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen);
    263 }
    264 #endif /* !WITH_OPENSSL */
    265