1 /*
2 * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com).
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 "ecdsa.h"
28 #include "utils.h"
29 #include <botan/ffi.h>
30 #include <string.h>
31 #include "bn.h"
32
33 static bool
ecdsa_load_public_key(botan_pubkey_t * pubkey,const pgp_ec_key_t * keydata)34 ecdsa_load_public_key(botan_pubkey_t *pubkey, const pgp_ec_key_t *keydata)
35 {
36 botan_mp_t px = NULL;
37 botan_mp_t py = NULL;
38 bool res = false;
39
40 const ec_curve_desc_t *curve = get_curve_desc(keydata->curve);
41 if (!curve) {
42 RNP_LOG("unknown curve");
43 return false;
44 }
45 const size_t curve_order = BITS_TO_BYTES(curve->bitlen);
46
47 if (!mpi_bytes(&keydata->p) || (keydata->p.mpi[0] != 0x04)) {
48 RNP_LOG(
49 "Failed to load public key: %zu, %02x", mpi_bytes(&keydata->p), keydata->p.mpi[0]);
50 return false;
51 }
52
53 if (botan_mp_init(&px) || botan_mp_init(&py) ||
54 botan_mp_from_bin(px, &keydata->p.mpi[1], curve_order) ||
55 botan_mp_from_bin(py, &keydata->p.mpi[1 + curve_order], curve_order)) {
56 goto end;
57 }
58
59 if (!(res = !botan_pubkey_load_ecdsa(pubkey, px, py, curve->botan_name))) {
60 RNP_LOG("failed to load ecdsa public key");
61 }
62 end:
63 botan_mp_destroy(px);
64 botan_mp_destroy(py);
65 return res;
66 }
67
68 static bool
ecdsa_load_secret_key(botan_privkey_t * seckey,const pgp_ec_key_t * keydata)69 ecdsa_load_secret_key(botan_privkey_t *seckey, const pgp_ec_key_t *keydata)
70 {
71 const ec_curve_desc_t *curve;
72 bignum_t * x = NULL;
73 bool res = false;
74
75 if (!(curve = get_curve_desc(keydata->curve))) {
76 return false;
77 }
78 if (!(x = mpi2bn(&keydata->x))) {
79 return false;
80 }
81 if (!(res = !botan_privkey_load_ecdsa(seckey, BN_HANDLE_PTR(x), curve->botan_name))) {
82 RNP_LOG("Can't load private key");
83 }
84 bn_free(x);
85 return res;
86 }
87
88 rnp_result_t
ecdsa_validate_key(rnp::RNG * rng,const pgp_ec_key_t * key,bool secret)89 ecdsa_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret)
90 {
91 botan_pubkey_t bpkey = NULL;
92 botan_privkey_t bskey = NULL;
93 rnp_result_t ret = RNP_ERROR_BAD_PARAMETERS;
94
95 if (!ecdsa_load_public_key(&bpkey, key) ||
96 botan_pubkey_check_key(bpkey, rng->handle(), 0)) {
97 goto done;
98 }
99 if (!secret) {
100 ret = RNP_SUCCESS;
101 goto done;
102 }
103
104 if (!ecdsa_load_secret_key(&bskey, key) ||
105 botan_privkey_check_key(bskey, rng->handle(), 0)) {
106 goto done;
107 }
108 ret = RNP_SUCCESS;
109 done:
110 botan_privkey_destroy(bskey);
111 botan_pubkey_destroy(bpkey);
112 return ret;
113 }
114
115 static const char *
ecdsa_padding_str_for(pgp_hash_alg_t hash_alg)116 ecdsa_padding_str_for(pgp_hash_alg_t hash_alg)
117 {
118 switch (hash_alg) {
119 case PGP_HASH_MD5:
120 return "Raw(MD5)";
121 case PGP_HASH_SHA1:
122 return "Raw(SHA-1)";
123 case PGP_HASH_RIPEMD:
124 return "Raw(RIPEMD-160)";
125
126 case PGP_HASH_SHA256:
127 return "Raw(SHA-256)";
128 case PGP_HASH_SHA384:
129 return "Raw(SHA-384)";
130 case PGP_HASH_SHA512:
131 return "Raw(SHA-512)";
132 case PGP_HASH_SHA224:
133 return "Raw(SHA-224)";
134 case PGP_HASH_SHA3_256:
135 return "Raw(SHA3(256))";
136 case PGP_HASH_SHA3_512:
137 return "Raw(SHA3(512))";
138
139 case PGP_HASH_SM3:
140 return "Raw(SM3)";
141 default:
142 return "Raw";
143 }
144 }
145
146 rnp_result_t
ecdsa_sign(rnp::RNG * rng,pgp_ec_signature_t * sig,pgp_hash_alg_t hash_alg,const uint8_t * hash,size_t hash_len,const pgp_ec_key_t * key)147 ecdsa_sign(rnp::RNG * rng,
148 pgp_ec_signature_t *sig,
149 pgp_hash_alg_t hash_alg,
150 const uint8_t * hash,
151 size_t hash_len,
152 const pgp_ec_key_t *key)
153 {
154 botan_pk_op_sign_t signer = NULL;
155 botan_privkey_t b_key = NULL;
156 rnp_result_t ret = RNP_ERROR_GENERIC;
157 uint8_t out_buf[2 * MAX_CURVE_BYTELEN] = {0};
158 const ec_curve_desc_t *curve = get_curve_desc(key->curve);
159 const char * padding_str = ecdsa_padding_str_for(hash_alg);
160
161 if (!curve) {
162 return RNP_ERROR_BAD_PARAMETERS;
163 }
164 const size_t curve_order = BITS_TO_BYTES(curve->bitlen);
165 size_t sig_len = 2 * curve_order;
166
167 if (!ecdsa_load_secret_key(&b_key, key)) {
168 RNP_LOG("Can't load private key");
169 goto end;
170 }
171
172 if (botan_pk_op_sign_create(&signer, b_key, padding_str, 0)) {
173 goto end;
174 }
175
176 if (botan_pk_op_sign_update(signer, hash, hash_len)) {
177 goto end;
178 }
179
180 if (botan_pk_op_sign_finish(signer, rng->handle(), out_buf, &sig_len)) {
181 RNP_LOG("Signing failed");
182 goto end;
183 }
184
185 // Allocate memory and copy results
186 if (mem2mpi(&sig->r, out_buf, curve_order) &&
187 mem2mpi(&sig->s, out_buf + curve_order, curve_order)) {
188 ret = RNP_SUCCESS;
189 }
190 end:
191 botan_privkey_destroy(b_key);
192 botan_pk_op_sign_destroy(signer);
193 return ret;
194 }
195
196 rnp_result_t
ecdsa_verify(const pgp_ec_signature_t * sig,pgp_hash_alg_t hash_alg,const uint8_t * hash,size_t hash_len,const pgp_ec_key_t * key)197 ecdsa_verify(const pgp_ec_signature_t *sig,
198 pgp_hash_alg_t hash_alg,
199 const uint8_t * hash,
200 size_t hash_len,
201 const pgp_ec_key_t * key)
202 {
203 botan_pubkey_t pub = NULL;
204 botan_pk_op_verify_t verifier = NULL;
205 rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID;
206 uint8_t sign_buf[2 * MAX_CURVE_BYTELEN] = {0};
207 size_t r_blen, s_blen;
208 const char * padding_str = ecdsa_padding_str_for(hash_alg);
209
210 const ec_curve_desc_t *curve = get_curve_desc(key->curve);
211 if (!curve) {
212 RNP_LOG("unknown curve");
213 return RNP_ERROR_BAD_PARAMETERS;
214 }
215 const size_t curve_order = BITS_TO_BYTES(curve->bitlen);
216
217 if (!ecdsa_load_public_key(&pub, key)) {
218 goto end;
219 }
220
221 if (botan_pk_op_verify_create(&verifier, pub, padding_str, 0)) {
222 goto end;
223 }
224
225 if (botan_pk_op_verify_update(verifier, hash, hash_len)) {
226 goto end;
227 }
228
229 r_blen = mpi_bytes(&sig->r);
230 s_blen = mpi_bytes(&sig->s);
231 if ((r_blen > curve_order) || (s_blen > curve_order) ||
232 (curve_order > MAX_CURVE_BYTELEN)) {
233 ret = RNP_ERROR_BAD_PARAMETERS;
234 goto end;
235 }
236
237 // Both can't fail
238 mpi2mem(&sig->r, &sign_buf[curve_order - r_blen]);
239 mpi2mem(&sig->s, &sign_buf[curve_order + curve_order - s_blen]);
240
241 if (!botan_pk_op_verify_finish(verifier, sign_buf, curve_order * 2)) {
242 ret = RNP_SUCCESS;
243 }
244 end:
245 botan_pubkey_destroy(pub);
246 botan_pk_op_verify_destroy(verifier);
247 return ret;
248 }
249
250 pgp_hash_alg_t
ecdsa_get_min_hash(pgp_curve_t curve)251 ecdsa_get_min_hash(pgp_curve_t curve)
252 {
253 switch (curve) {
254 case PGP_CURVE_NIST_P_256:
255 case PGP_CURVE_BP256:
256 case PGP_CURVE_P256K1:
257 return PGP_HASH_SHA256;
258 case PGP_CURVE_NIST_P_384:
259 case PGP_CURVE_BP384:
260 return PGP_HASH_SHA384;
261 case PGP_CURVE_NIST_P_521:
262 case PGP_CURVE_BP512:
263 return PGP_HASH_SHA512;
264 default:
265 return PGP_HASH_UNKNOWN;
266 }
267 }
268