Branch data Line data Source code
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 "includes.h"
19 : :
20 : : #include <sys/types.h>
21 : : #include <limits.h>
22 : : #include <stdlib.h>
23 : : #include <string.h>
24 : :
25 : : #include <openssl/evp.h>
26 : :
27 : : #include "openbsd-compat/openssl-compat.h"
28 : :
29 : : #include "buffer.h"
30 : : #include "digest.h"
31 : :
32 : : struct ssh_digest_ctx {
33 : : int alg;
34 : : EVP_MD_CTX mdctx;
35 : : };
36 : :
37 : : struct ssh_digest {
38 : : int id;
39 : : const char *name;
40 : : size_t digest_len;
41 : : const EVP_MD *(*mdfunc)(void);
42 : : };
43 : :
44 : : /* NB. Indexed directly by algorithm number */
45 : : const struct ssh_digest digests[] = {
46 : : { SSH_DIGEST_MD5, "MD5", 16, EVP_md5 },
47 : : { SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 },
48 : : { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 },
49 : : #ifdef HAVE_EVP_SHA256 /* XXX replace with local if missing */
50 : : { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 },
51 : : { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 },
52 : : { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 },
53 : : #endif
54 : : { -1, NULL, 0, NULL },
55 : : };
56 : :
57 : : static const struct ssh_digest *
58 : : ssh_digest_by_alg(int alg)
59 : : {
60 [ + - ][ + - ]: 195510 : if (alg < 0 || alg >= SSH_DIGEST_MAX)
[ + - ]
61 : : return NULL;
62 [ + - ][ + - ]: 195510 : if (digests[alg].id != alg) /* sanity */
[ + - ]
63 : : return NULL;
64 : 195510 : return &(digests[alg]);
65 : : }
66 : :
67 : : size_t
68 : 61896 : ssh_digest_bytes(int alg)
69 : : {
70 : 61896 : const struct ssh_digest *digest = ssh_digest_by_alg(alg);
71 : :
72 [ + - ]: 61896 : return digest == NULL ? 0 : digest->digest_len;
73 : : }
74 : :
75 : : size_t
76 : 4238 : ssh_digest_blocksize(struct ssh_digest_ctx *ctx)
77 : : {
78 : 4238 : return EVP_MD_CTX_block_size(&ctx->mdctx);
79 : : }
80 : :
81 : : struct ssh_digest_ctx *
82 : 40380 : ssh_digest_start(int alg)
83 : : {
84 : 40380 : const struct ssh_digest *digest = ssh_digest_by_alg(alg);
85 : : struct ssh_digest_ctx *ret;
86 : :
87 [ + - ][ + - ]: 40380 : if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL))
88 : : return NULL;
89 : 40380 : ret->alg = alg;
90 : 40380 : EVP_MD_CTX_init(&ret->mdctx);
91 [ - + ]: 40380 : if (EVP_DigestInit_ex(&ret->mdctx, digest->mdfunc(), NULL) != 1) {
92 : 0 : free(ret);
93 : 0 : return NULL;
94 : : }
95 : : return ret;
96 : : }
97 : :
98 : : int
99 : 69776 : ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
100 : : {
101 : : /* we have bcopy-style order while openssl has memcpy-style */
102 [ + - ]: 69776 : if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx))
103 : : return -1;
104 : 69776 : return 0;
105 : : }
106 : :
107 : : int
108 : 143585 : ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
109 : : {
110 [ + - ][ + - ]: 170925 : if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1)
[ + - ]
111 : : return -1;
112 : 143585 : return 0;
113 : : }
114 : :
115 : : int
116 : 12384 : ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b)
117 : : {
118 : 12384 : return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b));
119 : : }
120 : :
121 : : int
122 : 93234 : ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
123 : : {
124 : 186468 : const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
125 : 93234 : u_int l = dlen;
126 : :
127 [ + - ]: 93234 : if (dlen > UINT_MAX)
128 : : return -1;
129 [ + - ]: 93234 : if (dlen < digest->digest_len) /* No truncation allowed */
130 : : return -1;
131 [ + - ]: 93234 : if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1)
132 : : return -1;
133 [ + - ]: 93234 : if (l != digest->digest_len) /* sanity */
134 : : return -1;
135 : 93234 : return 0;
136 : : }
137 : :
138 : : void
139 : 29397 : ssh_digest_free(struct ssh_digest_ctx *ctx)
140 : : {
141 [ + - ]: 29397 : if (ctx != NULL) {
142 : 29397 : EVP_MD_CTX_cleanup(&ctx->mdctx);
143 : 29397 : explicit_bzero(ctx, sizeof(*ctx));
144 : 29397 : free(ctx);
145 : : }
146 : 29397 : }
147 : :
148 : : int
149 : 14956 : ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
150 : : {
151 : 14956 : struct ssh_digest_ctx *ctx = ssh_digest_start(alg);
152 : :
153 [ + - ]: 14956 : if (ctx == NULL)
154 : : return -1;
155 [ + - + - ]: 29912 : if (ssh_digest_update(ctx, m, mlen) != 0 ||
156 : 14956 : ssh_digest_final(ctx, d, dlen) != 0)
157 : : return -1;
158 : 14956 : ssh_digest_free(ctx);
159 : 14956 : return 0;
160 : : }
161 : :
162 : : int
163 : 1872 : ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen)
164 : : {
165 : 1872 : return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen);
166 : : }
|