1 /*
2 * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com).
3 * Copyright (c) 2009 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is originally derived from software contributed to
7 * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and
8 * carried further by Ribose Inc (https://www.ribose.com).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 /*
32 * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
33 * All rights reserved.
34 * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
35 * their moral rights under the UK Copyright Design and Patents Act 1988 to
36 * be recorded as the authors of this copyright work.
37 *
38 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
39 * use this file except in compliance with the License.
40 *
41 * You may obtain a copy of the License at
42 * http://www.apache.org/licenses/LICENSE-2.0
43 *
44 * Unless required by applicable law or agreed to in writing, software
45 * distributed under the License is distributed on an "AS IS" BASIS,
46 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
47 *
48 * See the License for the specific language governing permissions and
49 * limitations under the License.
50 */
51 #include "config.h"
52
53 #ifdef HAVE_SYS_CDEFS_H
54 #include <sys/cdefs.h>
55 #endif
56
57 #if defined(__NetBSD__)
58 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
59 __RCSID("$NetBSD: crypto.c,v 1.36 2014/02/17 07:39:19 agc Exp $");
60 #endif
61
62 #include <sys/types.h>
63 #include <sys/stat.h>
64
65 #ifdef HAVE_UNISTD_H
66 #include <unistd.h>
67 #endif
68
69 #include <string.h>
70 #include <time.h>
71 #include <rnp/rnp_def.h>
72
73 #include <librepgp/stream-packet.h>
74 #include <librepgp/stream-key.h>
75
76 #include "types.h"
77 #include "crypto/common.h"
78 #include "crypto.h"
79 #include "fingerprint.h"
80 #include "pgp-key.h"
81 #include "utils.h"
82
83 bool
pgp_generate_seckey(const rnp_keygen_crypto_params_t & crypto,pgp_key_pkt_t & seckey,bool primary)84 pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto,
85 pgp_key_pkt_t & seckey,
86 bool primary)
87 {
88 /* populate pgp key structure */
89 seckey = {};
90 seckey.version = PGP_V4;
91 seckey.creation_time = time(NULL);
92 seckey.alg = crypto.key_alg;
93 seckey.material.alg = crypto.key_alg;
94 seckey.tag = primary ? PGP_PKT_SECRET_KEY : PGP_PKT_SECRET_SUBKEY;
95
96 switch (seckey.alg) {
97 case PGP_PKA_RSA:
98 if (rsa_generate(&crypto.ctx->rng, &seckey.material.rsa, crypto.rsa.modulus_bit_len)) {
99 RNP_LOG("failed to generate RSA key");
100 return false;
101 }
102 break;
103 case PGP_PKA_DSA:
104 if (dsa_generate(&crypto.ctx->rng,
105 &seckey.material.dsa,
106 crypto.dsa.p_bitlen,
107 crypto.dsa.q_bitlen)) {
108 RNP_LOG("failed to generate DSA key");
109 return false;
110 }
111 break;
112 case PGP_PKA_EDDSA:
113 if (eddsa_generate(&crypto.ctx->rng, &seckey.material.ec)) {
114 RNP_LOG("failed to generate EDDSA key");
115 return false;
116 }
117 break;
118 case PGP_PKA_ECDH:
119 if (!ecdh_set_params(&seckey.material.ec, crypto.ecc.curve)) {
120 RNP_LOG("Unsupported curve [ID=%d]", crypto.ecc.curve);
121 return false;
122 }
123 if (crypto.ecc.curve == PGP_CURVE_25519) {
124 if (x25519_generate(&crypto.ctx->rng, &seckey.material.ec)) {
125 RNP_LOG("failed to generate x25519 key");
126 return false;
127 }
128 seckey.material.ec.curve = crypto.ecc.curve;
129 break;
130 }
131 [[fallthrough]];
132 case PGP_PKA_ECDSA:
133 case PGP_PKA_SM2:
134 if (!curve_supported(crypto.ecc.curve)) {
135 RNP_LOG("EC generate: curve %d is not supported.", (int) crypto.ecc.curve);
136 return false;
137 }
138 if (ec_generate(&crypto.ctx->rng, &seckey.material.ec, seckey.alg, crypto.ecc.curve)) {
139 RNP_LOG("failed to generate EC key");
140 return false;
141 }
142 seckey.material.ec.curve = crypto.ecc.curve;
143 break;
144 case PGP_PKA_ELGAMAL:
145 if (elgamal_generate(
146 &crypto.ctx->rng, &seckey.material.eg, crypto.elgamal.key_bitlen)) {
147 RNP_LOG("failed to generate ElGamal key");
148 return false;
149 }
150 break;
151 default:
152 RNP_LOG("key generation not implemented for PK alg: %d", seckey.alg);
153 return false;
154 }
155 seckey.sec_protection.s2k.usage = PGP_S2KU_NONE;
156 seckey.material.secret = true;
157 seckey.material.validity.mark_valid();
158 /* fill the sec_data/sec_len */
159 if (encrypt_secret_key(&seckey, NULL, crypto.ctx->rng)) {
160 RNP_LOG("failed to fill sec_data");
161 return false;
162 }
163 return true;
164 }
165
166 bool
key_material_equal(const pgp_key_material_t * key1,const pgp_key_material_t * key2)167 key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key2)
168 {
169 if (key1->alg != key2->alg) {
170 return false;
171 }
172
173 switch (key1->alg) {
174 case PGP_PKA_RSA:
175 case PGP_PKA_RSA_ENCRYPT_ONLY:
176 case PGP_PKA_RSA_SIGN_ONLY:
177 return mpi_equal(&key1->rsa.n, &key2->rsa.n) && mpi_equal(&key1->rsa.e, &key2->rsa.e);
178 case PGP_PKA_DSA:
179 return mpi_equal(&key1->dsa.p, &key2->dsa.p) &&
180 mpi_equal(&key1->dsa.q, &key2->dsa.q) &&
181 mpi_equal(&key1->dsa.g, &key2->dsa.g) && mpi_equal(&key1->dsa.y, &key2->dsa.y);
182 case PGP_PKA_ELGAMAL:
183 case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
184 return mpi_equal(&key1->eg.p, &key2->eg.p) && mpi_equal(&key1->eg.g, &key2->eg.g) &&
185 mpi_equal(&key1->eg.y, &key2->eg.y);
186 case PGP_PKA_EDDSA:
187 case PGP_PKA_ECDH:
188 case PGP_PKA_ECDSA:
189 case PGP_PKA_SM2:
190 return (key1->ec.curve == key2->ec.curve) && mpi_equal(&key1->ec.p, &key2->ec.p);
191 default:
192 RNP_LOG("unknown public key algorithm: %d", (int) key1->alg);
193 return false;
194 }
195 }
196
197 rnp_result_t
validate_pgp_key_material(const pgp_key_material_t * material,rnp::RNG * rng)198 validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng)
199 {
200 #ifdef FUZZERS_ENABLED
201 /* do not timeout on large keys during fuzzing */
202 return RNP_SUCCESS;
203 #else
204 switch (material->alg) {
205 case PGP_PKA_RSA:
206 case PGP_PKA_RSA_ENCRYPT_ONLY:
207 case PGP_PKA_RSA_SIGN_ONLY:
208 return rsa_validate_key(rng, &material->rsa, material->secret);
209 case PGP_PKA_DSA:
210 return dsa_validate_key(rng, &material->dsa, material->secret);
211 case PGP_PKA_EDDSA:
212 return eddsa_validate_key(rng, &material->ec, material->secret);
213 case PGP_PKA_ECDH:
214 if (!curve_supported(material->ec.curve)) {
215 /* allow to import key if curve is not supported */
216 RNP_LOG("ECDH validate: curve %d is not supported.", (int) material->ec.curve);
217 return RNP_SUCCESS;
218 }
219 return ecdh_validate_key(rng, &material->ec, material->secret);
220 case PGP_PKA_ECDSA:
221 if (!curve_supported(material->ec.curve)) {
222 /* allow to import key if curve is not supported */
223 RNP_LOG("ECDH validate: curve %d is not supported.", (int) material->ec.curve);
224 return RNP_SUCCESS;
225 }
226 return ecdsa_validate_key(rng, &material->ec, material->secret);
227 case PGP_PKA_SM2:
228 #if defined(ENABLE_SM2)
229 return sm2_validate_key(rng, &material->ec, material->secret);
230 #else
231 RNP_LOG("SM2 key validation is not available.");
232 return RNP_ERROR_NOT_IMPLEMENTED;
233 #endif
234 case PGP_PKA_ELGAMAL:
235 case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
236 return elgamal_validate_key(&material->eg, material->secret) ? RNP_SUCCESS :
237 RNP_ERROR_GENERIC;
238 default:
239 RNP_LOG("unknown public key algorithm: %d", (int) material->alg);
240 }
241
242 return RNP_ERROR_BAD_PARAMETERS;
243 #endif
244 }
245