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