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