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