xref: /openbsd-src/usr.bin/ssh/digest-openssl.c (revision 5ad04d351680822078003e2b066cfc9680d6157d)
1 /* $OpenBSD: digest-openssl.c,v 1.2 2014/02/02 03:44:31 djm 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 		explicit_bzero(ctx, 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 }
161