1 /*
2  * Copyright (c) 2021 Ribose Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <stdio.h>
28 #include <memory>
29 #include <cassert>
30 #include <openssl/evp.h>
31 #include <openssl/err.h>
32 #include "config.h"
33 #include "hash.h"
34 #include "types.h"
35 #include "utils.h"
36 #include "str-utils.h"
37 #include "defaults.h"
38 #include "sha1cd/hash_sha1cd.h"
39 
40 static const id_str_pair openssl_alg_map[] = {
41   {PGP_HASH_MD5, "md5"},
42   {PGP_HASH_SHA1, "sha1"},
43   {PGP_HASH_RIPEMD, "ripemd160"},
44   {PGP_HASH_SHA256, "sha256"},
45   {PGP_HASH_SHA384, "sha384"},
46   {PGP_HASH_SHA512, "sha512"},
47   {PGP_HASH_SHA224, "sha224"},
48   {PGP_HASH_SM3, "sm3"},
49   {PGP_HASH_SHA3_256, "sha3-256"},
50   {PGP_HASH_SHA3_512, "sha3-512"},
51   {0, NULL},
52 };
53 
54 namespace rnp {
Hash(pgp_hash_alg_t alg)55 Hash::Hash(pgp_hash_alg_t alg)
56 {
57     if (alg == PGP_HASH_SHA1) {
58         handle_ = hash_sha1cd_create();
59         if (!handle_) {
60             throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY);
61         }
62         alg_ = alg;
63         size_ = rnp::Hash::size(alg);
64         return;
65     }
66     const char *hash_name = rnp::Hash::name_backend(alg);
67     if (!hash_name) {
68         throw rnp_exception(RNP_ERROR_BAD_PARAMETERS);
69     }
70 #if !defined(ENABLE_SM2)
71     if (alg == PGP_HASH_SM3) {
72         RNP_LOG("SM3 hash is not available.");
73         throw rnp_exception(RNP_ERROR_BAD_PARAMETERS);
74     }
75 #endif
76     const EVP_MD *hash_tp = EVP_get_digestbyname(hash_name);
77     if (!hash_tp) {
78         RNP_LOG("Error creating hash object for '%s'", hash_name);
79         throw rnp_exception(RNP_ERROR_BAD_STATE);
80     }
81     EVP_MD_CTX *hash_fn = EVP_MD_CTX_new();
82     if (!hash_fn) {
83         RNP_LOG("Allocation failure");
84         throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY);
85     }
86     int res = EVP_DigestInit_ex(hash_fn, hash_tp, NULL);
87     if (res != 1) {
88         RNP_LOG("Digest initializataion error %d : %lu", res, ERR_peek_last_error());
89         EVP_MD_CTX_free(hash_fn);
90         throw rnp_exception(RNP_ERROR_BAD_STATE);
91     }
92 
93     alg_ = alg;
94     size_ = EVP_MD_size(hash_tp);
95     handle_ = hash_fn;
96 }
97 
98 void
add(const void * buf,size_t len)99 Hash::add(const void *buf, size_t len)
100 {
101     if (!handle_) {
102         throw rnp_exception(RNP_ERROR_NULL_POINTER);
103     }
104     if (alg_ == PGP_HASH_SHA1) {
105         hash_sha1cd_add(handle_, buf, len);
106         return;
107     }
108     assert(alg_ != PGP_HASH_UNKNOWN);
109 
110     EVP_MD_CTX *hash_fn = static_cast<EVP_MD_CTX *>(handle_);
111     int         res = EVP_DigestUpdate(hash_fn, buf, len);
112     if (res != 1) {
113         RNP_LOG("Digest updating error %d: %lu", res, ERR_peek_last_error());
114         throw rnp_exception(RNP_ERROR_GENERIC);
115     }
116 }
117 
118 size_t
finish(uint8_t * digest)119 Hash::finish(uint8_t *digest)
120 {
121     if (!handle_) {
122         return 0;
123     }
124     if (alg_ == PGP_HASH_SHA1) {
125         int res = hash_sha1cd_finish(handle_, digest);
126         handle_ = NULL;
127         size_ = 0;
128         if (res) {
129             throw rnp_exception(RNP_ERROR_BAD_STATE);
130         }
131         return 20;
132     }
133     assert(alg_ != PGP_HASH_UNKNOWN);
134 
135     EVP_MD_CTX *hash_fn = static_cast<EVP_MD_CTX *>(handle_);
136     int         res = digest ? EVP_DigestFinal_ex(hash_fn, digest, NULL) : 1;
137     EVP_MD_CTX_free(hash_fn);
138     handle_ = NULL;
139     if (res != 1) {
140         RNP_LOG("Digest finalization error %d: %lu", res, ERR_peek_last_error());
141         return 0;
142     }
143 
144     size_t outsz = size_;
145     size_ = 0;
146     alg_ = PGP_HASH_UNKNOWN;
147     return outsz;
148 }
149 
150 void
clone(Hash & dst) const151 Hash::clone(Hash &dst) const
152 {
153     if (!handle_) {
154         throw rnp_exception(RNP_ERROR_BAD_PARAMETERS);
155     }
156 
157     assert(alg_ != PGP_HASH_UNKNOWN);
158 
159     if (dst.handle_) {
160         dst.finish();
161     }
162 
163     if (alg_ == PGP_HASH_SHA1) {
164         dst.handle_ = hash_sha1cd_clone(handle_);
165         if (!dst.handle_) {
166             throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY);
167         }
168         dst.size_ = size_;
169         dst.alg_ = alg_;
170         return;
171     }
172 
173     EVP_MD_CTX *hash_fn = EVP_MD_CTX_new();
174     if (!hash_fn) {
175         RNP_LOG("Allocation failure");
176         throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY);
177     }
178 
179     int res = EVP_MD_CTX_copy(hash_fn, static_cast<EVP_MD_CTX *>(handle_));
180     if (res != 1) {
181         RNP_LOG("Digest copying error %d: %lu", res, ERR_peek_last_error());
182         EVP_MD_CTX_free(hash_fn);
183         throw rnp_exception(RNP_ERROR_BAD_STATE);
184     }
185 
186     dst.size_ = size_;
187     dst.alg_ = alg_;
188     dst.handle_ = hash_fn;
189 }
190 
~Hash()191 Hash::~Hash()
192 {
193     if (!handle_) {
194         return;
195     }
196     if (alg_ == PGP_HASH_SHA1) {
197         hash_sha1cd_finish(handle_, NULL);
198     } else {
199         EVP_MD_CTX_free(static_cast<EVP_MD_CTX *>(handle_));
200     }
201 }
202 
203 const char *
name_backend(pgp_hash_alg_t alg)204 Hash::name_backend(pgp_hash_alg_t alg)
205 {
206     return id_str_pair::lookup(openssl_alg_map, alg);
207 }
208 } // namespace rnp
209