diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index fb65ac587c..b7f6022c65 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -364,9 +364,7 @@ add_library(librnp-obj OBJECT # other sources sec_profile.cpp - crypto.cpp fingerprint.cpp - generate-key.cpp key-provider.cpp logging.cpp json-utils.cpp @@ -374,6 +372,7 @@ add_library(librnp-obj OBJECT pass-provider.cpp sig_subpacket.cpp key_material.cpp + keygen.cpp pgp-key.cpp rnp.cpp ) diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp deleted file mode 100644 index a9a33b6968..0000000000 --- a/src/lib/crypto.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2017-2023, [Ribose Inc](https://www.ribose.com). - * Copyright (c) 2009 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/* - * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) - * All rights reserved. - * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted - * their moral rights under the UK Copyright Design and Patents Act 1988 to - * be recorded as the authors of this copyright work. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. - * - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "config.h" - -#ifdef HAVE_SYS_CDEFS_H -#include -#endif - -#if defined(__NetBSD__) -__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved."); -__RCSID("$NetBSD: crypto.c,v 1.36 2014/02/17 07:39:19 agc Exp $"); -#endif - -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include -#include -#include - -#include -#include - -#include "types.h" -#include "crypto/common.h" -#include "crypto.h" -#include "fingerprint.h" -#include "pgp-key.h" -#include "utils.h" - -bool -pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, - pgp_key_pkt_t & seckey, - bool primary, - pgp_version_t pgp_version) -{ - /* populate pgp key structure */ - seckey = {}; -#if defined(ENABLE_CRYPTO_REFRESH) - seckey.version = pgp_version; -#else - seckey.version = PGP_V4; -#endif - seckey.creation_time = crypto.ctx->time(); - seckey.alg = crypto.key_alg; - seckey.material = pgp::KeyMaterial::create(crypto.key_alg); - if (!seckey.material) { - RNP_LOG("Unsupported key algorithm: %d", crypto.key_alg); - return false; - } - seckey.tag = primary ? PGP_PKT_SECRET_KEY : PGP_PKT_SECRET_SUBKEY; - - if (!seckey.material->generate(crypto)) { - return false; - } - - seckey.sec_protection.s2k.usage = PGP_S2KU_NONE; - /* fill the sec_data/sec_len */ - if (encrypt_secret_key(&seckey, NULL, crypto.ctx->rng)) { - RNP_LOG("failed to fill sec_data"); - return false; - } - return true; -} diff --git a/src/lib/crypto.h b/src/lib/crypto.h deleted file mode 100644 index 47346f0f06..0000000000 --- a/src/lib/crypto.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). - * Copyright (c) 2009 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/* - * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) - * All rights reserved. - * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted - * their moral rights under the UK Copyright Design and Patents Act 1988 to - * be recorded as the authors of this copyright work. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. - * - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** \file - */ - -#ifndef CRYPTO_H_ -#define CRYPTO_H_ - -#include -#include "crypto/common.h" -#include - -/* raw key generation */ -bool pgp_generate_seckey(const rnp_keygen_crypto_params_t ¶ms, - pgp_key_pkt_t & seckey, - bool primary, - pgp_version_t pgp_version = PGP_V4); - -/** generate a new primary key - * - * @param desc keygen description - * @param merge_defaults true if you want defaults to be set for unset - * keygen description parameters. - * @param primary_sec pointer to store the generated secret key, must not be NULL - * @param primary_pub pointer to store the generated public key, must not be NULL - * @return true if successful, false otherwise. - **/ -bool pgp_generate_primary_key(rnp_keygen_primary_desc_t &desc, - bool merge_defaults, - pgp_key_t & primary_sec, - pgp_key_t & primary_pub, - pgp_key_store_format_t secformat); - -/** generate a new subkey - * - * @param desc keygen description - * @param merge_defaults true if you want defaults to be set for unset - * keygen description parameters. - * @param primary_sec pointer to the primary secret key that will own this - * subkey, must not be NULL - * @param primary_pub pointer to the primary public key that will own this - * subkey, must not be NULL - * @param subkey_sec pointer to store the generated secret key, must not be NULL - * @param subkey_pub pointer to store the generated public key, must not be NULL - * @param password_provider the password provider that will be used to - * decrypt the primary key, may be NULL if primary key is unlocked - * @return true if successful, false otherwise. - **/ -bool pgp_generate_subkey(rnp_keygen_subkey_desc_t & desc, - bool merge_defaults, - pgp_key_t & primary_sec, - pgp_key_t & primary_pub, - pgp_key_t & subkey_sec, - pgp_key_t & subkey_pub, - const pgp_password_provider_t &password_provider, - pgp_key_store_format_t secformat); - -#endif /* CRYPTO_H_ */ diff --git a/src/lib/crypto/dsa_common.cpp b/src/lib/crypto/dsa_common.cpp index e32a206feb..67d97ae706 100644 --- a/src/lib/crypto/dsa_common.cpp +++ b/src/lib/crypto/dsa_common.cpp @@ -24,10 +24,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "crypto.h" #include "config.h" #include "defaults.h" +#include "repgp/repgp_def.h" #include "dsa_common.h" +#include "dsa.h" +#include pgp_hash_alg_t dsa_get_min_hash(size_t qsize) diff --git a/src/lib/crypto/symmetric.cpp b/src/lib/crypto/symmetric.cpp index 8f713e0b58..e9e4ee8782 100644 --- a/src/lib/crypto/symmetric.cpp +++ b/src/lib/crypto/symmetric.cpp @@ -1,55 +1,29 @@ /* * Copyright (c) 2017-2024, [Ribose Inc](https://www.ribose.com). - * Copyright (c) 2009 The NetBSD Foundation, Inc. * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/* - * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) - * All rights reserved. - * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted - * their moral rights under the UK Copyright Design and Patents Act 1988 to - * be recorded as the authors of this copyright work. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. - * - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * - * See the License for the specific language governing permissions and - * limitations under the License. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "crypto.h" #include "config.h" #include "defaults.h" @@ -59,6 +33,8 @@ #include #include #include "utils.h" +#include "repgp/repgp_def.h" +#include "symmetric.h" static const char * pgp_sa_to_botan_string(int alg, bool silent = false) diff --git a/src/lib/crypto/symmetric_common.cpp b/src/lib/crypto/symmetric_common.cpp index 608e6fe00e..3c3da1c938 100644 --- a/src/lib/crypto/symmetric_common.cpp +++ b/src/lib/crypto/symmetric_common.cpp @@ -24,9 +24,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "crypto.h" #include "config.h" #include "defaults.h" +#include "symmetric.h" +#include void pgp_cipher_cfb_resync(pgp_crypt_t *crypt, const uint8_t *buf) diff --git a/src/lib/crypto/symmetric_ossl.cpp b/src/lib/crypto/symmetric_ossl.cpp index e9a42aed91..763687b4ad 100644 --- a/src/lib/crypto/symmetric_ossl.cpp +++ b/src/lib/crypto/symmetric_ossl.cpp @@ -24,7 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "crypto.h" #include "config.h" #include "defaults.h" @@ -35,6 +34,8 @@ #include #include "mem.h" #include "utils.h" +#include "repgp/repgp_def.h" +#include "symmetric.h" static const char * pgp_sa_to_openssl_string(int alg, bool silent = false) diff --git a/src/lib/ffi-priv-types.h b/src/lib/ffi-priv-types.h index 341ae5b00e..a9379f66a8 100644 --- a/src/lib/ffi-priv-types.h +++ b/src/lib/ffi-priv-types.h @@ -32,6 +32,7 @@ #include #include #include "sec_profile.hpp" +#include "keygen.hpp" struct rnp_key_handle_st { rnp_ffi_t ffi; @@ -145,7 +146,7 @@ struct rnp_output_st { }; struct rnp_op_generate_st { - rnp_ffi_t ffi{}; + rnp_ffi_t ffi; bool primary{}; pgp_key_t *primary_sec{}; pgp_key_t *primary_pub{}; @@ -154,13 +155,16 @@ struct rnp_op_generate_st { /* password used to encrypt the key, if specified */ rnp::secure_vector password; /* request password for key encryption via ffi's password provider */ - bool request_password{}; - /* we don't use top-level keygen action here for easier fields access */ - rnp_keygen_crypto_params_t crypto{}; + bool request_password{}; + rnp::KeygenParams keygen; rnp_key_protection_params_t protection{}; - rnp_selfsig_cert_info_t cert{}; - rnp_selfsig_binding_info_t binding{}; - pgp_version_t pgp_version = PGP_V4; + rnp::CertParams cert; + rnp::BindingParams binding; + + rnp_op_generate_st(rnp_ffi_t affi, pgp_pubkey_alg_t alg) + : ffi(affi), keygen(alg, affi->context) + { + } }; struct rnp_op_sign_signature_st { diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp deleted file mode 100644 index 8a8dd18ca8..0000000000 --- a/src/lib/generate-key.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/* - * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include -#include - -#include -#include -#include -#include "crypto.h" -#include "pgp-key.h" -#include "defaults.h" -#include "utils.h" - -static const uint8_t DEFAULT_SYMMETRIC_ALGS[] = { - PGP_SA_AES_256, PGP_SA_AES_192, PGP_SA_AES_128}; -static const uint8_t DEFAULT_HASH_ALGS[] = { - PGP_HASH_SHA256, PGP_HASH_SHA384, PGP_HASH_SHA512, PGP_HASH_SHA224}; -static const uint8_t DEFAULT_COMPRESS_ALGS[] = { - PGP_C_ZLIB, PGP_C_BZIP2, PGP_C_ZIP, PGP_C_NONE}; -#if defined(ENABLE_CRYPTO_REFRESH) -static const uint8_t DEFAULT_AEAD_ALGS[] = {PGP_AEAD_OCB}; -#endif - -static const id_str_pair pubkey_alg_map[] = { - {PGP_PKA_RSA, "RSA (Encrypt or Sign)"}, - {PGP_PKA_RSA_ENCRYPT_ONLY, "RSA Encrypt-Only"}, - {PGP_PKA_RSA_SIGN_ONLY, "RSA Sign-Only"}, - {PGP_PKA_ELGAMAL, "Elgamal (Encrypt-Only)"}, - {PGP_PKA_DSA, "DSA"}, - {PGP_PKA_ECDH, "ECDH"}, - {PGP_PKA_ECDSA, "ECDSA"}, - {PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN, "Reserved (formerly Elgamal Encrypt or Sign"}, - {PGP_PKA_RESERVED_DH, "Reserved for Diffie-Hellman (X9.42)"}, - {PGP_PKA_EDDSA, "EdDSA"}, - {PGP_PKA_SM2, "SM2"}, -#if defined(ENABLE_CRYPTO_REFRESH) - {PGP_PKA_ED25519, "ED25519"}, - {PGP_PKA_X25519, "X25519"}, -#endif -#if defined(ENABLE_PQC) - {PGP_PKA_KYBER768_X25519, "ML-KEM-768_X25519"}, - //{PGP_PKA_KYBER1024_X448, "Kyber-X448"}, - {PGP_PKA_KYBER768_P256, "ML-KEM-768_P256"}, - {PGP_PKA_KYBER1024_P384, "ML-KEM-1024_P384"}, - {PGP_PKA_KYBER768_BP256, "ML-KEM-768_BP256"}, - {PGP_PKA_KYBER1024_BP384, "ML-KEM-1024_BP384"}, - {PGP_PKA_DILITHIUM3_ED25519, "ML-DSA-65_ED25519"}, - //{PGP_PKA_DILITHIUM5_ED448, "Dilithium-ED448"}, - {PGP_PKA_DILITHIUM3_P256, "ML-DSA-65_P256"}, - {PGP_PKA_DILITHIUM5_P384, "ML-DSA-87_P384"}, - {PGP_PKA_DILITHIUM3_BP256, "ML-DSA-65_BP256"}, - {PGP_PKA_DILITHIUM5_BP384, "ML-DSA-87_BP384"}, - {PGP_PKA_SPHINCSPLUS_SHA2, "SLH-DSA-SHA2"}, - {PGP_PKA_SPHINCSPLUS_SHAKE, "SLH-DSA-SHAKE"}, - {PGP_PKA_PRIVATE00, "Private/Experimental"}, - {PGP_PKA_PRIVATE01, "Private/Experimental"}, - {PGP_PKA_PRIVATE02, "Private/Experimental"}, - {PGP_PKA_PRIVATE03, "Private/Experimental"}, - {PGP_PKA_PRIVATE04, "Private/Experimental"}, - {PGP_PKA_PRIVATE06, "Private/Experimental"}, - {PGP_PKA_PRIVATE08, "Private/Experimental"}, - {PGP_PKA_PRIVATE10, "Private/Experimental"}, -#else - {PGP_PKA_PRIVATE00, "Private/Experimental"}, - {PGP_PKA_PRIVATE01, "Private/Experimental"}, - {PGP_PKA_PRIVATE02, "Private/Experimental"}, - {PGP_PKA_PRIVATE03, "Private/Experimental"}, - {PGP_PKA_PRIVATE04, "Private/Experimental"}, - {PGP_PKA_PRIVATE05, "Private/Experimental"}, - {PGP_PKA_PRIVATE06, "Private/Experimental"}, - {PGP_PKA_PRIVATE07, "Private/Experimental"}, - {PGP_PKA_PRIVATE08, "Private/Experimental"}, - {PGP_PKA_PRIVATE09, "Private/Experimental"}, - {PGP_PKA_PRIVATE10, "Private/Experimental"}, -#endif - {0, NULL}}; - -static bool -load_generated_g10_key(pgp_key_t * dst, - pgp_key_pkt_t * newkey, - pgp_key_t * primary_key, - pgp_key_t * pubkey, - rnp::SecurityContext &ctx) -{ - // this should generally be zeroed - assert(dst->type() == 0); - // if a primary is provided, make sure it's actually a primary key - assert(!primary_key || primary_key->is_primary()); - // if a pubkey is provided, make sure it's actually a public key - assert(!pubkey || pubkey->is_public()); - // G10 always needs pubkey here - assert(pubkey); - - // this would be better on the stack but the key store does not allow it - std::unique_ptr key_store(new (std::nothrow) rnp::KeyStore(ctx)); - if (!key_store) { - return false; - } - /* Write g10 seckey */ - rnp::MemoryDest memdst(NULL, 0); - if (!g10_write_seckey(&memdst.dst(), newkey, NULL, ctx)) { - RNP_LOG("failed to write generated seckey"); - return false; - } - - std::vector key_ptrs; /* holds primary and pubkey, when used */ - // if this is a subkey, add the primary in first - if (primary_key) { - key_ptrs.push_back(primary_key); - } - // G10 needs the pubkey for copying some attributes (key version, creation time, etc) - key_ptrs.push_back(pubkey); - - rnp::MemorySource memsrc(memdst.memory(), memdst.writeb(), false); - rnp::KeyProvider prov(rnp_key_provider_key_ptr_list, &key_ptrs); - if (!key_store.get()->load_g10(memsrc.src(), &prov)) { - return false; - } - if (key_store.get()->key_count() != 1) { - return false; - } - // if a primary key is provided, it should match the sub with regards to type - assert(!primary_key || (primary_key->is_secret() == key_store->keys.front().is_secret())); - *dst = pgp_key_t(key_store->keys.front()); - return true; -} - -static uint8_t -pk_alg_default_flags(pgp_pubkey_alg_t alg) -{ - // just use the full capabilities as the ultimate fallback - return pgp_pk_alg_capabilities(alg); -} - -// TODO: Similar as pgp_pick_hash_alg but different enough to -// keep another version. This will be changed when refactoring crypto -static void -adjust_hash_alg(rnp_keygen_crypto_params_t &crypto) -{ - if (!crypto.hash_alg) { - crypto.hash_alg = (pgp_hash_alg_t) DEFAULT_HASH_ALGS[0]; - } - - if ((crypto.key_alg != PGP_PKA_DSA) && (crypto.key_alg != PGP_PKA_ECDSA)) { - return; - } - - pgp_hash_alg_t min_hash = (crypto.key_alg == PGP_PKA_ECDSA) ? - ecdsa_get_min_hash(crypto.ecc.curve) : - dsa_get_min_hash(crypto.dsa.q_bitlen); - - if (rnp::Hash::size(crypto.hash_alg) < rnp::Hash::size(min_hash)) { - crypto.hash_alg = min_hash; - } -} - -static void -keygen_merge_crypto_defaults(rnp_keygen_crypto_params_t &crypto) -{ - // default to RSA - if (!crypto.key_alg) { - crypto.key_alg = PGP_PKA_RSA; - } - - switch (crypto.key_alg) { - case PGP_PKA_RSA: - if (!crypto.rsa.modulus_bit_len) { - crypto.rsa.modulus_bit_len = DEFAULT_RSA_NUMBITS; - } - break; - - case PGP_PKA_SM2: - if (!crypto.hash_alg) { - crypto.hash_alg = PGP_HASH_SM3; - } - if (!crypto.ecc.curve) { - crypto.ecc.curve = PGP_CURVE_SM2_P_256; - } - break; - - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: { - if (!crypto.hash_alg) { - crypto.hash_alg = (pgp_hash_alg_t) DEFAULT_HASH_ALGS[0]; - } - break; - } - - case PGP_PKA_EDDSA: - if (!crypto.ecc.curve) { - crypto.ecc.curve = PGP_CURVE_ED25519; - } - break; - - case PGP_PKA_DSA: { - if (!crypto.dsa.p_bitlen) { - crypto.dsa.p_bitlen = DSA_DEFAULT_P_BITLEN; - } - if (!crypto.dsa.q_bitlen) { - crypto.dsa.q_bitlen = dsa_choose_qsize_by_psize(crypto.dsa.p_bitlen); - } - break; - } - default: - break; - } - - adjust_hash_alg(crypto); -} - -static bool -validate_keygen_primary(const rnp_keygen_primary_desc_t &desc) -{ - /* Confirm that the specified pk alg can certify. - * gpg requires this, though the RFC only says that a V4 primary - * key SHOULD be a key capable of certification. - */ - if (!(pgp_pk_alg_capabilities(desc.crypto.key_alg) & PGP_KF_CERTIFY)) { - RNP_LOG("primary key alg (%d) must be able to sign", desc.crypto.key_alg); - return false; - } - - // check key flags - if (!desc.cert.key_flags) { - // these are probably not *technically* required - RNP_LOG("key flags are required"); - return false; - } else if (desc.cert.key_flags & ~pgp_pk_alg_capabilities(desc.crypto.key_alg)) { - // check the flags against the alg capabilities - RNP_LOG("usage not permitted for pk algorithm"); - return false; - } - // require a userid - if (!desc.cert.userid[0]) { - RNP_LOG("userid is required for primary key"); - return false; - } - return true; -} - -static uint32_t -get_numbits(const rnp_keygen_crypto_params_t *crypto) -{ - switch (crypto->key_alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return crypto->rsa.modulus_bit_len; - case PGP_PKA_ECDSA: - case PGP_PKA_ECDH: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: { - if (const ec_curve_desc_t *curve = get_curve_desc(crypto->ecc.curve)) { - return curve->bitlen; - } else { - return 0; - } - } -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - return 255; - case PGP_PKA_X25519: - return 255; -#endif - case PGP_PKA_DSA: - return crypto->dsa.p_bitlen; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return crypto->elgamal.key_bitlen; -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - return pgp_kyber_ecdh_composite_public_key_t::encoded_size(crypto->key_alg) * 8; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - return pgp_dilithium_exdsa_composite_public_key_t::encoded_size(crypto->key_alg) * 8; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - return sphincsplus_pubkey_size(crypto->sphincsplus.param) * 8; -#endif - default: - return 0; - } -} - -static void -set_default_user_prefs(pgp_user_prefs_t &prefs) -{ - if (prefs.symm_algs.empty()) { - prefs.set_symm_algs( - std::vector(DEFAULT_SYMMETRIC_ALGS, - DEFAULT_SYMMETRIC_ALGS + ARRAY_SIZE(DEFAULT_SYMMETRIC_ALGS))); - } - if (prefs.hash_algs.empty()) { - prefs.set_hash_algs(std::vector( - DEFAULT_HASH_ALGS, DEFAULT_HASH_ALGS + ARRAY_SIZE(DEFAULT_HASH_ALGS))); - } - if (prefs.z_algs.empty()) { - prefs.set_z_algs(std::vector( - DEFAULT_COMPRESS_ALGS, DEFAULT_COMPRESS_ALGS + ARRAY_SIZE(DEFAULT_COMPRESS_ALGS))); - } -#if defined(ENABLE_CRYPTO_REFRESH) - if (prefs.aead_prefs.empty()) { - std::vector algs; - for (auto aead_alg : DEFAULT_AEAD_ALGS) { - for (auto sym_alg : prefs.symm_algs) { - algs.push_back(sym_alg); - algs.push_back(aead_alg); - } - } - prefs.set_aead_prefs(algs); - } -#endif -} - -static void -keygen_primary_merge_defaults(rnp_keygen_primary_desc_t &desc) -{ - keygen_merge_crypto_defaults(desc.crypto); - set_default_user_prefs(desc.cert.prefs); - - if (!desc.cert.key_flags) { - // set some default key flags if none are provided - desc.cert.key_flags = pk_alg_default_flags(desc.crypto.key_alg); - } - if (desc.cert.userid.empty()) { - char uid[MAX_ID_LENGTH] = {0}; - snprintf(uid, - sizeof(uid), - "%s %d-bit key <%s@localhost>", - id_str_pair::lookup(pubkey_alg_map, desc.crypto.key_alg), - get_numbits(&desc.crypto), - getenv_logname()); - desc.cert.userid = uid; - } -} - -#if defined(ENABLE_PQC) -static bool -pgp_check_key_hash_requirements(rnp_keygen_crypto_params_t &crypto) -{ - switch (crypto.key_alg) { - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - if (!sphincsplus_hash_allowed( - crypto.key_alg, crypto.sphincsplus.param, crypto.hash_alg)) { - return false; - } - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - if (!dilithium_hash_allowed(crypto.hash_alg)) { - return false; - } - break; - default: - break; - } - return true; -} -#endif - -bool -pgp_generate_primary_key(rnp_keygen_primary_desc_t &desc, - bool merge_defaults, - pgp_key_t & primary_sec, - pgp_key_t & primary_pub, - pgp_key_store_format_t secformat) -{ - // validate args - if (primary_sec.type() || primary_pub.type()) { - RNP_LOG("invalid parameters (should be zeroed)"); - return false; - } - - try { - // merge some defaults in, if requested - if (merge_defaults) { - keygen_primary_merge_defaults(desc); - } - // now validate the keygen fields - if (!validate_keygen_primary(desc)) { - return false; - } - -#if defined(ENABLE_PQC) - // check hash requirements - if (!pgp_check_key_hash_requirements(desc.crypto)) { - RNP_LOG("invalid hash algorithm for the chosen key"); - return false; - } -#endif - - // generate the raw key and fill tag/secret fields - pgp_key_pkt_t secpkt; - if (!pgp_generate_seckey(desc.crypto, secpkt, true, desc.pgp_version)) { - return false; - } - - pgp_key_t sec(secpkt); - pgp_key_t pub(secpkt, true); -#if defined(ENABLE_CRYPTO_REFRESH) - // for v6 packets, a direct-key sig is mandatory. - if (sec.version() == PGP_V6) { - sec.add_direct_sig(desc.cert, desc.crypto.hash_alg, *desc.crypto.ctx, &pub); - } -#endif - sec.add_uid_cert(desc.cert, desc.crypto.hash_alg, *desc.crypto.ctx, &pub); - - switch (secformat) { - case PGP_KEY_STORE_GPG: - case PGP_KEY_STORE_KBX: - primary_sec = std::move(sec); - primary_pub = std::move(pub); - break; - case PGP_KEY_STORE_G10: - primary_pub = std::move(pub); - if (!load_generated_g10_key( - &primary_sec, &secpkt, NULL, &primary_pub, *desc.crypto.ctx)) { - RNP_LOG("failed to load generated key"); - return false; - } - break; - default: - RNP_LOG("invalid format"); - return false; - } - } catch (const std::exception &e) { - RNP_LOG("Failure: %s", e.what()); - return false; - } - - /* mark it as valid */ - primary_pub.mark_valid(); - primary_sec.mark_valid(); - /* refresh key's data */ - return primary_pub.refresh_data(*desc.crypto.ctx) && - primary_sec.refresh_data(*desc.crypto.ctx); -} - -static bool -validate_keygen_subkey(rnp_keygen_subkey_desc_t &desc) -{ - if (!desc.binding.key_flags) { - RNP_LOG("key flags are required"); - return false; - } else if (desc.binding.key_flags & ~pgp_pk_alg_capabilities(desc.crypto.key_alg)) { - // check the flags against the alg capabilities - RNP_LOG("usage not permitted for pk algorithm"); - return false; - } - return true; -} - -static void -keygen_subkey_merge_defaults(rnp_keygen_subkey_desc_t &desc) -{ - keygen_merge_crypto_defaults(desc.crypto); - if (!desc.binding.key_flags) { - // set some default key flags if none are provided - desc.binding.key_flags = pk_alg_default_flags(desc.crypto.key_alg); - } -} - -bool -pgp_generate_subkey(rnp_keygen_subkey_desc_t & desc, - bool merge_defaults, - pgp_key_t & primary_sec, - pgp_key_t & primary_pub, - pgp_key_t & subkey_sec, - pgp_key_t & subkey_pub, - const pgp_password_provider_t &password_provider, - pgp_key_store_format_t secformat) -{ - // validate args - if (!primary_sec.is_primary() || !primary_pub.is_primary() || !primary_sec.is_secret() || - !primary_pub.is_public()) { - RNP_LOG("invalid parameters"); - return false; - } - if (subkey_sec.type() || subkey_pub.type()) { - RNP_LOG("invalid parameters (should be zeroed)"); - return false; - } - - // merge some defaults in, if requested - if (merge_defaults) { - keygen_subkey_merge_defaults(desc); - } - - // now validate the keygen fields - if (!validate_keygen_subkey(desc)) { - return false; - } - -#if defined(ENABLE_PQC) - // check hash requirements - if (!pgp_check_key_hash_requirements(desc.crypto)) { - RNP_LOG("invalid hash algorithm for the chosen key"); - return false; - } -#endif - - try { - /* decrypt the primary seckey if needed (for signatures) */ - rnp::KeyLocker primlock(primary_sec); - if (primary_sec.encrypted() && - !primary_sec.unlock(password_provider, PGP_OP_ADD_SUBKEY)) { - RNP_LOG("Failed to unlock primary key."); - return false; - } - /* generate the raw subkey */ - pgp_key_pkt_t secpkt; - if (!pgp_generate_seckey(desc.crypto, secpkt, false, desc.pgp_version)) { - return false; - } - pgp_key_pkt_t pubpkt = pgp_key_pkt_t(secpkt, true); - pgp_key_t sec(secpkt, primary_sec); - pgp_key_t pub(pubpkt, primary_pub); - /* add binding */ - primary_sec.add_sub_binding( - sec, pub, desc.binding, desc.crypto.hash_alg, *desc.crypto.ctx); - /* copy to the result */ - subkey_pub = std::move(pub); - switch (secformat) { - case PGP_KEY_STORE_GPG: - case PGP_KEY_STORE_KBX: - subkey_sec = std::move(sec); - break; - case PGP_KEY_STORE_G10: - if (!load_generated_g10_key( - &subkey_sec, &secpkt, &primary_sec, &subkey_pub, *desc.crypto.ctx)) { - RNP_LOG("failed to load generated key"); - return false; - } - break; - default: - RNP_LOG("invalid format"); - return false; - } - - subkey_pub.mark_valid(); - subkey_sec.mark_valid(); - return subkey_pub.refresh_data(&primary_pub, *desc.crypto.ctx) && - subkey_sec.refresh_data(&primary_sec, *desc.crypto.ctx); - } catch (const std::exception &e) { - RNP_LOG("Subkey generation failed: %s", e.what()); - return false; - } -} diff --git a/src/lib/json-utils.cpp b/src/lib/json-utils.cpp index 9f556f33f4..ac86988a56 100644 --- a/src/lib/json-utils.cpp +++ b/src/lib/json-utils.cpp @@ -147,3 +147,82 @@ json_array_add(json_object *obj, json_object *val) } return true; } + +static json_object * +json_get_field(json_object *obj, const char *name, json_type type) +{ + json_object *res = NULL; + if (!json_object_object_get_ex(obj, name, &res) || !json_object_is_type(res, type)) { + return NULL; + } + return res; +} + +bool +json_get_str(json_object *obj, const char *name, std::string &value, bool del) +{ + auto str = json_get_field(obj, name, json_type_string); + if (!str) { + return false; + } + value = json_object_get_string(str); + if (del) { + json_object_object_del(obj, name); + } + return true; +} + +bool +json_get_int(json_object *obj, const char *name, int &value, bool del) +{ + auto num = json_get_field(obj, name, json_type_int); + if (!num) { + return false; + } + value = json_object_get_int(num); + if (del) { + json_object_object_del(obj, name); + } + return true; +} + +bool +json_get_uint64(json_object *obj, const char *name, uint64_t &value, bool del) +{ + auto num = json_get_field(obj, name, json_type_int); + if (!num) { + return false; + } + value = (uint64_t) json_object_get_int64(num); + if (del) { + json_object_object_del(obj, name); + } + return true; +} + +bool +json_get_str_arr(json_object *obj, const char *name, std::vector &value, bool del) +{ + auto arr = json_get_field(obj, name, json_type_array); + if (!arr) { + return false; + } + value.clear(); + for (size_t i = 0; i < (size_t) json_object_array_length(arr); i++) { + json_object *item = json_object_array_get_idx(arr, i); + if (!json_object_is_type(item, json_type_string)) { + return false; + } + value.push_back(json_object_get_string(item)); + } + if (del) { + json_object_object_del(obj, name); + } + return true; +} + +json_object * +json_get_obj(json_object *obj, const char *name) +{ + return json_get_field(obj, name, json_type_object); +} diff --git a/src/lib/json-utils.h b/src/lib/json-utils.h index 00708c8259..bb18c0411e 100644 --- a/src/lib/json-utils.h +++ b/src/lib/json-utils.h @@ -100,6 +100,35 @@ bool json_array_add(json_object *obj, const char *val); */ bool json_array_add(json_object *obj, json_object *val); +/** + * @brief Get string from the object, and optionally delete the field. + * Would check field's type as well. + * + * @param obj json object + * @param name field name + * @param value on success field value will be stored here. + * @param del true to delete field after the extraction. + * @return true on success or false otherwise. + */ +bool json_get_str(json_object *obj, const char *name, std::string &value, bool del = true); + +/** + * Analog of the previous but extracts int value. + */ +bool json_get_int(json_object *obj, const char *name, int &value, bool del = true); +bool json_get_uint64(json_object *obj, const char *name, uint64_t &value, bool del = true); + +/** + * Analog of previous which extract array of string values. + */ +bool json_get_str_arr(json_object * obj, + const char * name, + std::vector &value, + bool del = true); + +/* Get object with specified name, but do not delete it from json */ +json_object *json_get_obj(json_object *obj, const char *name); + namespace rnp { class JSONObject { json_object *obj_; diff --git a/src/lib/key_material.cpp b/src/lib/key_material.cpp index e989e8eb36..43f81519eb 100644 --- a/src/lib/key_material.cpp +++ b/src/lib/key_material.cpp @@ -127,6 +127,117 @@ grip_hash_ec(rnp::Hash &hash, const pgp_ec_key_t &key) namespace pgp { +KeyParams::~KeyParams() +{ +} + +std::unique_ptr +KeyParams::create(pgp_pubkey_alg_t alg) +{ + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return std::unique_ptr(new RSAKeyParams()); + case PGP_PKA_ECDSA: + return std::unique_ptr(new ECDSAKeyParams()); + case PGP_PKA_ECDH: + return std::unique_ptr(new ECCKeyParams()); + case PGP_PKA_EDDSA: + return std::unique_ptr(new ECCKeyParams(PGP_CURVE_ED25519)); + case PGP_PKA_SM2: + return std::unique_ptr(new ECCKeyParams(PGP_CURVE_SM2_P_256)); +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + return std::unique_ptr(new ECCKeyParams(PGP_CURVE_ED25519)); + case PGP_PKA_X25519: + return std::unique_ptr(new ECCKeyParams(PGP_CURVE_25519)); +#endif + case PGP_PKA_DSA: + return std::unique_ptr(new DSAKeyParams()); + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return std::unique_ptr(new EGKeyParams()); +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; + case PGP_PKA_KYBER768_P256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_KYBER1024_P384: + FALLTHROUGH_STATEMENT; + case PGP_PKA_KYBER768_BP256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_KYBER1024_BP384: + return std::unique_ptr(new MlkemEcdhKeyParams(alg)); + case PGP_PKA_DILITHIUM3_ED25519: + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM3_P256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM5_P384: + FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM3_BP256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM5_BP384: + return std::unique_ptr(new DilithiumEccKeyParams(alg)); + case PGP_PKA_SPHINCSPLUS_SHA2: + FALLTHROUGH_STATEMENT; + case PGP_PKA_SPHINCSPLUS_SHAKE: + return std::unique_ptr(new SlhdsaKeyParams()); +#endif + default: + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +void +DSAKeyParams::check_defaults() noexcept +{ + if (!qbits_) { + qbits_ = dsa_choose_qsize_by_psize(bits()); + } +} + +pgp_hash_alg_t +DSAKeyParams::min_hash() const noexcept +{ + return dsa_get_min_hash(qbits_); +} + +size_t +ECCKeyParams::bits() const noexcept +{ + auto curve = get_curve_desc(curve_); + return curve ? curve->bitlen : 0; +} + +pgp_hash_alg_t +ECDSAKeyParams::min_hash() const noexcept +{ + return ecdsa_get_min_hash(curve()); +} + +#if defined(ENABLE_PQC) +size_t +MlkemEcdhKeyParams::bits() const noexcept +{ + return pgp_kyber_ecdh_composite_public_key_t::encoded_size(alg_) * 8; +} + +size_t +DilithiumEccKeyParams::bits() const noexcept +{ + return pgp_dilithium_exdsa_composite_public_key_t::encoded_size(alg_) * 8; +} + +size_t +SlhdsaKeyParams::bits() const noexcept +{ + return sphincsplus_pubkey_size(param_) * 8; +} +#endif + KeyMaterial::~KeyMaterial() { } @@ -204,7 +315,7 @@ KeyMaterial::finish_generate() } bool -KeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +KeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { RNP_LOG("key generation not implemented for PK alg: %d", alg_); return false; @@ -438,14 +549,14 @@ RSAKeyMaterial::write_secret(pgp_packet_body_t &pkt) const } bool -RSAKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +RSAKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { /* We do not generate PGP_PKA_RSA_ENCRYPT_ONLY or PGP_PKA_RSA_SIGN_ONLY keys */ if (alg_ != PGP_PKA_RSA) { RNP_LOG("Unsupported algorithm for key generation: %d", alg_); return false; } - if (rsa_generate(¶ms.ctx->rng, &key_, params.rsa.modulus_bit_len)) { + if (rsa_generate(&ctx.rng, &key_, params.bits())) { RNP_LOG("failed to generate RSA key"); return false; } @@ -619,9 +730,10 @@ DSAKeyMaterial::write_secret(pgp_packet_body_t &pkt) const } bool -DSAKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +DSAKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { - if (dsa_generate(¶ms.ctx->rng, &key_, params.dsa.p_bitlen, params.dsa.q_bitlen)) { + auto &dsa = dynamic_cast(params); + if (dsa_generate(&ctx.rng, &key_, dsa.bits(), dsa.qbits())) { RNP_LOG("failed to generate DSA key"); return false; } @@ -773,14 +885,14 @@ EGKeyMaterial::write_secret(pgp_packet_body_t &pkt) const } bool -EGKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +EGKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { /* We do not generate PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN keys */ if (alg_ != PGP_PKA_ELGAMAL) { RNP_LOG("Unsupported algorithm for key generation: %d", alg_); return false; } - if (elgamal_generate(¶ms.ctx->rng, &key_, params.elgamal.key_bitlen)) { + if (elgamal_generate(&ctx.rng, &key_, params.bits())) { RNP_LOG("failed to generate ElGamal key"); return false; } @@ -929,17 +1041,18 @@ ECKeyMaterial::write_secret(pgp_packet_body_t &pkt) const } bool -ECKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +ECKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { - if (!curve_supported(params.ecc.curve)) { - RNP_LOG("EC generate: curve %d is not supported.", params.ecc.curve); + auto &ecc = dynamic_cast(params); + if (!curve_supported(ecc.curve())) { + RNP_LOG("EC generate: curve %d is not supported.", ecc.curve()); return false; } - if (ec_generate(¶ms.ctx->rng, &key_, alg_, params.ecc.curve)) { + if (ec_generate(&ctx.rng, &key_, alg_, ecc.curve())) { RNP_LOG("failed to generate EC key"); return false; } - key_.curve = params.ecc.curve; + key_.curve = ecc.curve(); return finish_generate(); } @@ -1077,24 +1190,24 @@ ECDHKeyMaterial::write(pgp_packet_body_t &pkt) const } bool -ECDHKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +ECDHKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { - if (!ecdh_set_params(&key_, params.ecc.curve)) { - RNP_LOG("Unsupported curve [ID=%d]", params.ecc.curve); + auto &ecc = dynamic_cast(params); + if (!ecdh_set_params(&key_, ecc.curve())) { + RNP_LOG("Unsupported curve [ID=%d]", ecc.curve()); return false; } /* Special case for x25519*/ - if (params.ecc.curve == PGP_CURVE_25519) { - if (x25519_generate(¶ms.ctx->rng, &key_)) { + if (ecc.curve() == PGP_CURVE_25519) { + if (x25519_generate(&ctx.rng, &key_)) { RNP_LOG("failed to generate x25519 key"); return false; } - key_.curve = params.ecc.curve; + key_.curve = ecc.curve(); return finish_generate(); - ; } /* Fallback to default EC generation for other cases */ - return ECKeyMaterial::generate(params); + return ECKeyMaterial::generate(ctx, params); } rnp_result_t @@ -1164,9 +1277,9 @@ EDDSAKeyMaterial::clone() } bool -EDDSAKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +EDDSAKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { - if (eddsa_generate(¶ms.ctx->rng, &key_)) { + if (eddsa_generate(&ctx.rng, &key_)) { RNP_LOG("failed to generate EDDSA key"); return false; } @@ -1357,9 +1470,9 @@ Ed25519KeyMaterial::write_secret(pgp_packet_body_t &pkt) const } bool -Ed25519KeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +Ed25519KeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { - if (generate_ed25519_native(¶ms.ctx->rng, key_.priv, key_.pub)) { + if (generate_ed25519_native(&ctx.rng, key_.priv, key_.pub)) { RNP_LOG("failed to generate ED25519 key"); return false; } @@ -1483,9 +1596,9 @@ X25519KeyMaterial::write_secret(pgp_packet_body_t &pkt) const } bool -X25519KeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +X25519KeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { - if (generate_x25519_native(¶ms.ctx->rng, key_.priv, key_.pub)) { + if (generate_x25519_native(&ctx.rng, key_.priv, key_.pub)) { RNP_LOG("failed to generate X25519 key"); return false; } @@ -1610,9 +1723,9 @@ MlkemEcdhKeyMaterial::write_secret(pgp_packet_body_t &pkt) const } bool -MlkemEcdhKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +MlkemEcdhKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { - if (pgp_kyber_ecdh_composite_key_t::gen_keypair(¶ms.ctx->rng, &key_, alg_)) { + if (pgp_kyber_ecdh_composite_key_t::gen_keypair(&ctx.rng, &key_, alg_)) { RNP_LOG("failed to generate MLKEM-ECDH-composite key for PK alg %d", alg_); return false; } @@ -1729,9 +1842,9 @@ DilithiumEccKeyMaterial::write_secret(pgp_packet_body_t &pkt) const } bool -DilithiumEccKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +DilithiumEccKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { - if (pgp_dilithium_exdsa_composite_key_t::gen_keypair(¶ms.ctx->rng, &key_, alg_)) { + if (pgp_dilithium_exdsa_composite_key_t::gen_keypair(&ctx.rng, &key_, alg_)) { RNP_LOG("failed to generate mldsa-ecdsa/eddsa-composite key for PK alg %d", alg_); return false; } @@ -1871,9 +1984,10 @@ SlhdsaKeyMaterial::write_secret(pgp_packet_body_t &pkt) const } bool -SlhdsaKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +SlhdsaKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) { - if (pgp_sphincsplus_generate(¶ms.ctx->rng, &key_, params.sphincsplus.param, alg_)) { + auto &slhdsa = dynamic_cast(params); + if (pgp_sphincsplus_generate(&ctx.rng, &key_, slhdsa.param(), alg_)) { RNP_LOG("failed to generate SLH-DSA key for PK alg %d", alg_); return false; } diff --git a/src/lib/key_material.hpp b/src/lib/key_material.hpp index 2a24fbdb84..9a03e9915f 100644 --- a/src/lib/key_material.hpp +++ b/src/lib/key_material.hpp @@ -28,13 +28,155 @@ #define RNP_KEY_MATERIAL_HPP_ #include "types.h" +#include "defaults.h" -typedef struct pgp_packet_body_t pgp_packet_body_t; -typedef struct rnp_keygen_crypto_params_t rnp_keygen_crypto_params_t; -typedef struct pgp_encrypted_material_t pgp_encrypted_material_t; -typedef struct pgp_signature_material_t pgp_signature_material_t; +typedef struct pgp_packet_body_t pgp_packet_body_t; +typedef struct pgp_encrypted_material_t pgp_encrypted_material_t; +typedef struct pgp_signature_material_t pgp_signature_material_t; namespace pgp { + +class KeyParams { + public: + virtual ~KeyParams(); + virtual size_t bits() const noexcept = 0; + virtual pgp_hash_alg_t + min_hash() const noexcept + { + return PGP_HASH_UNKNOWN; + } + + virtual void + check_defaults() noexcept + { + } + + static std::unique_ptr create(pgp_pubkey_alg_t alg); +}; + +class BitsKeyParams : public KeyParams { + private: + size_t bits_; + + public: + BitsKeyParams(size_t bits) : bits_(bits){}; + + size_t + bits() const noexcept override + { + return bits_; + }; + + void + set_bits(size_t value) noexcept + { + bits_ = value; + }; +}; + +class RSAKeyParams : public BitsKeyParams { + public: + RSAKeyParams() : BitsKeyParams(DEFAULT_RSA_NUMBITS){}; +}; + +class DSAKeyParams : public BitsKeyParams { + private: + size_t qbits_; + + public: + DSAKeyParams() : BitsKeyParams(DSA_DEFAULT_P_BITLEN), qbits_(0){}; + + size_t + qbits() const noexcept + { + return qbits_; + }; + + void + set_qbits(size_t value) noexcept + { + qbits_ = value; + }; + + void check_defaults() noexcept override; + + pgp_hash_alg_t min_hash() const noexcept override; +}; + +class EGKeyParams : public BitsKeyParams { + public: + EGKeyParams() : BitsKeyParams(DEFAULT_ELGAMAL_NUMBITS){}; +}; + +class ECCKeyParams : public KeyParams { + private: + pgp_curve_t curve_; + + public: + ECCKeyParams(pgp_curve_t curve = PGP_CURVE_UNKNOWN) : curve_(curve){}; + + pgp_curve_t + curve() const noexcept + { + return curve_; + } + + void + set_curve(const pgp_curve_t value) noexcept + { + curve_ = value; + } + + size_t bits() const noexcept override; +}; + +class ECDSAKeyParams : public ECCKeyParams { + public: + pgp_hash_alg_t min_hash() const noexcept override; +}; + +#if defined(ENABLE_PQC) +class MlkemEcdhKeyParams : public KeyParams { + private: + pgp_pubkey_alg_t alg_; + + public: + MlkemEcdhKeyParams(pgp_pubkey_alg_t alg) : alg_(alg){}; + size_t bits() const noexcept override; +}; + +class DilithiumEccKeyParams : public KeyParams { + private: + pgp_pubkey_alg_t alg_; + + public: + DilithiumEccKeyParams(pgp_pubkey_alg_t alg) : alg_(alg){}; + size_t bits() const noexcept override; +}; + +class SlhdsaKeyParams : public KeyParams { + private: + sphincsplus_parameter_t param_; + + public: + SlhdsaKeyParams() : param_(sphincsplus_simple_128f){}; + + sphincsplus_parameter_t + param() const noexcept + { + return param_; + } + + void + set_param(sphincsplus_parameter_t value) noexcept + { + param_ = value; + } + + size_t bits() const noexcept override; +}; +#endif + class KeyMaterial { pgp_validity_t validity_; /* key material validation status */ protected: @@ -64,7 +206,7 @@ class KeyMaterial { virtual bool parse_secret(pgp_packet_body_t &pkt) noexcept = 0; virtual void write(pgp_packet_body_t &pkt) const = 0; virtual void write_secret(pgp_packet_body_t &pkt) const = 0; - virtual bool generate(const rnp_keygen_crypto_params_t ¶ms); + virtual bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms); virtual rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, @@ -113,7 +255,7 @@ class RSAKeyMaterial : public KeyMaterial { bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, @@ -159,7 +301,7 @@ class DSAKeyMaterial : public KeyMaterial { bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; @@ -197,7 +339,7 @@ class EGKeyMaterial : public KeyMaterial { bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, @@ -237,7 +379,7 @@ class ECKeyMaterial : public KeyMaterial { bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; void set_secret(const mpi &x); size_t bits() const noexcept override; pgp_curve_t curve() const noexcept override; @@ -277,7 +419,7 @@ class ECDHKeyMaterial : public ECKeyMaterial { bool parse(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, @@ -303,7 +445,7 @@ class EDDSAKeyMaterial : public ECKeyMaterial { : ECKeyMaterial(PGP_PKA_EDDSA, key, secret){}; std::unique_ptr clone() override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; @@ -357,7 +499,7 @@ class Ed25519KeyMaterial : public KeyMaterial { bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; @@ -388,7 +530,7 @@ class X25519KeyMaterial : public KeyMaterial { bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, @@ -423,7 +565,7 @@ class MlkemEcdhKeyMaterial : public KeyMaterial { bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, @@ -457,7 +599,7 @@ class DilithiumEccKeyMaterial : public KeyMaterial { bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; @@ -488,7 +630,7 @@ class SlhdsaKeyMaterial : public KeyMaterial { bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; - bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; diff --git a/src/lib/keygen.cpp b/src/lib/keygen.cpp new file mode 100644 index 0000000000..e3d47bfe89 --- /dev/null +++ b/src/lib/keygen.cpp @@ -0,0 +1,542 @@ +/* + * Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "keygen.hpp" +#include +#include +#include "librekey/key_store_g10.h" + +namespace rnp { +KeygenParams::KeygenParams(pgp_pubkey_alg_t alg, SecurityContext &ctx) + : alg_(alg), hash_(PGP_HASH_UNKNOWN), version_(PGP_V4), ctx_(ctx) +{ + key_params_ = pgp::KeyParams::create(alg); +} + +void +KeygenParams::check_defaults() noexcept +{ + if (hash_ == PGP_HASH_UNKNOWN) { + hash_ = alg_ == PGP_PKA_SM2 ? PGP_HASH_SM3 : DEFAULT_PGP_HASH_ALG; + } + pgp_hash_alg_t min_hash = key_params_->min_hash(); + if (Hash::size(hash_) < Hash::size(min_hash)) { + hash_ = min_hash; + } + key_params_->check_defaults(); +} + +bool +KeygenParams::validate() const noexcept +{ +#if defined(ENABLE_PQC) + switch (alg()) { + case PGP_PKA_SPHINCSPLUS_SHA2: + FALLTHROUGH_STATEMENT; + case PGP_PKA_SPHINCSPLUS_SHAKE: { + auto &slhdsa = dynamic_cast(key_params()); + if (!sphincsplus_hash_allowed(alg(), slhdsa.param(), hash())) { + RNP_LOG("invalid hash algorithm for the slhdsa key"); + return false; + } + break; + } + case PGP_PKA_DILITHIUM3_ED25519: + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM3_P256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM5_P384: + FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM3_BP256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM5_BP384: + if (!dilithium_hash_allowed(hash())) { + RNP_LOG("invalid hash algorithm for the dilithium key"); + return false; + } + break; + default: + break; + } +#endif + return true; +} + +bool +KeygenParams::validate(const CertParams &cert) const noexcept +{ + /* Confirm that the specified pk alg can certify. + * gpg requires this, though the RFC only says that a V4 primary + * key SHOULD be a key capable of certification. + */ + if (!(pgp_pk_alg_capabilities(alg()) & PGP_KF_CERTIFY)) { + RNP_LOG("primary key alg (%d) must be able to sign", alg()); + return false; + } + + // check key flags + if (!cert.flags) { + // these are probably not *technically* required + RNP_LOG("key flags are required"); + return false; + } + if (cert.flags & ~pgp_pk_alg_capabilities(alg())) { + // check the flags against the alg capabilities + RNP_LOG("usage not permitted for pk algorithm"); + return false; + } + // require a userid + if (cert.userid.empty()) { + RNP_LOG("userid is required for primary key"); + return false; + } + return validate(); +} + +bool +KeygenParams::validate(const BindingParams &binding) const noexcept +{ + if (!binding.flags) { + RNP_LOG("key flags are required"); + return false; + } + if (binding.flags & ~pgp_pk_alg_capabilities(alg())) { + // check the flags against the alg capabilities + RNP_LOG("usage not permitted for pk algorithm"); + return false; + } + return validate(); +} + +static const id_str_pair pubkey_alg_map[] = {{PGP_PKA_RSA, "RSA (Encrypt or Sign)"}, + {PGP_PKA_RSA_ENCRYPT_ONLY, "RSA Encrypt-Only"}, + {PGP_PKA_RSA_SIGN_ONLY, "RSA Sign-Only"}, + {PGP_PKA_ELGAMAL, "Elgamal (Encrypt-Only)"}, + {PGP_PKA_DSA, "DSA"}, + {PGP_PKA_ECDH, "ECDH"}, + {PGP_PKA_ECDSA, "ECDSA"}, + {PGP_PKA_EDDSA, "EdDSA"}, + {PGP_PKA_SM2, "SM2"}, +#if defined(ENABLE_CRYPTO_REFRESH) + {PGP_PKA_ED25519, "ED25519"}, + {PGP_PKA_X25519, "X25519"}, +#endif +#if defined(ENABLE_PQC) + {PGP_PKA_KYBER768_X25519, "ML-KEM-768_X25519"}, + //{PGP_PKA_KYBER1024_X448, "Kyber-X448"}, + {PGP_PKA_KYBER768_P256, "ML-KEM-768_P256"}, + {PGP_PKA_KYBER1024_P384, "ML-KEM-1024_P384"}, + {PGP_PKA_KYBER768_BP256, "ML-KEM-768_BP256"}, + {PGP_PKA_KYBER1024_BP384, "ML-KEM-1024_BP384"}, + {PGP_PKA_DILITHIUM3_ED25519, "ML-DSA-65_ED25519"}, + //{PGP_PKA_DILITHIUM5_ED448, "Dilithium-ED448"}, + {PGP_PKA_DILITHIUM3_P256, "ML-DSA-65_P256"}, + {PGP_PKA_DILITHIUM5_P384, "ML-DSA-87_P384"}, + {PGP_PKA_DILITHIUM3_BP256, "ML-DSA-65_BP256"}, + {PGP_PKA_DILITHIUM5_BP384, "ML-DSA-87_BP384"}, + {PGP_PKA_SPHINCSPLUS_SHA2, "SLH-DSA-SHA2"}, + {PGP_PKA_SPHINCSPLUS_SHAKE, "SLH-DSA-SHAKE"}, +#endif + {0, NULL}}; + +bool +KeygenParams::generate(pgp_key_pkt_t &seckey, bool primary) +{ + /* populate pgp key structure */ + seckey = {}; + seckey.version = version(); + seckey.creation_time = ctx().time(); + seckey.alg = alg(); + seckey.material = pgp::KeyMaterial::create(alg()); + if (!seckey.material) { + RNP_LOG("Unsupported key algorithm: %d", alg()); + return false; + } + seckey.tag = primary ? PGP_PKT_SECRET_KEY : PGP_PKT_SECRET_SUBKEY; + + if (!seckey.material->generate(ctx(), key_params())) { + return false; + } + + seckey.sec_protection.s2k.usage = PGP_S2KU_NONE; + /* fill the sec_data/sec_len */ + if (encrypt_secret_key(&seckey, NULL, ctx().rng)) { + RNP_LOG("failed to fill sec_data"); + return false; + } + return true; +} + +static bool +load_generated_g10_key(pgp_key_t * dst, + pgp_key_pkt_t * newkey, + pgp_key_t * primary_key, + pgp_key_t * pubkey, + SecurityContext &ctx) +{ + // this should generally be zeroed + assert(dst->type() == 0); + // if a primary is provided, make sure it's actually a primary key + assert(!primary_key || primary_key->is_primary()); + // if a pubkey is provided, make sure it's actually a public key + assert(!pubkey || pubkey->is_public()); + // G10 always needs pubkey here + assert(pubkey); + + // this would be better on the stack but the key store does not allow it + std::unique_ptr key_store(new (std::nothrow) KeyStore(ctx)); + if (!key_store) { + return false; + } + /* Write g10 seckey */ + MemoryDest memdst(NULL, 0); + if (!g10_write_seckey(&memdst.dst(), newkey, NULL, ctx)) { + RNP_LOG("failed to write generated seckey"); + return false; + } + + std::vector key_ptrs; /* holds primary and pubkey, when used */ + // if this is a subkey, add the primary in first + if (primary_key) { + key_ptrs.push_back(primary_key); + } + // G10 needs the pubkey for copying some attributes (key version, creation time, etc) + key_ptrs.push_back(pubkey); + + MemorySource memsrc(memdst.memory(), memdst.writeb(), false); + KeyProvider prov(rnp_key_provider_key_ptr_list, &key_ptrs); + if (!key_store.get()->load_g10(memsrc.src(), &prov)) { + return false; + } + if (key_store.get()->key_count() != 1) { + return false; + } + // if a primary key is provided, it should match the sub with regards to type + assert(!primary_key || (primary_key->is_secret() == key_store->keys.front().is_secret())); + *dst = pgp_key_t(key_store->keys.front()); + return true; +} + +bool +KeygenParams::generate(CertParams & cert, + pgp_key_t & primary_sec, + pgp_key_t & primary_pub, + pgp_key_store_format_t secformat) +{ + primary_sec = {}; + primary_pub = {}; + + // merge some defaults in + check_defaults(); + cert.check_defaults(*this); + // now validate the keygen fields + if (!validate(cert)) { + return false; + } + + // generate the raw key and fill tag/secret fields + pgp_key_pkt_t secpkt; + if (!generate(secpkt, true)) { + return false; + } + + pgp_key_t sec(secpkt); + pgp_key_t pub(secpkt, true); +#if defined(ENABLE_CRYPTO_REFRESH) + // for v6 packets, a direct-key sig is mandatory. + if (sec.version() == PGP_V6) { + sec.add_direct_sig(cert, hash(), ctx(), &pub); + } +#endif + sec.add_uid_cert(cert, hash(), ctx(), &pub); + + switch (secformat) { + case PGP_KEY_STORE_GPG: + case PGP_KEY_STORE_KBX: + primary_sec = std::move(sec); + primary_pub = std::move(pub); + break; + case PGP_KEY_STORE_G10: + primary_pub = std::move(pub); + if (!load_generated_g10_key(&primary_sec, &secpkt, NULL, &primary_pub, ctx())) { + RNP_LOG("failed to load generated key"); + return false; + } + break; + default: + RNP_LOG("invalid format"); + return false; + } + + /* mark it as valid */ + primary_pub.mark_valid(); + primary_sec.mark_valid(); + /* refresh key's data */ + return primary_pub.refresh_data(ctx()) && primary_sec.refresh_data(ctx()); +} + +bool +KeygenParams::generate(BindingParams & binding, + pgp_key_t & primary_sec, + pgp_key_t & primary_pub, + pgp_key_t & subkey_sec, + pgp_key_t & subkey_pub, + const pgp_password_provider_t &password_provider, + pgp_key_store_format_t secformat) +{ + // validate args + if (!primary_sec.is_primary() || !primary_pub.is_primary() || !primary_sec.is_secret() || + !primary_pub.is_public()) { + RNP_LOG("invalid parameters"); + return false; + } + subkey_sec = {}; + subkey_pub = {}; + + // merge some defaults in + check_defaults(); + binding.check_defaults(*this); + + // now validate the keygen fields + if (!validate(binding)) { + return false; + } + + /* decrypt the primary seckey if needed (for signatures) */ + KeyLocker primlock(primary_sec); + if (primary_sec.encrypted() && !primary_sec.unlock(password_provider, PGP_OP_ADD_SUBKEY)) { + RNP_LOG("Failed to unlock primary key."); + return false; + } + /* generate the raw subkey */ + pgp_key_pkt_t secpkt; + if (!generate(secpkt, false)) { + return false; + } + pgp_key_pkt_t pubpkt = pgp_key_pkt_t(secpkt, true); + pgp_key_t sec(secpkt, primary_sec); + pgp_key_t pub(pubpkt, primary_pub); + /* add binding */ + primary_sec.add_sub_binding(sec, pub, binding, hash(), ctx()); + /* copy to the result */ + subkey_pub = std::move(pub); + switch (secformat) { + case PGP_KEY_STORE_GPG: + case PGP_KEY_STORE_KBX: + subkey_sec = std::move(sec); + break; + case PGP_KEY_STORE_G10: + if (!load_generated_g10_key(&subkey_sec, &secpkt, &primary_sec, &subkey_pub, ctx())) { + RNP_LOG("failed to load generated key"); + return false; + } + break; + default: + RNP_LOG("invalid format"); + return false; + } + + subkey_pub.mark_valid(); + subkey_sec.mark_valid(); + return subkey_pub.refresh_data(&primary_pub, ctx()) && + subkey_sec.refresh_data(&primary_sec, ctx()); +} + +UserPrefs::UserPrefs(const pgp_signature_t &sig) +{ + symm_algs = sig.preferred_symm_algs(); + hash_algs = sig.preferred_hash_algs(); + z_algs = sig.preferred_z_algs(); + + if (sig.has_subpkt(PGP_SIG_SUBPKT_KEYSERV_PREFS)) { + ks_prefs = {sig.key_server_prefs()}; + } + + if (sig.has_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV)) { + key_server = sig.key_server(); + } +} + +void +UserPrefs::add_uniq(std::vector &vec, uint8_t val) +{ + if (std::find(vec.begin(), vec.end(), val) == vec.end()) { + vec.push_back(val); + } +} + +void +UserPrefs::add_symm_alg(pgp_symm_alg_t alg) +{ + add_uniq(symm_algs, alg); +} + +void +UserPrefs::add_hash_alg(pgp_hash_alg_t alg) +{ + add_uniq(hash_algs, alg); +} + +void +UserPrefs::add_z_alg(pgp_compression_type_t alg) +{ + add_uniq(z_algs, alg); +} + +void +UserPrefs::add_ks_pref(pgp_key_server_prefs_t pref) +{ + add_uniq(ks_prefs, pref); +} + +#if defined(ENABLE_CRYPTO_REFRESH) +void +UserPrefs::add_aead_prefs(pgp_symm_alg_t sym_alg, pgp_aead_alg_t aead_alg) +{ + for (size_t i = 0; i < aead_prefs.size(); i += 2) { + if (aead_prefs[i] == sym_alg && aead_prefs[i + 1] == aead_alg) { + return; + } + } + aead_prefs.push_back(sym_alg); + aead_prefs.push_back(aead_alg); +} +#endif + +void +UserPrefs::check_defaults(pgp_version_t version) +{ + if (symm_algs.empty()) { + symm_algs = {PGP_SA_AES_256, PGP_SA_AES_192, PGP_SA_AES_128}; + } + if (hash_algs.empty()) { + hash_algs = {PGP_HASH_SHA256, PGP_HASH_SHA384, PGP_HASH_SHA512, PGP_HASH_SHA224}; + } + if (z_algs.empty()) { + z_algs = {PGP_C_ZLIB, PGP_C_BZIP2, PGP_C_ZIP, PGP_C_NONE}; + } +#if defined(ENABLE_CRYPTO_REFRESH) + if (aead_prefs.empty() && (version == PGP_V6)) { + for (auto sym_alg : symm_algs) { + aead_prefs.push_back(sym_alg); + aead_prefs.push_back(PGP_AEAD_OCB); + } + } +#endif +} + +void +CertParams::check_defaults(const KeygenParams ¶ms) +{ + prefs.check_defaults(params.version()); + + if (!flags) { + // set some default key flags if none are provided + flags = pgp_pk_alg_capabilities(params.alg()); + } + if (userid.empty()) { + std::string alg = id_str_pair::lookup(pubkey_alg_map, params.alg()); + std::string bits = std::to_string(params.key_params().bits()); + std::string name = getenv_logname() ? getenv_logname() : ""; + /* Awkward but better then sprintf */ + userid = alg + " " + bits + "-bit key <" + name + "@localhost>"; + } +} + +void +CertParams::populate(pgp_userid_pkt_t &uid) const +{ + uid.tag = PGP_PKT_USER_ID; + uid.uid.assign(userid.data(), userid.data() + userid.size()); +} + +void +CertParams::populate(pgp_signature_t &sig) const +{ + if (key_expiration) { + sig.set_key_expiration(key_expiration); + } + if (primary) { + sig.set_primary_uid(true); + } +#if defined(ENABLE_CRYPTO_REFRESH) + if ((sig.version == PGP_V6) && (sig.type() != PGP_SIG_DIRECT)) { + /* only set key expiraton and primary uid for v6 self-signatures + * since most information is stored in the direct-key signature of the primary key. + */ + + if (flags && (sig.type() == PGP_SIG_SUBKEY)) { + /* for v6 subkeys signatures we also add the key flags */ + sig.set_key_flags(flags); + } + return; + } else if ((sig.version == PGP_V6) && (sig.type() == PGP_SIG_DIRECT)) { + /* set some additional packets for v6 direct-key self signatures */ + sig.set_key_features(PGP_KEY_FEATURE_MDC | PGP_KEY_FEATURE_SEIPDV2); + if (!prefs.aead_prefs.empty()) { + sig.set_preferred_aead_algs(prefs.aead_prefs); + } + } +#endif + if (flags) { + sig.set_key_flags(flags); + } + if (!prefs.symm_algs.empty()) { + sig.set_preferred_symm_algs(prefs.symm_algs); + } + if (!prefs.hash_algs.empty()) { + sig.set_preferred_hash_algs(prefs.hash_algs); + } + if (!prefs.z_algs.empty()) { + sig.set_preferred_z_algs(prefs.z_algs); + } + if (!prefs.ks_prefs.empty()) { + sig.set_key_server_prefs(prefs.ks_prefs[0]); + } + if (!prefs.key_server.empty()) { + sig.set_key_server(prefs.key_server); + } +} + +void +CertParams::populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig) const +{ + sig.set_type(PGP_CERT_POSITIVE); + populate(sig); + populate(uid); +} + +void +BindingParams::check_defaults(const KeygenParams ¶ms) +{ + if (!flags) { + // set some default key flags if none are provided + flags = pgp_pk_alg_capabilities(params.alg()); + } +} + +} // namespace rnp diff --git a/src/lib/keygen.hpp b/src/lib/keygen.hpp new file mode 100644 index 0000000000..affbfb1e3f --- /dev/null +++ b/src/lib/keygen.hpp @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_KEYGEN_HPP_ +#define RNP_KEYGEN_HPP_ + +#include "repgp/repgp_def.h" +#include "types.h" +#include "sec_profile.hpp" +#include "key_material.hpp" +#include "pgp-key.h" + +namespace rnp { + +class KeygenParams { + private: + pgp_pubkey_alg_t alg_; + pgp_hash_alg_t hash_; + pgp_version_t version_; + SecurityContext & ctx_; + std::unique_ptr key_params_; + + public: + KeygenParams(pgp_pubkey_alg_t alg, SecurityContext &ctx); + + pgp_pubkey_alg_t + alg() const noexcept + { + return alg_; + } + + pgp_hash_alg_t + hash() const noexcept + { + return hash_; + } + + void + set_hash(pgp_hash_alg_t value) noexcept + { + hash_ = value; + } + + void check_defaults() noexcept; + + bool validate() const noexcept; + + bool validate(const CertParams &cert) const noexcept; + + bool validate(const BindingParams &binding) const noexcept; + + pgp_version_t + version() const noexcept + { + return version_; + } + + void + set_version(pgp_version_t value) noexcept + { + version_ = value; + } + + SecurityContext & + ctx() noexcept + { + return ctx_; + } + + const pgp::KeyParams & + key_params() const noexcept + { + return *key_params_; + } + + pgp::KeyParams & + key_params() noexcept + { + return *key_params_; + } + + /* Generate secret key packet */ + bool generate(pgp_key_pkt_t &seckey, bool primary); + + /* Generate primary key with self-certification */ + bool generate(CertParams & cert, + pgp_key_t & primary_sec, + pgp_key_t & primary_pub, + pgp_key_store_format_t secformat); + + /* Generate a subkey for already existing primary key*/ + bool generate(BindingParams & binding, + pgp_key_t & primary_sec, + pgp_key_t & primary_pub, + pgp_key_t & subkey_sec, + pgp_key_t & subkey_pub, + const pgp_password_provider_t &password_provider, + pgp_key_store_format_t secformat); +}; + +class UserPrefs { + void add_uniq(std::vector &vec, uint8_t val); + + public: + // preferred symmetric algs (pgp_symm_alg_t) + std::vector symm_algs; + // preferred hash algs (pgp_hash_alg_t) + std::vector hash_algs; + // preferred compression algs (pgp_compression_type_t) + std::vector z_algs; + // key server preferences (pgp_key_server_prefs_t) + std::vector ks_prefs; + // preferred key server + std::string key_server; +#if defined(ENABLE_CRYPTO_REFRESH) + std::vector aead_prefs; +#endif + + UserPrefs(){}; + UserPrefs(const pgp_signature_t &sig); + + void add_symm_alg(pgp_symm_alg_t alg); + void add_hash_alg(pgp_hash_alg_t alg); + void add_z_alg(pgp_compression_type_t alg); + void add_ks_pref(pgp_key_server_prefs_t pref); +#if defined(ENABLE_CRYPTO_REFRESH) + void add_aead_prefs(pgp_symm_alg_t sym_alg, pgp_aead_alg_t aead_alg); +#endif + void check_defaults(pgp_version_t version = PGP_V4); +}; + +class CertParams { + public: + std::string userid; /* userid, required */ + uint8_t flags{}; /* key flags */ + uint32_t key_expiration{}; /* key expiration time (sec), 0 = no expiration */ + UserPrefs prefs; /* user preferences, optional */ + bool primary; /* mark this as the primary user id */ + + void check_defaults(const KeygenParams ¶ms); + + /** + * @brief Populate uid and sig packet with data stored in this struct. + * At some point we should get rid of it. + */ + void populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig) const; + void populate(pgp_signature_t &sig) const; + void populate(pgp_userid_pkt_t &uid) const; +}; + +class BindingParams { + public: + uint8_t flags{}; + uint32_t key_expiration{}; + + void check_defaults(const KeygenParams ¶ms); +}; + +} // namespace rnp + +#endif // RNP_KEYGEN_HPP_ \ No newline at end of file diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 918d799a18..fa4c694d47 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -52,11 +52,11 @@ #include "pgp-key.h" #include "utils.h" #include -#include "crypto.h" #include "crypto/s2k.h" #include "crypto/mem.h" #include "crypto/signatures.h" #include "fingerprint.h" +#include "keygen.hpp" #include #include @@ -498,82 +498,6 @@ find_suitable_key(pgp_op_t op, return subkey; } -static void -bytevec_append_uniq(std::vector &vec, uint8_t val) -{ - if (std::find(vec.begin(), vec.end(), val) == vec.end()) { - vec.push_back(val); - } -} - -void -pgp_user_prefs_t::set_symm_algs(const std::vector &algs) -{ - symm_algs = algs; -} - -void -pgp_user_prefs_t::add_symm_alg(pgp_symm_alg_t alg) -{ - bytevec_append_uniq(symm_algs, alg); -} - -void -pgp_user_prefs_t::set_hash_algs(const std::vector &algs) -{ - hash_algs = algs; -} - -void -pgp_user_prefs_t::add_hash_alg(pgp_hash_alg_t alg) -{ - bytevec_append_uniq(hash_algs, alg); -} - -void -pgp_user_prefs_t::set_z_algs(const std::vector &algs) -{ - z_algs = algs; -} - -void -pgp_user_prefs_t::add_z_alg(pgp_compression_type_t alg) -{ - bytevec_append_uniq(z_algs, alg); -} - -void -pgp_user_prefs_t::set_ks_prefs(const std::vector &prefs) -{ - ks_prefs = prefs; -} - -void -pgp_user_prefs_t::add_ks_pref(pgp_key_server_prefs_t pref) -{ - bytevec_append_uniq(ks_prefs, pref); -} - -#if defined(ENABLE_CRYPTO_REFRESH) -void -pgp_user_prefs_t::set_aead_prefs(const std::vector &algs) -{ - aead_prefs = algs; -} - -void -pgp_user_prefs_t::add_aead_prefs(pgp_symm_alg_t sym_alg, pgp_aead_alg_t aead_alg) -{ - for (size_t i = 0; i < aead_prefs.size(); i += 2) { - if (aead_prefs[i] == sym_alg && aead_prefs[i + 1] == aead_alg) { - return; - } - } - aead_prefs.push_back(sym_alg); - aead_prefs.push_back(aead_alg); -} -#endif - pgp_rawpacket_t::pgp_rawpacket_t(const pgp_signature_t &sig) { raw = sig.write(); @@ -622,23 +546,6 @@ pgp_subsig_t::pgp_subsig_t(const pgp_signature_t &pkt) { sig = pkt; sigid = sig.get_id(); - if (sig.has_subpkt(PGP_SIG_SUBPKT_TRUST)) { - trustlevel = sig.trust_level(); - trustamount = sig.trust_amount(); - } - prefs.set_symm_algs(sig.preferred_symm_algs()); - prefs.set_hash_algs(sig.preferred_hash_algs()); - prefs.set_z_algs(sig.preferred_z_algs()); - - if (sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { - key_flags = sig.key_flags(); - } - if (sig.has_subpkt(PGP_SIG_SUBPKT_KEYSERV_PREFS)) { - prefs.set_ks_prefs({sig.key_server_prefs()}); - } - if (sig.has_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV)) { - prefs.key_server = sig.key_server(); - } /* add signature rawpacket */ rawpkt = pgp_rawpacket_t(sig); } @@ -687,7 +594,7 @@ pgp_userid_t::pgp_userid_t(const pgp_userid_pkt_t &uidpkt) rawpkt = pgp_rawpacket_t(uidpkt); /* populate uid string */ if (uidpkt.tag == PGP_PKT_USER_ID) { - str = std::string(uidpkt.uid, uidpkt.uid + uidpkt.uid_len); + str.assign(uidpkt.uid.data(), uidpkt.uid.data() + uidpkt.uid.size()); } else { str = "(photo)"; } @@ -2569,10 +2476,10 @@ pgp_key_t::sign_subkey_binding(pgp_key_t & sub, #if defined(ENABLE_CRYPTO_REFRESH) void -pgp_key_t::add_direct_sig(rnp_selfsig_cert_info_t &cert, - pgp_hash_alg_t hash, - rnp::SecurityContext & ctx, - pgp_key_t * pubkey) +pgp_key_t::add_direct_sig(rnp::CertParams & cert, + pgp_hash_alg_t hash, + rnp::SecurityContext &ctx, + pgp_key_t * pubkey) { // We only support modifying v4 and newer keys if (pkt().version < PGP_V4) { @@ -2597,10 +2504,10 @@ pgp_key_t::add_direct_sig(rnp_selfsig_cert_info_t &cert, #endif void -pgp_key_t::add_uid_cert(rnp_selfsig_cert_info_t &cert, - pgp_hash_alg_t hash, - rnp::SecurityContext & ctx, - pgp_key_t * pubkey) +pgp_key_t::add_uid_cert(rnp::CertParams & cert, + pgp_hash_alg_t hash, + rnp::SecurityContext &ctx, + pgp_key_t * pubkey) { if (cert.userid.empty()) { /* todo: why not to allow empty uid? */ @@ -2657,11 +2564,11 @@ pgp_key_t::add_uid_cert(rnp_selfsig_cert_info_t &cert, } void -pgp_key_t::add_sub_binding(pgp_key_t & subsec, - pgp_key_t & subpub, - const rnp_selfsig_binding_info_t &binding, - pgp_hash_alg_t hash, - rnp::SecurityContext & ctx) +pgp_key_t::add_sub_binding(pgp_key_t & subsec, + pgp_key_t & subpub, + const rnp::BindingParams &binding, + pgp_hash_alg_t hash, + rnp::SecurityContext & ctx) { if (!is_primary()) { RNP_LOG("must be called on primary key"); @@ -2675,11 +2582,11 @@ pgp_key_t::add_sub_binding(pgp_key_t & subsec, if (binding.key_expiration) { sig.set_key_expiration(binding.key_expiration); } - if (binding.key_flags) { - sig.set_key_flags(binding.key_flags); + if (binding.flags) { + sig.set_key_flags(binding.flags); } /* calculate binding */ - pgp_key_flags_t realkf = (pgp_key_flags_t) binding.key_flags; + pgp_key_flags_t realkf = (pgp_key_flags_t) binding.flags; if (!realkf) { realkf = pgp_pk_alg_capabilities(subsec.alg()); } @@ -2750,11 +2657,11 @@ pgp_key_t::refresh_data(const rnp::SecurityContext &ctx) } /* key flags: check in direct-key sig first, then primary uid, and then latest */ if (dirsig && dirsig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { - flags_ = dirsig->key_flags; + flags_ = dirsig->sig.key_flags(); } else if (prisig && prisig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { - flags_ = prisig->key_flags; + flags_ = prisig->sig.key_flags(); } else if (latest && latest->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { - flags_ = latest->key_flags; + flags_ = latest->sig.key_flags(); } else { flags_ = pgp_pk_alg_capabilities(alg()); } @@ -2818,7 +2725,7 @@ pgp_key_t::refresh_data(pgp_key_t *primary, const rnp::SecurityContext &ctx) expiration_ = sig ? sig->sig.key_expiration() : 0; /* subkey flags */ if (sig && sig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { - flags_ = sig->key_flags; + flags_ = sig->sig.key_flags(); } else { flags_ = pgp_pk_alg_capabilities(alg()); } diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index 5ff6de8d32..c30c81aa51 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -82,15 +82,11 @@ typedef struct pgp_rawpacket_t { /** information about the signature */ typedef struct pgp_subsig_t { - uint32_t uid{}; /* index in userid array in key for certification sig */ - pgp_signature_t sig{}; /* signature packet */ - pgp_sig_id_t sigid{}; /* signature identifier */ - pgp_rawpacket_t rawpkt{}; /* signature's rawpacket */ - uint8_t trustlevel{}; /* level of trust */ - uint8_t trustamount{}; /* amount of trust */ - uint8_t key_flags{}; /* key flags for certification/direct key sig */ - pgp_user_prefs_t prefs{}; /* user preferences for certification sig */ - pgp_validity_t validity{}; /* signature validity information */ + uint32_t uid{}; /* index in userid array in key for certification sig */ + pgp_signature_t sig{}; /* signature packet */ + pgp_sig_id_t sigid{}; /* signature identifier */ + pgp_rawpacket_t rawpkt{}; /* signature's rawpacket */ + pgp_validity_t validity{}; /* signature validity information */ pgp_subsig_t() = delete; pgp_subsig_t(const pgp_signature_t &sig); @@ -132,7 +128,9 @@ typedef struct pgp_userid_t { namespace rnp { class KeyStore; -} +class CertParams; +class BindingParams; +} // namespace rnp /* describes a user's key */ struct pgp_key_t { @@ -580,10 +578,10 @@ struct pgp_key_t { * @param pubkey if non-NULL then the direct-key signature will be added to this key as * well. */ - void add_direct_sig(rnp_selfsig_cert_info_t &cert, - pgp_hash_alg_t hash, - rnp::SecurityContext & ctx, - pgp_key_t * pubkey = nullptr); + void add_direct_sig(rnp::CertParams & cert, + pgp_hash_alg_t hash, + rnp::SecurityContext &ctx, + pgp_key_t * pubkey = nullptr); #endif /** @@ -596,10 +594,10 @@ struct pgp_key_t { * @param pubkey if non-NULL then userid and certification will be added to this key as * well. */ - void add_uid_cert(rnp_selfsig_cert_info_t &cert, - pgp_hash_alg_t hash, - rnp::SecurityContext & ctx, - pgp_key_t * pubkey = nullptr); + void add_uid_cert(rnp::CertParams & cert, + pgp_hash_alg_t hash, + rnp::SecurityContext &ctx, + pgp_key_t * pubkey = nullptr); /** * @brief Calculate and add subkey binding signature. @@ -612,11 +610,11 @@ struct pgp_key_t { * @param hash hash algorithm to use (may be adjusted according to key and subkey * algorithms) */ - void add_sub_binding(pgp_key_t & subsec, - pgp_key_t & subpub, - const rnp_selfsig_binding_info_t &binding, - pgp_hash_alg_t hash, - rnp::SecurityContext & ctx); + void add_sub_binding(pgp_key_t & subsec, + pgp_key_t & subpub, + const rnp::BindingParams &binding, + pgp_hash_alg_t hash, + rnp::SecurityContext & ctx); /** @brief Refresh internal fields after primary key is updated */ bool refresh_data(const rnp::SecurityContext &ctx); diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 73f5386571..6ca0514fd4 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -25,7 +25,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "crypto.h" #include "crypto/common.h" #include "pgp-key.h" #include "defaults.h" @@ -4399,343 +4398,210 @@ pk_alg_allows_custom_curve(pgp_pubkey_alg_t pkalg) } static bool -parse_preferences(json_object *jso, pgp_user_prefs_t &prefs) -{ - static const struct { - const char * key; - enum json_type type; - } properties[] = {{"hashes", json_type_array}, - {"ciphers", json_type_array}, - {"compression", json_type_array}, - {"key server", json_type_string}}; - - for (size_t iprop = 0; iprop < ARRAY_SIZE(properties); iprop++) { - json_object *value = NULL; - const char * key = properties[iprop].key; - - if (!json_object_object_get_ex(jso, key, &value)) { - continue; +parse_preferences(json_object *jso, rnp::UserPrefs &prefs) +{ + /* Preferred hashes */ + std::vector strs; + if (json_get_str_arr(jso, "hashes", strs)) { + for (auto &str : strs) { + pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN; + if (!str_to_hash_alg(str.c_str(), &hash_alg)) { + return false; + } + prefs.add_hash_alg(hash_alg); } - - if (!json_object_is_type(value, properties[iprop].type)) { - return false; + } + /* Preferred symmetric algorithms */ + if (json_get_str_arr(jso, "ciphers", strs)) { + for (auto &str : strs) { + pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN; + if (!str_to_cipher(str.c_str(), &symm_alg)) { + return false; + } + prefs.add_symm_alg(symm_alg); } - try { - if (rnp::str_case_eq(key, "hashes")) { - int length = json_object_array_length(value); - for (int i = 0; i < length; i++) { - json_object *item = json_object_array_get_idx(value, i); - if (!json_object_is_type(item, json_type_string)) { - return false; - } - pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN; - if (!str_to_hash_alg(json_object_get_string(item), &hash_alg)) { - return false; - } - prefs.add_hash_alg(hash_alg); - } - } else if (rnp::str_case_eq(key, "ciphers")) { - int length = json_object_array_length(value); - for (int i = 0; i < length; i++) { - json_object *item = json_object_array_get_idx(value, i); - if (!json_object_is_type(item, json_type_string)) { - return false; - } - pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN; - if (!str_to_cipher(json_object_get_string(item), &symm_alg)) { - return false; - } - prefs.add_symm_alg(symm_alg); - } - } else if (rnp::str_case_eq(key, "compression")) { - int length = json_object_array_length(value); - for (int i = 0; i < length; i++) { - json_object *item = json_object_array_get_idx(value, i); - if (!json_object_is_type(item, json_type_string)) { - return false; - } - pgp_compression_type_t z_alg = PGP_C_UNKNOWN; - if (!str_to_compression_alg(json_object_get_string(item), &z_alg)) { - return false; - } - prefs.add_z_alg(z_alg); - } - } else if (rnp::str_case_eq(key, "key server")) { - prefs.key_server = json_object_get_string(value); + } + /* Preferred compression algorithms */ + if (json_get_str_arr(jso, "compression", strs)) { + for (auto &str : strs) { + pgp_compression_type_t z_alg = PGP_C_UNKNOWN; + if (!str_to_compression_alg(str.c_str(), &z_alg)) { + return false; } - } catch (const std::exception &e) { - RNP_LOG("%s", e.what()); - return false; + prefs.add_z_alg(z_alg); } - // delete this field since it has been handled - json_object_object_del(jso, key); } - return true; + /* Preferred key server */ + std::string key_server; + if (json_get_str(jso, "key server", key_server)) { + prefs.key_server = key_server; + } + /* Do not allow extra unknown keys */ + return !json_object_object_length(jso); } -static bool -parse_keygen_crypto(json_object *jso, rnp_keygen_crypto_params_t &crypto) +static std::unique_ptr +parse_keygen_params(rnp_ffi_t ffi, json_object *jso) { - static const struct { - const char * key; - enum json_type type; - } properties[] = {{"type", json_type_string}, - {"curve", json_type_string}, - {"length", json_type_int}, - {"hash", json_type_string}}; - - for (size_t i = 0; i < ARRAY_SIZE(properties); i++) { - json_object *value = NULL; - const char * key = properties[i].key; - - if (!json_object_object_get_ex(jso, key, &value)) { - continue; + /* Type */ + std::string str; + pgp_pubkey_alg_t alg = PGP_PKA_RSA; + if (json_get_str(jso, "type", str) && !str_to_pubkey_alg(str.c_str(), &alg)) { + return nullptr; + } + std::unique_ptr params(new rnp::KeygenParams(alg, ffi->context)); + /* Length */ + int bits = 0; + if (json_get_int(jso, "length", bits)) { + auto bit_params = dynamic_cast(¶ms->key_params()); + if (!bit_params) { + return nullptr; } - - if (!json_object_is_type(value, properties[i].type)) { - return false; + bit_params->set_bits(bits); + } + /* Curve */ + if (json_get_str(jso, "curve", str)) { + if (!pk_alg_allows_custom_curve(params->alg())) { + return nullptr; } - // TODO: make sure there are no duplicate keys in the JSON - if (rnp::str_case_eq(key, "type")) { - if (!str_to_pubkey_alg(json_object_get_string(value), &crypto.key_alg)) { - return false; - } - } else if (rnp::str_case_eq(key, "length")) { - int length = json_object_get_int(value); - switch (crypto.key_alg) { - case PGP_PKA_RSA: - crypto.rsa.modulus_bit_len = length; - break; - case PGP_PKA_DSA: - crypto.dsa.p_bitlen = length; - break; - case PGP_PKA_ELGAMAL: - crypto.elgamal.key_bitlen = length; - break; - default: - return false; - } - } else if (rnp::str_case_eq(key, "curve")) { - if (!pk_alg_allows_custom_curve(crypto.key_alg)) { - return false; - } - if (!curve_str_to_type(json_object_get_string(value), &crypto.ecc.curve)) { - return false; - } - } else if (rnp::str_case_eq(key, "hash")) { - if (!str_to_hash_alg(json_object_get_string(value), &crypto.hash_alg)) { - return false; - } - } else { - // shouldn't happen - return false; + auto ecc_params = dynamic_cast(¶ms->key_params()); + pgp_curve_t curve = PGP_CURVE_UNKNOWN; + if (!ecc_params || !curve_str_to_type(str.c_str(), &curve)) { + return nullptr; } - // delete this field since it has been handled - json_object_object_del(jso, key); + ecc_params->set_curve(curve); } - return true; + /* Hash algorithm */ + if (json_get_str(jso, "hash", str)) { + pgp_hash_alg_t hash = PGP_HASH_UNKNOWN; + if (!str_to_hash_alg(str.c_str(), &hash)) { + return nullptr; + } + params->set_hash(hash); + } + return params; } static bool parse_protection(json_object *jso, rnp_key_protection_params_t &protection) { - static const struct { - const char * key; - enum json_type type; - } properties[] = {{"cipher", json_type_string}, - {"mode", json_type_string}, - {"iterations", json_type_int}, - {"hash", json_type_string}}; - - for (size_t i = 0; i < ARRAY_SIZE(properties); i++) { - json_object *value = NULL; - const char * key = properties[i].key; - - if (!json_object_object_get_ex(jso, key, &value)) { - continue; + /* Cipher */ + std::string str; + if (json_get_str(jso, "cipher", str)) { + if (!str_to_cipher(str.c_str(), &protection.symm_alg)) { + return false; + } + } + /* Mode */ + if (json_get_str(jso, "mode", str)) { + if (!str_to_cipher_mode(str.c_str(), &protection.cipher_mode)) { + return false; + } + } + /* Iterations */ + int iterations = 0; + if (json_get_int(jso, "iterations", iterations)) { + protection.iterations = iterations; + } + /* Hash algorithm */ + if (json_get_str(jso, "hash", str)) { + if (!str_to_hash_alg(str.c_str(), &protection.hash_alg)) { + return false; } + } + /* Do not allow extra unknown keys */ + return !json_object_object_length(jso); +} - if (!json_object_is_type(value, properties[i].type)) { +static bool +parse_keygen_common_fields(json_object * jso, + uint8_t & usage, + uint32_t & expiry, + rnp_key_protection_params_t &prot) +{ + /* Key/subkey usage flags */ + std::string str; + std::vector strs; + if (json_get_str(jso, "usage", str)) { + strs.push_back(str); + } else { + json_get_str_arr(jso, "usage", strs); + } + for (auto &st : strs) { + uint8_t flag = 0; + if (!str_to_key_flag(st.c_str(), &flag) || (usage & flag)) { return false; } - // TODO: make sure there are no duplicate keys in the JSON - if (rnp::str_case_eq(key, "cipher")) { - if (!str_to_cipher(json_object_get_string(value), &protection.symm_alg)) { - return false; - } - } else if (rnp::str_case_eq(key, "mode")) { - if (!str_to_cipher_mode(json_object_get_string(value), &protection.cipher_mode)) { - return false; - } - } else if (rnp::str_case_eq(key, "iterations")) { - protection.iterations = json_object_get_int(value); - } else if (rnp::str_case_eq(key, "hash")) { - if (!str_to_hash_alg(json_object_get_string(value), &protection.hash_alg)) { - return false; - } - } else { - // shouldn't happen + usage |= flag; + } + /* Key/subkey expiration */ + uint64_t keyexp = 0; + if (json_get_uint64(jso, "expiration", keyexp)) { + keyexp = expiry; + } + /* Protection */ + auto obj = json_get_obj(jso, "protection"); + if (obj) { + if (!parse_protection(obj, prot)) { return false; } - // delete this field since it has been handled - json_object_object_del(jso, key); + json_object_object_del(jso, "protection"); } return true; } -static bool -parse_keygen_primary(json_object * jso, - rnp_keygen_primary_desc_t & desc, +static std::unique_ptr +parse_keygen_primary(rnp_ffi_t ffi, + json_object * jso, + rnp::CertParams & cert, rnp_key_protection_params_t &prot) { - static const char *properties[] = { - "userid", "usage", "expiration", "preferences", "protection"}; - auto &cert = desc.cert; - - if (!parse_keygen_crypto(jso, desc.crypto)) { - return false; + /* Parse keygen params first */ + auto params = parse_keygen_params(ffi, jso); + if (!params) { + return nullptr; } - for (size_t i = 0; i < ARRAY_SIZE(properties); i++) { - json_object *value = NULL; - const char * key = properties[i]; - - if (!json_object_object_get_ex(jso, key, &value)) { - continue; + /* Parse common key/subkey fields */ + if (!parse_keygen_common_fields(jso, cert.flags, cert.key_expiration, prot)) { + return nullptr; + } + /* UserID */ + std::string str; + if (json_get_str(jso, "userid", str)) { + if (str.size() > MAX_ID_LENGTH) { + return nullptr; } - if (rnp::str_case_eq(key, "userid")) { - if (!json_object_is_type(value, json_type_string)) { - return false; - } - auto uid = json_object_get_string(value); - if (strlen(uid) > MAX_ID_LENGTH) { - return false; - } - cert.userid = json_object_get_string(value); - } else if (rnp::str_case_eq(key, "usage")) { - switch (json_object_get_type(value)) { - case json_type_array: { - int length = json_object_array_length(value); - for (int j = 0; j < length; j++) { - json_object *item = json_object_array_get_idx(value, j); - if (!json_object_is_type(item, json_type_string)) { - return false; - } - uint8_t flag = 0; - if (!str_to_key_flag(json_object_get_string(item), &flag)) { - return false; - } - // check for duplicate - if (cert.key_flags & flag) { - return false; - } - cert.key_flags |= flag; - } - } break; - case json_type_string: { - if (!str_to_key_flag(json_object_get_string(value), &cert.key_flags)) { - return false; - } - } break; - default: - return false; - } - } else if (rnp::str_case_eq(key, "expiration")) { - if (!json_object_is_type(value, json_type_int)) { - return false; - } - cert.key_expiration = json_object_get_int(value); - } else if (rnp::str_case_eq(key, "preferences")) { - if (!json_object_is_type(value, json_type_object)) { - return false; - } - if (!parse_preferences(value, cert.prefs)) { - return false; - } - if (json_object_object_length(value)) { - return false; - } - } else if (rnp::str_case_eq(key, "protection")) { - if (!json_object_is_type(value, json_type_object)) { - return false; - } - if (!parse_protection(value, prot)) { - return false; - } - if (json_object_object_length(value)) { - return false; - } + cert.userid = str; + } + /* Preferences */ + auto obj = json_get_obj(jso, "preferences"); + if (obj) { + if (!parse_preferences(obj, cert.prefs)) { + return nullptr; } - // delete this field since it has been handled - json_object_object_del(jso, key); + json_object_object_del(jso, "preferences"); } - return !json_object_object_length(jso); + /* Do not allow unknown extra fields */ + return json_object_object_length(jso) ? nullptr : std::move(params); } -static bool -parse_keygen_sub(json_object * jso, - rnp_keygen_subkey_desc_t & desc, +static std::unique_ptr +parse_keygen_sub(rnp_ffi_t ffi, + json_object * jso, + rnp::BindingParams & binding, rnp_key_protection_params_t &prot) { - static const char *properties[] = {"usage", "expiration", "protection"}; - auto & binding = desc.binding; - - if (!parse_keygen_crypto(jso, desc.crypto)) { - return false; + /* Parse keygen params first */ + auto params = parse_keygen_params(ffi, jso); + if (!params) { + return nullptr; } - for (size_t i = 0; i < ARRAY_SIZE(properties); i++) { - json_object *value = NULL; - const char * key = properties[i]; - - if (!json_object_object_get_ex(jso, key, &value)) { - continue; - } - if (rnp::str_case_eq(key, "usage")) { - switch (json_object_get_type(value)) { - case json_type_array: { - int length = json_object_array_length(value); - for (int j = 0; j < length; j++) { - json_object *item = json_object_array_get_idx(value, j); - if (!json_object_is_type(item, json_type_string)) { - return false; - } - uint8_t flag = 0; - if (!str_to_key_flag(json_object_get_string(item), &flag)) { - return false; - } - if (binding.key_flags & flag) { - return false; - } - binding.key_flags |= flag; - } - } break; - case json_type_string: { - if (!str_to_key_flag(json_object_get_string(value), &binding.key_flags)) { - return false; - } - } break; - default: - return false; - } - } else if (rnp::str_case_eq(key, "expiration")) { - if (!json_object_is_type(value, json_type_int)) { - return false; - } - binding.key_expiration = json_object_get_int(value); - } else if (rnp::str_case_eq(key, "protection")) { - if (!json_object_is_type(value, json_type_object)) { - return false; - } - if (!parse_protection(value, prot)) { - return false; - } - if (json_object_object_length(value)) { - return false; - } - } - // delete this field since it has been handled - json_object_object_del(jso, key); + /* Parse common with primary key fields */ + if (!parse_keygen_common_fields(jso, binding.flags, binding.key_expiration, prot)) { + return nullptr; } - return !json_object_object_length(jso); + /* Do not allow unknown extra fields */ + return json_object_object_length(jso) ? nullptr : std::move(params); } static bool @@ -4783,23 +4649,20 @@ gen_json_primary_key(rnp_ffi_t ffi, pgp_fingerprint_t & fp, bool protect) { - rnp_keygen_primary_desc_t desc = {}; - // desc.crypto is a union - // so at least Clang 12 on Windows zero-initializes the first union member only - // keeping the "larger" member partially uninitialized - desc.crypto.dsa.q_bitlen = 0; + rnp::CertParams cert; + cert.key_expiration = DEFAULT_KEY_EXPIRATION; - desc.cert.key_expiration = DEFAULT_KEY_EXPIRATION; - if (!parse_keygen_primary(jsoparams, desc, prot)) { + auto keygen = parse_keygen_primary(ffi, jsoparams, cert, prot); + if (!keygen) { return RNP_ERROR_BAD_PARAMETERS; } pgp_key_t pub; pgp_key_t sec; - desc.crypto.ctx = &ffi->context; - if (!pgp_generate_primary_key(desc, true, sec, pub, ffi->secring->format)) { + if (!keygen->generate(cert, sec, pub, ffi->secring->format)) { return RNP_ERROR_GENERIC; } + if (!ffi->pubring->add_key(pub)) { return RNP_ERROR_OUT_OF_MEMORY; } @@ -4821,28 +4684,22 @@ gen_json_subkey(rnp_ffi_t ffi, pgp_key_t & prim_sec, pgp_fingerprint_t &fp) { - rnp_keygen_subkey_desc_t desc = {}; + rnp::BindingParams binding; rnp_key_protection_params_t prot = {}; - desc.binding.key_expiration = DEFAULT_KEY_EXPIRATION; - if (!parse_keygen_sub(jsoparams, desc, prot)) { + binding.key_expiration = DEFAULT_KEY_EXPIRATION; + auto keygen = parse_keygen_sub(ffi, jsoparams, binding, prot); + if (!keygen) { return RNP_ERROR_BAD_PARAMETERS; } - if (!desc.binding.key_flags) { + if (!binding.flags) { /* Generate encrypt-only subkeys by default */ - desc.binding.key_flags = PGP_KF_ENCRYPT; + binding.flags = PGP_KF_ENCRYPT; } pgp_key_t pub; pgp_key_t sec; - desc.crypto.ctx = &ffi->context; - if (!pgp_generate_subkey(desc, - true, - prim_sec, - prim_pub, - sec, - pub, - ffi->pass_provider, - ffi->secring->format)) { + if (!keygen->generate( + binding, prim_sec, prim_pub, sec, pub, ffi->pass_provider, ffi->secring->format)) { return RNP_ERROR_GENERIC; } if (!ffi->pubring->add_key(pub)) { @@ -5043,7 +4900,7 @@ try { if (password && (ret = rnp_op_generate_set_protection_password(subop, password))) { goto done; } - if (pgp_pk_alg_capabilities(subop->crypto.key_alg) & PGP_KF_ENCRYPT) { + if (pgp_pk_alg_capabilities(subop->keygen.alg()) & PGP_KF_ENCRYPT) { if ((ret = rnp_op_generate_add_usage(subop, "encrypt"))) { goto done; } @@ -5241,12 +5098,9 @@ try { return RNP_ERROR_BAD_PARAMETERS; } - *op = new rnp_op_generate_st(); - (*op)->ffi = ffi; + *op = new rnp_op_generate_st(ffi, key_alg); (*op)->primary = true; - (*op)->crypto.key_alg = key_alg; - (*op)->crypto.ctx = &ffi->context; - (*op)->cert.key_flags = default_key_flags(key_alg, false); + (*op)->cert.flags = default_key_flags(key_alg, false); (*op)->cert.key_expiration = DEFAULT_KEY_EXPIRATION; return RNP_SUCCESS; @@ -5277,12 +5131,9 @@ try { return RNP_ERROR_BAD_PARAMETERS; } - *op = new rnp_op_generate_st(); - (*op)->ffi = ffi; + *op = new rnp_op_generate_st(ffi, key_alg); (*op)->primary = false; - (*op)->crypto.key_alg = key_alg; - (*op)->crypto.ctx = &ffi->context; - (*op)->binding.key_flags = default_key_flags(key_alg, true); + (*op)->binding.flags = default_key_flags(key_alg, true); (*op)->binding.key_expiration = DEFAULT_KEY_EXPIRATION; (*op)->primary_sec = primary->sec; (*op)->primary_pub = primary->pub; @@ -5298,22 +5149,11 @@ try { return RNP_ERROR_NULL_POINTER; } - switch (op->crypto.key_alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - op->crypto.rsa.modulus_bit_len = bits; - break; - case PGP_PKA_ELGAMAL: - op->crypto.elgamal.key_bitlen = bits; - break; - case PGP_PKA_DSA: - op->crypto.dsa.p_bitlen = bits; - break; - default: + auto bitkeygen = dynamic_cast(&op->keygen.key_params()); + if (!bitkeygen) { return RNP_ERROR_BAD_PARAMETERS; } - + bitkeygen->set_bits(bits); return RNP_SUCCESS; } FFI_GUARD @@ -5324,10 +5164,12 @@ try { if (!op || !hash) { return RNP_ERROR_NULL_POINTER; } - if (!str_to_hash_alg(hash, &op->crypto.hash_alg)) { + pgp_hash_alg_t halg = PGP_HASH_UNKNOWN; + if (!str_to_hash_alg(hash, &halg)) { FFI_LOG(op->ffi, "Invalid hash: %s", hash); return RNP_ERROR_BAD_PARAMETERS; } + op->keygen.set_hash(halg); return RNP_SUCCESS; } FFI_GUARD @@ -5338,10 +5180,11 @@ try { if (!op) { return RNP_ERROR_NULL_POINTER; } - if (op->crypto.key_alg != PGP_PKA_DSA) { + if (op->keygen.alg() != PGP_PKA_DSA) { return RNP_ERROR_BAD_PARAMETERS; } - op->crypto.dsa.q_bitlen = qbits; + auto &dsa = dynamic_cast(op->keygen.key_params()); + dsa.set_qbits(qbits); return RNP_SUCCESS; } FFI_GUARD @@ -5352,12 +5195,15 @@ try { if (!op || !curve) { return RNP_ERROR_NULL_POINTER; } - if (!pk_alg_allows_custom_curve(op->crypto.key_alg)) { + if (!pk_alg_allows_custom_curve(op->keygen.alg())) { return RNP_ERROR_BAD_PARAMETERS; } - if (!curve_str_to_type(curve, &op->crypto.ecc.curve)) { + pgp_curve_t eccurve = PGP_CURVE_UNKNOWN; + if (!curve_str_to_type(curve, &eccurve)) { return RNP_ERROR_BAD_PARAMETERS; } + auto &ecc = dynamic_cast(op->keygen.key_params()); + ecc.set_curve(eccurve); return RNP_SUCCESS; } FFI_GUARD @@ -5444,13 +5290,13 @@ try { if (!str_to_key_flag(usage, &flag)) { return RNP_ERROR_BAD_PARAMETERS; } - if (!(pgp_pk_alg_capabilities(op->crypto.key_alg) & flag)) { + if (!(pgp_pk_alg_capabilities(op->keygen.alg()) & flag)) { return RNP_ERROR_NOT_SUPPORTED; } if (op->primary) { - op->cert.key_flags |= flag; + op->cert.flags |= flag; } else { - op->binding.key_flags |= flag; + op->binding.flags |= flag; } return RNP_SUCCESS; } @@ -5463,9 +5309,9 @@ try { return RNP_ERROR_NULL_POINTER; } if (op->primary) { - op->cert.key_flags = 0; + op->cert.flags = 0; } else { - op->binding.key_flags = 0; + op->binding.flags = 0; } return RNP_SUCCESS; } @@ -5512,7 +5358,7 @@ try { if (!op->primary) { return RNP_ERROR_BAD_PARAMETERS; } - op->cert.prefs.set_hash_algs({}); + op->cert.prefs.hash_algs.clear(); return RNP_SUCCESS; } FFI_GUARD @@ -5544,7 +5390,7 @@ try { if (!op->primary) { return RNP_ERROR_BAD_PARAMETERS; } - op->cert.prefs.set_z_algs({}); + op->cert.prefs.z_algs.clear(); return RNP_SUCCESS; } FFI_GUARD @@ -5576,7 +5422,7 @@ try { if (!op->primary) { return RNP_ERROR_BAD_PARAMETERS; } - op->cert.prefs.set_symm_algs({}); + op->cert.prefs.symm_algs.clear(); return RNP_SUCCESS; } FFI_GUARD @@ -5620,7 +5466,7 @@ try { if (!op) { return RNP_ERROR_NULL_POINTER; } - op->pgp_version = PGP_V6; + op->keygen.set_version(PGP_V6); return RNP_SUCCESS; } FFI_GUARD @@ -5633,6 +5479,10 @@ try { if (!op || !param_cstr) { return RNP_ERROR_NULL_POINTER; } + auto slhdsa = dynamic_cast(&op->keygen.key_params()); + if (!slhdsa) { + return RNP_ERROR_BAD_PARAMETERS; + } sphincsplus_parameter_t param; std::string param_str = param_cstr; @@ -5653,7 +5503,7 @@ try { return RNP_ERROR_BAD_PARAMETERS; } - op->crypto.sphincsplus.param = param; + slhdsa->set_param(param); return RNP_SUCCESS; } FFI_GUARD @@ -5672,23 +5522,12 @@ try { pgp_password_provider_t prov; if (op->primary) { - rnp_keygen_primary_desc_t keygen = {}; - keygen.crypto = op->crypto; - keygen.cert = op->cert; - keygen.pgp_version = op->pgp_version; - op->cert.prefs = {}; /* generate call will free prefs */ - - if (!pgp_generate_primary_key(keygen, true, sec, pub, op->ffi->secring->format)) { + if (!op->keygen.generate(op->cert, sec, pub, op->ffi->secring->format)) { return RNP_ERROR_KEY_GENERATION; } } else { /* subkey generation */ - rnp_keygen_subkey_desc_t keygen = {}; - keygen.crypto = op->crypto; - keygen.binding = op->binding; - keygen.pgp_version = op->pgp_version; - if (!pgp_generate_subkey(keygen, - true, + if (!op->keygen.generate(op->binding, *op->primary_sec, *op->primary_pub, sec, @@ -5862,9 +5701,9 @@ try { FFI_LOG(handle->ffi, "UserID too long"); return RNP_ERROR_BAD_PARAMETERS; } - rnp_selfsig_cert_info_t info; + rnp::CertParams info; info.userid = uid; - info.key_flags = key_flags; + info.flags = key_flags; info.key_expiration = expiration; info.primary = primary; @@ -6003,12 +5842,12 @@ try { if (!id) { return RNP_ERROR_NULL_POINTER; } - *data = malloc(id->pkt.uid_len); - if (id->pkt.uid_len && !*data) { + *data = malloc(id->pkt.uid.size()); + if (id->pkt.uid.size() && !*data) { return RNP_ERROR_OUT_OF_MEMORY; } - memcpy(*data, id->pkt.uid, id->pkt.uid_len); - *size = id->pkt.uid_len; + memcpy(*data, id->pkt.uid.data(), id->pkt.uid.size()); + *size = id->pkt.uid.size(); return RNP_SUCCESS; } FFI_GUARD @@ -8362,57 +8201,44 @@ add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) } static bool -add_json_user_prefs(json_object *jso, const pgp_user_prefs_t &prefs) +add_json_array_lookup(json_object * jso, + std::vector vals, + const char * name, + const id_str_pair * map) { - // TODO: instead of using a string "Unknown" as a fallback for these, - // we could add a string of hex/dec (or even an int) - if (!prefs.symm_algs.empty()) { - json_object *jsoarr = json_object_new_array(); - if (!jsoarr || !json_add(jso, "ciphers", jsoarr)) { - return false; - } - for (auto alg : prefs.symm_algs) { - const char *name = id_str_pair::lookup(symm_alg_map, alg, "Unknown"); - if (!json_array_add(jsoarr, name)) { - return false; - } - } + if (vals.empty()) { + return true; } - if (!prefs.hash_algs.empty()) { - json_object *jsoarr = json_object_new_array(); - if (!jsoarr || !json_add(jso, "hashes", jsoarr)) { - return false; - } - for (auto alg : prefs.hash_algs) { - const char *name = id_str_pair::lookup(hash_alg_map, alg, "Unknown"); - if (!json_array_add(jsoarr, name)) { - return false; - } - } + json_object *jsoarr = json_object_new_array(); + if (!jsoarr || !json_add(jso, name, jsoarr)) { + return false; } - if (!prefs.z_algs.empty()) { - json_object *jsoarr = json_object_new_array(); - if (!jsoarr || !json_add(jso, "compression", jsoarr)) { + for (auto val : vals) { + const char *vname = id_str_pair::lookup(map, val, "Unknown"); + if (!json_array_add(jsoarr, vname)) { return false; } - for (auto alg : prefs.z_algs) { - const char *name = id_str_pair::lookup(compress_alg_map, alg, "Unknown"); - if (!json_array_add(jsoarr, name)) { - return false; - } - } } - if (!prefs.ks_prefs.empty()) { - json_object *jsoarr = json_object_new_array(); - if (!jsoarr || !json_add(jso, "key server preferences", jsoarr)) { - return false; - } - for (auto flag : prefs.ks_prefs) { - const char *name = id_str_pair::lookup(key_server_prefs_map, flag, "Unknown"); - if (!json_array_add(jsoarr, name)) { - return false; - } - } + return true; +} + +static bool +add_json_user_prefs(json_object *jso, const rnp::UserPrefs &prefs) +{ + // TODO: instead of using a string "Unknown" as a fallback for these, + // we could add a string of hex/dec (or even an int) + if (!add_json_array_lookup(jso, prefs.symm_algs, "ciphers", symm_alg_map)) { + return false; + } + if (!add_json_array_lookup(jso, prefs.hash_algs, "hashes", hash_alg_map)) { + return false; + } + if (!add_json_array_lookup(jso, prefs.z_algs, "compression", compress_alg_map)) { + return false; + } + if (!add_json_array_lookup( + jso, prefs.ks_prefs, "key server preferences", key_server_prefs_map)) { + return false; } if (!prefs.key_server.empty()) { if (!json_add(jso, "key server", prefs.key_server.c_str())) { @@ -8435,20 +8261,20 @@ add_json_subsig(json_object *jso, bool is_sub, uint32_t flags, const pgp_subsig_ return RNP_ERROR_OUT_OF_MEMORY; } // trust level and amount - if (!json_add(jsotrust, "level", (int) subsig->trustlevel) || - !json_add(jsotrust, "amount", (int) subsig->trustamount)) { + if (!json_add(jsotrust, "level", (int) subsig->sig.trust_level()) || + !json_add(jsotrust, "amount", (int) subsig->sig.trust_amount())) { return RNP_ERROR_OUT_OF_MEMORY; } // key flags (usage) - if (!add_json_key_usage(jso, subsig->key_flags)) { + if (!add_json_key_usage(jso, subsig->sig.key_flags())) { return RNP_ERROR_OUT_OF_MEMORY; } // key flags (other) - if (!add_json_key_flags(jso, subsig->key_flags)) { + if (!add_json_key_flags(jso, subsig->sig.key_flags())) { return RNP_ERROR_OUT_OF_MEMORY; } // preferences - const pgp_user_prefs_t &prefs = subsig->prefs; + const rnp::UserPrefs prefs(subsig->sig); if (!prefs.symm_algs.empty() || !prefs.hash_algs.empty() || !prefs.z_algs.empty() || !prefs.ks_prefs.empty() || !prefs.key_server.empty()) { json_object *jsoprefs = json_object_new_object(); diff --git a/src/lib/sig_subpacket.cpp b/src/lib/sig_subpacket.cpp index b13ab6b75a..f4072ee4f5 100644 --- a/src/lib/sig_subpacket.cpp +++ b/src/lib/sig_subpacket.cpp @@ -69,7 +69,7 @@ bool Raw::parse(const uint8_t *data, size_t size) { if (!check_size(size)) { - RNP_LOG("wrong len %zu of subpacket type %" PRIu8, size, type_); + RNP_LOG("wrong len %zu of subpacket type %" PRIu8, size, raw_type_); return false; } if (!parse_data(data, size)) { @@ -494,7 +494,7 @@ NotationData::parse_data(const uint8_t *data, size_t size) { uint16_t nlen = read_uint16(data + 4); uint16_t vlen = read_uint16(data + 6); - if (size != 8 + nlen + vlen) { + if (size != nlen + vlen + 8) { return false; } memcpy(flags_.data(), data, 4); diff --git a/src/lib/types.h b/src/lib/types.h index 11849c5147..2b90f8d0aa 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -289,115 +289,6 @@ typedef struct pgp_revoke_t { pgp_revoke_t(pgp_subsig_t &sig); } pgp_revoke_t; -typedef struct pgp_user_prefs_t { - // preferred symmetric algs (pgp_symm_alg_t) - std::vector symm_algs{}; - // preferred hash algs (pgp_hash_alg_t) - std::vector hash_algs{}; - // preferred compression algs (pgp_compression_type_t) - std::vector z_algs{}; - // key server preferences (pgp_key_server_prefs_t) - std::vector ks_prefs{}; - // preferred key server - std::string key_server{}; -#if defined(ENABLE_CRYPTO_REFRESH) - std::vector aead_prefs{}; -#endif - - void set_symm_algs(const std::vector &algs); - void add_symm_alg(pgp_symm_alg_t alg); - void set_hash_algs(const std::vector &algs); - void add_hash_alg(pgp_hash_alg_t alg); - void set_z_algs(const std::vector &algs); - void add_z_alg(pgp_compression_type_t alg); - void set_ks_prefs(const std::vector &prefs); - void add_ks_pref(pgp_key_server_prefs_t pref); -#if defined(ENABLE_CRYPTO_REFRESH) - void set_aead_prefs(const std::vector &algs); - void add_aead_prefs(pgp_symm_alg_t sym_alg, pgp_aead_alg_t aead_alg); -#endif - -} pgp_user_prefs_t; - -struct rnp_keygen_ecc_params_t { - pgp_curve_t curve; -}; - -struct rnp_keygen_rsa_params_t { - uint32_t modulus_bit_len; -}; - -struct rnp_keygen_dsa_params_t { - size_t p_bitlen; - size_t q_bitlen; -}; - -struct rnp_keygen_elgamal_params_t { - size_t key_bitlen; -}; - -#if defined(ENABLE_PQC) -struct rnp_keygen_sphincsplus_params_t { - sphincsplus_parameter_t param; -}; -#endif - -/* structure used to hold context of key generation */ -namespace rnp { -class SecurityContext; -} - -typedef struct rnp_keygen_crypto_params_t { - // Asymmetric algorithm that user requested key for - pgp_pubkey_alg_t key_alg; - // Hash to be used for key signature - pgp_hash_alg_t hash_alg; - // Pointer to security context - rnp::SecurityContext *ctx; - union { - struct rnp_keygen_ecc_params_t ecc; - struct rnp_keygen_rsa_params_t rsa; - struct rnp_keygen_dsa_params_t dsa; - struct rnp_keygen_elgamal_params_t elgamal; -#if defined(ENABLE_PQC) - struct rnp_keygen_sphincsplus_params_t sphincsplus; -#endif - }; -} rnp_keygen_crypto_params_t; - -typedef struct rnp_selfsig_cert_info_t { - std::string userid; /* userid, required */ - uint8_t key_flags{}; /* key flags */ - uint32_t key_expiration{}; /* key expiration time (sec), 0 = no expiration */ - pgp_user_prefs_t prefs{}; /* user preferences, optional */ - bool primary; /* mark this as the primary user id */ - - /** - * @brief Populate uid and sig packet with data stored in this struct. - * At some point we should get rid of it. - */ - void populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig); - void populate(pgp_signature_t &sig); - void populate(pgp_userid_pkt_t &uid); -} rnp_selfsig_cert_info_t; - -typedef struct rnp_selfsig_binding_info_t { - uint8_t key_flags; - uint32_t key_expiration; -} rnp_selfsig_binding_info_t; - -typedef struct rnp_keygen_primary_desc_t { - rnp_keygen_crypto_params_t crypto{}; - rnp_selfsig_cert_info_t cert{}; - pgp_version_t pgp_version = PGP_V4; -} rnp_keygen_primary_desc_t; - -typedef struct rnp_keygen_subkey_desc_t { - rnp_keygen_crypto_params_t crypto; - rnp_selfsig_binding_info_t binding; - pgp_version_t pgp_version = PGP_V4; -} rnp_keygen_subkey_desc_t; - typedef struct rnp_key_protection_params_t { pgp_symm_alg_t symm_alg; pgp_cipher_mode_t cipher_mode; diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 6d475ef8dd..ad425c9551 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -46,7 +46,6 @@ #include "crypto/s2k.h" #include "fingerprint.h" #include "pgp-key.h" -#include "crypto.h" #include "json-utils.h" #include @@ -1146,11 +1145,11 @@ stream_dump_userid(pgp_source_t *src, pgp_dest_t *dst) switch (uid.tag) { case PGP_PKT_USER_ID: dst_printf(dst, "id: "); - dst_write(dst, uid.uid, uid.uid_len); + dst_write(dst, uid.uid.data(), uid.uid.size()); dst_printf(dst, "\n"); break; case PGP_PKT_USER_ATTR: - dst_printf(dst, "id: (%d bytes of data)\n", (int) uid.uid_len); + dst_printf(dst, "id: (%zu bytes of data)\n", uid.uid.size()); break; default:; } @@ -2327,12 +2326,12 @@ stream_dump_userid_json(pgp_source_t *src, json_object *pkt) switch (uid.tag) { case PGP_PKT_USER_ID: - if (!json_add(pkt, "userid", (char *) uid.uid, uid.uid_len)) { + if (!json_add(pkt, "userid", (char *) uid.uid.data(), uid.uid.size())) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } break; case PGP_PKT_USER_ATTR: - if (!json_add_hex(pkt, "userattr", uid.uid, uid.uid_len)) { + if (!json_add_hex(pkt, "userattr", uid.uid.data(), uid.uid.size())) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } break; diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index 30fe3bf0fc..c9c310d853 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -44,7 +44,6 @@ #include "types.h" #include "fingerprint.h" #include "pgp-key.h" -#include "crypto.h" #include "crypto/signatures.h" #include "crypto/mem.h" #include "str-utils.h" @@ -662,66 +661,10 @@ encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng) } } -pgp_userid_pkt_t::pgp_userid_pkt_t(const pgp_userid_pkt_t &src) -{ - tag = src.tag; - uid_len = src.uid_len; - uid = NULL; - if (src.uid) { - uid = (uint8_t *) malloc(uid_len); - if (!uid) { - throw std::bad_alloc(); - } - memcpy(uid, src.uid, uid_len); - } -} - -pgp_userid_pkt_t::pgp_userid_pkt_t(pgp_userid_pkt_t &&src) -{ - tag = src.tag; - uid_len = src.uid_len; - uid = src.uid; - src.uid = NULL; -} - -pgp_userid_pkt_t & -pgp_userid_pkt_t::operator=(pgp_userid_pkt_t &&src) -{ - if (this == &src) { - return *this; - } - tag = src.tag; - uid_len = src.uid_len; - free(uid); - uid = src.uid; - src.uid = NULL; - return *this; -} - -pgp_userid_pkt_t & -pgp_userid_pkt_t::operator=(const pgp_userid_pkt_t &src) -{ - if (this == &src) { - return *this; - } - tag = src.tag; - uid_len = src.uid_len; - free(uid); - uid = NULL; - if (src.uid) { - uid = (uint8_t *) malloc(uid_len); - if (!uid) { - throw std::bad_alloc(); - } - memcpy(uid, src.uid, uid_len); - } - return *this; -} - bool pgp_userid_pkt_t::operator==(const pgp_userid_pkt_t &src) const { - return (tag == src.tag) && (uid_len == src.uid_len) && !memcmp(uid, src.uid, uid_len); + return (tag == src.tag) && (uid == src.uid); } bool @@ -729,12 +672,6 @@ pgp_userid_pkt_t::operator!=(const pgp_userid_pkt_t &src) const { return !(*this == src); } - -pgp_userid_pkt_t::~pgp_userid_pkt_t() -{ - free(uid); -} - void pgp_userid_pkt_t::write(pgp_dest_t &dst) const { @@ -742,15 +679,9 @@ pgp_userid_pkt_t::write(pgp_dest_t &dst) const RNP_LOG("wrong userid tag"); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - if (uid_len && !uid) { - RNP_LOG("null but non-empty userid"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } pgp_packet_body_t pktbody(tag); - if (uid) { - pktbody.add(uid, uid_len); - } + pktbody.add(uid.data(), uid.size()); pktbody.write(dst); } @@ -772,14 +703,8 @@ pgp_userid_pkt_t::parse(pgp_source_t &src) /* userid type, i.e. tag */ tag = (pgp_pkt_type_t) stag; - free(uid); - uid = (uint8_t *) malloc(pkt.size()); - if (!uid) { - RNP_LOG("allocation failed"); - return RNP_ERROR_OUT_OF_MEMORY; - } - memcpy(uid, pkt.data(), pkt.size()); - uid_len = pkt.size(); + uid.resize(pkt.size()); + memcpy(uid.data(), pkt.data(), pkt.size()); return RNP_SUCCESS; } diff --git a/src/librepgp/stream-packet.cpp b/src/librepgp/stream-packet.cpp index 1ed2239840..9419436ea7 100644 --- a/src/librepgp/stream-packet.cpp +++ b/src/librepgp/stream-packet.cpp @@ -37,7 +37,6 @@ #include #include #include "types.h" -#include "crypto.h" #include "crypto/mem.h" #include "stream-packet.h" #include "stream-key.h" diff --git a/src/librepgp/stream-packet.h b/src/librepgp/stream-packet.h index 11f3ee75b1..25445d27cb 100644 --- a/src/librepgp/stream-packet.h +++ b/src/librepgp/stream-packet.h @@ -230,18 +230,12 @@ typedef struct pgp_one_pass_sig_t { * binary blob as it is. It may be distinguished by tag field. */ typedef struct pgp_userid_pkt_t { - pgp_pkt_type_t tag; - uint8_t * uid; - size_t uid_len; - - pgp_userid_pkt_t() : tag(PGP_PKT_RESERVED), uid(NULL), uid_len(0){}; - pgp_userid_pkt_t(const pgp_userid_pkt_t &src); - pgp_userid_pkt_t(pgp_userid_pkt_t &&src); - pgp_userid_pkt_t &operator=(pgp_userid_pkt_t &&src); - pgp_userid_pkt_t &operator=(const pgp_userid_pkt_t &src); - bool operator==(const pgp_userid_pkt_t &src) const; - bool operator!=(const pgp_userid_pkt_t &src) const; - ~pgp_userid_pkt_t(); + pgp_pkt_type_t tag; + std::vector uid; + + bool operator==(const pgp_userid_pkt_t &src) const; + bool operator!=(const pgp_userid_pkt_t &src) const; + pgp_userid_pkt_t() : tag(PGP_PKT_RESERVED){}; void write(pgp_dest_t &dst) const; rnp_result_t parse(pgp_source_t &src); diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index 0b98b4fa18..6569d1d510 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -44,7 +44,6 @@ #include "str-utils.h" #include "types.h" #include "crypto/s2k.h" -#include "crypto.h" #include "crypto/signatures.h" #include "fingerprint.h" #include "pgp-key.h" diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index 0715ee25a8..0a5e53f8dd 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -100,7 +100,7 @@ void signature_hash_userid(const pgp_userid_pkt_t &uid, rnp::Hash &hash, pgp_version_t sigver) { if (sigver < PGP_V4) { - hash.add(uid.uid, uid.uid_len); + hash.add(uid.uid.data(), uid.uid.size()); return; } @@ -116,9 +116,9 @@ signature_hash_userid(const pgp_userid_pkt_t &uid, rnp::Hash &hash, pgp_version_ RNP_LOG("wrong uid"); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - write_uint32(hdr + 1, uid.uid_len); + write_uint32(hdr + 1, uid.uid.size()); hash.add(hdr, 5); - hash.add(uid.uid, uid.uid_len); + hash.add(uid.uid.data(), uid.uid.size()); } std::unique_ptr @@ -1256,71 +1256,3 @@ pgp_signature_t::fill_hashed_data() } hashed_data.assign(hbody.data(), hbody.data() + hbody.size()); } - -void -rnp_selfsig_cert_info_t::populate(pgp_userid_pkt_t &uid) -{ - uid.tag = PGP_PKT_USER_ID; - uid.uid_len = userid.size(); - if (!(uid.uid = (uint8_t *) malloc(uid.uid_len))) { - RNP_LOG("alloc failed"); - throw rnp::rnp_exception(RNP_ERROR_OUT_OF_MEMORY); - } - memcpy(uid.uid, userid.data(), uid.uid_len); -} - -void -rnp_selfsig_cert_info_t::populate(pgp_signature_t &sig) -{ - if (key_expiration) { - sig.set_key_expiration(key_expiration); - } - if (primary) { - sig.set_primary_uid(true); - } -#if defined(ENABLE_CRYPTO_REFRESH) - if ((sig.version == PGP_V6) && (sig.type() != PGP_SIG_DIRECT)) { - /* only set key expiraton and primary uid for v6 self-signatures - * since most information is stored in the direct-key signature of the primary key. - */ - - if (key_flags && (sig.type() == PGP_SIG_SUBKEY)) { - /* for v6 subkeys signatures we also add the key flags */ - sig.set_key_flags(key_flags); - } - return; - } else if ((sig.version == PGP_V6) && (sig.type() == PGP_SIG_DIRECT)) { - /* set some additional packets for v6 direct-key self signatures */ - sig.set_key_features(PGP_KEY_FEATURE_MDC | PGP_KEY_FEATURE_SEIPDV2); - if (!prefs.aead_prefs.empty()) { - sig.set_preferred_aead_algs(prefs.aead_prefs); - } - } -#endif - if (key_flags) { - sig.set_key_flags(key_flags); - } - if (!prefs.symm_algs.empty()) { - sig.set_preferred_symm_algs(prefs.symm_algs); - } - if (!prefs.hash_algs.empty()) { - sig.set_preferred_hash_algs(prefs.hash_algs); - } - if (!prefs.z_algs.empty()) { - sig.set_preferred_z_algs(prefs.z_algs); - } - if (!prefs.ks_prefs.empty()) { - sig.set_key_server_prefs(prefs.ks_prefs[0]); - } - if (!prefs.key_server.empty()) { - sig.set_key_server(prefs.key_server); - } -} - -void -rnp_selfsig_cert_info_t::populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig) -{ - sig.set_type(PGP_CERT_POSITIVE); - populate(sig); - populate(uid); -} diff --git a/src/tests/cipher.cpp b/src/tests/cipher.cpp index c12b8f33ca..e84a631741 100644 --- a/src/tests/cipher.cpp +++ b/src/tests/cipher.cpp @@ -25,7 +25,6 @@ */ #include -#include #include #include "rnp.h" #include @@ -34,6 +33,7 @@ #include "rnp_tests.h" #include "support.h" #include "fingerprint.h" +#include "keygen.hpp" TEST_F(rnp_tests, hash_test_success) { @@ -118,13 +118,12 @@ TEST_F(rnp_tests, pkcs1_rsa_test_success) uint8_t ptext[1024 / 8] = {'a', 'b', 'c', 0}; uint8_t dec[1024 / 8]; - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = PGP_PKA_RSA; - key_desc.hash_alg = PGP_HASH_SHA256; - key_desc.rsa.modulus_bit_len = 1024; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(PGP_PKA_RSA, global_ctx); + auto & rsa = dynamic_cast(keygen.key_params()); + rsa.set_bits(1024); + pgp_key_pkt_t seckey; - assert_true(pgp_generate_seckey(key_desc, seckey, true)); + assert_true(keygen.generate(seckey, true)); pgp_encrypted_material_t enc; assert_rnp_success(seckey.material->encrypt(global_ctx, enc, ptext, 3)); @@ -139,13 +138,9 @@ TEST_F(rnp_tests, pkcs1_rsa_test_success) TEST_F(rnp_tests, rnp_test_eddsa) { - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = PGP_PKA_EDDSA; - key_desc.hash_alg = PGP_HASH_SHA256; - key_desc.ctx = &global_ctx; - - pgp_key_pkt_t seckey; - assert_true(pgp_generate_seckey(key_desc, seckey, true)); + rnp::KeygenParams keygen(PGP_PKA_EDDSA, global_ctx); + pgp_key_pkt_t seckey; + assert_true(keygen.generate(seckey, true)); rnp::secure_vector hash(32); pgp_signature_material_t sig = {}; @@ -166,14 +161,13 @@ TEST_F(rnp_tests, rnp_test_eddsa) TEST_F(rnp_tests, rnp_test_x25519) { - rnp_keygen_crypto_params_t key_desc = {}; - key_desc.key_alg = PGP_PKA_ECDH; - key_desc.hash_alg = PGP_HASH_SHA256; - key_desc.ctx = &global_ctx; - key_desc.ecc.curve = PGP_CURVE_25519; + rnp::KeygenParams keygen(PGP_PKA_ECDH, global_ctx); + auto & ecc = dynamic_cast(keygen.key_params()); + ecc.set_curve(PGP_CURVE_25519); pgp_key_pkt_t seckey; - assert_true(pgp_generate_seckey(key_desc, seckey, true)); + assert_true(keygen.generate(seckey, true)); + /* check for length and correctly tweaked bits */ auto &ec = dynamic_cast(*seckey.material); assert_int_equal(ec.x().len, 32); @@ -249,17 +243,16 @@ TEST_F(rnp_tests, ecdsa_signverify_success) rnp::secure_vector hash(rnp::Hash::size(hash_alg)); global_ctx.rng.get(hash.data(), hash.size()); - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = PGP_PKA_ECDSA; - key_desc.hash_alg = hash_alg; - key_desc.ecc.curve = curves[i].id; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(PGP_PKA_ECDSA, global_ctx); + keygen.set_hash(hash_alg); + auto &ecc = dynamic_cast(keygen.key_params()); + ecc.set_curve(curves[i].id); pgp_key_pkt_t seckey1; pgp_key_pkt_t seckey2; - assert_true(pgp_generate_seckey(key_desc, seckey1, true)); - assert_true(pgp_generate_seckey(key_desc, seckey2, true)); + assert_true(keygen.generate(seckey1, true)); + assert_true(keygen.generate(seckey2, true)); pgp_signature_material_t sig = {}; sig.halg = hash_alg; @@ -287,14 +280,13 @@ TEST_F(rnp_tests, ecdh_roundtrip) size_t in_len = sizeof(in); for (size_t i = 0; i < ARRAY_SIZE(curves); i++) { - rnp_keygen_crypto_params_t key_desc{}; - key_desc.key_alg = PGP_PKA_ECDH; - key_desc.hash_alg = PGP_HASH_SHA512; - key_desc.ecc.curve = curves[i].id; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(PGP_PKA_ECDH, global_ctx); + keygen.set_hash(PGP_HASH_SHA512); + auto &ecc = dynamic_cast(keygen.key_params()); + ecc.set_curve(curves[i].id); pgp_key_pkt_t ecdh_key1{}; - assert_true(pgp_generate_seckey(key_desc, ecdh_key1, true)); + assert_true(keygen.generate(ecdh_key1, true)); pgp_fingerprint_t ecdh_key1_fpr{}; assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1)); @@ -340,14 +332,13 @@ TEST_F(rnp_tests, ecdh_decryptionNegativeCases) uint8_t res[36] = {0}; size_t res_len = sizeof(res); - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = PGP_PKA_ECDH; - key_desc.hash_alg = PGP_HASH_SHA512; - key_desc.ecc.curve = PGP_CURVE_NIST_P_256; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(PGP_PKA_ECDH, global_ctx); + keygen.set_hash(PGP_HASH_SHA512); + auto &ecc = dynamic_cast(keygen.key_params()); + ecc.set_curve(PGP_CURVE_NIST_P_256); pgp_key_pkt_t ecdh_key1; - assert_true(pgp_generate_seckey(key_desc, ecdh_key1, true)); + assert_true(keygen.generate(ecdh_key1, true)); pgp_fingerprint_t ecdh_key1_fpr = {}; assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1)); @@ -377,17 +368,14 @@ TEST_F(rnp_tests, ecdh_decryptionNegativeCases) #if defined(ENABLE_SM2) TEST_F(rnp_tests, sm2_roundtrip) { - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = PGP_PKA_SM2; - key_desc.hash_alg = PGP_HASH_SM3; - key_desc.ecc.curve = PGP_CURVE_SM2_P_256; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(PGP_PKA_SM2, global_ctx); + keygen.set_hash(PGP_HASH_SM3); uint8_t key[27] = {0}; global_ctx.rng.get(key, sizeof(key)); pgp_key_pkt_t seckey; - assert_true(pgp_generate_seckey(key_desc, seckey, true)); + assert_true(keygen.generate(seckey, true)); auto &eckey = *seckey.material; @@ -523,26 +511,21 @@ TEST_F(rnp_tests, test_dsa_roundtrip) global_ctx.rng.get(message, sizeof(message)); for (size_t i = 0; i < ARRAY_SIZE(keys); i++) { - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = PGP_PKA_DSA; - key_desc.hash_alg = keys[i].h; - key_desc.dsa.p_bitlen = keys[i].p; - key_desc.dsa.q_bitlen = keys[i].q; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(PGP_PKA_DSA, global_ctx); + keygen.set_hash(keys[i].h); + auto &dsa = dynamic_cast(keygen.key_params()); + dsa.set_bits(keys[i].p); + dsa.set_qbits(keys[i].q); pgp_key_pkt_t seckey; - assert_true(pgp_generate_seckey(key_desc, seckey, true)); + assert_true(keygen.generate(seckey, true)); // try to prevent timeouts in travis-ci - printf("p: %zu q: %zu h: %s\n", - key_desc.dsa.p_bitlen, - key_desc.dsa.q_bitlen, - rnp::Hash::name(key_desc.hash_alg)); + printf( + "p: %zu q: %zu h: %s\n", dsa.bits(), dsa.qbits(), rnp::Hash::name(keygen.hash())); fflush(stdout); - auto &key = *seckey.material; - - size_t h_size = rnp::Hash::size(keys[i].h); - rnp::secure_vector hash(message, message + h_size); + auto & key = *seckey.material; + rnp::secure_vector hash(message, message + rnp::Hash::size(keygen.hash())); pgp_signature_material_t sig = {}; assert_rnp_success(key.sign(global_ctx, sig, hash)); assert_rnp_success(key.verify(global_ctx, sig, hash)); @@ -555,34 +538,23 @@ TEST_F(rnp_tests, test_dsa_verify_negative) pgp_key_pkt_t sec_key1; pgp_key_pkt_t sec_key2; - struct key_params { - size_t p; - size_t q; - pgp_hash_alg_t h; - } key = {1024, 160, PGP_HASH_SHA1}; - global_ctx.rng.get(message, sizeof(message)); - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = PGP_PKA_DSA; - key_desc.hash_alg = key.h; - key_desc.dsa.p_bitlen = key.p; - key_desc.dsa.q_bitlen = key.q; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(PGP_PKA_DSA, global_ctx); + keygen.set_hash(PGP_HASH_SHA1); + auto &dsa = dynamic_cast(keygen.key_params()); + dsa.set_bits(1024); + dsa.set_qbits(160); - assert_true(pgp_generate_seckey(key_desc, sec_key1, true)); + assert_true(keygen.generate(sec_key1, true)); // try to prevent timeouts in travis-ci - printf("p: %zu q: %zu h: %s\n", - key_desc.dsa.p_bitlen, - key_desc.dsa.q_bitlen, - rnp::Hash::name(key_desc.hash_alg)); - assert_true(pgp_generate_seckey(key_desc, sec_key2, true)); + printf("p: %zu q: %zu h: %s\n", dsa.bits(), dsa.qbits(), rnp::Hash::name(keygen.hash())); + assert_true(keygen.generate(sec_key2, true)); auto &key1 = *sec_key1.material; auto &key2 = *sec_key2.material; - size_t h_size = rnp::Hash::size(key.h); - rnp::secure_vector hash(message, message + h_size); + rnp::secure_vector hash(message, message + rnp::Hash::size(keygen.hash())); pgp_signature_material_t sig = {}; assert_rnp_success(key1.sign(global_ctx, sig, hash)); // wrong key used @@ -611,13 +583,11 @@ TEST_F(rnp_tests, kyber_ecdh_roundtrip) } for (size_t i = 0; i < ARRAY_SIZE(algs); i++) { - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = algs[i]; - key_desc.hash_alg = PGP_HASH_SHA512; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(algs[i], global_ctx); + keygen.set_hash(PGP_HASH_SHA512); pgp_key_pkt_t key_pkt; - assert_true(pgp_generate_seckey(key_desc, key_pkt, true)); + assert_true(keygen.generate(key_pkt, true)); pgp_encrypted_material_t enc; assert_rnp_success(key_pkt.material->encrypt(global_ctx, enc, in, in_len)); @@ -643,16 +613,14 @@ TEST_F(rnp_tests, dilithium_exdsa_signverify_success) // Generate test data. Mainly to make valgrind not to complain about uninitialized data global_ctx.rng.get(message, sizeof(message)); - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = algs[i]; - key_desc.hash_alg = hash_alg; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(algs[i], global_ctx); + keygen.set_hash(hash_alg); pgp_key_pkt_t seckey1; pgp_key_pkt_t seckey2; - assert_true(pgp_generate_seckey(key_desc, seckey1, true)); - assert_true(pgp_generate_seckey(key_desc, seckey2, true)); + assert_true(keygen.generate(seckey1, true)); + assert_true(keygen.generate(seckey2, true)); auto &key1 = *seckey1.material; auto &key2 = *seckey2.material; @@ -685,16 +653,15 @@ TEST_F(rnp_tests, sphincsplus_signverify_success) // data global_ctx.rng.get(message, sizeof(message)); - rnp_keygen_crypto_params_t key_desc; - key_desc.key_alg = algs[i]; - key_desc.sphincsplus.param = params[j]; - key_desc.ctx = &global_ctx; + rnp::KeygenParams keygen(algs[i], global_ctx); + auto &slhdsa = dynamic_cast(keygen.key_params()); + slhdsa.set_param(params[j]); pgp_key_pkt_t seckey1; pgp_key_pkt_t seckey2; - assert_true(pgp_generate_seckey(key_desc, seckey1, true)); - assert_true(pgp_generate_seckey(key_desc, seckey2, true)); + assert_true(keygen.generate(seckey1, true)); + assert_true(keygen.generate(seckey2, true)); auto & key1 = *seckey1.material; auto & key2 = *seckey2.material; diff --git a/src/tests/generatekey.cpp b/src/tests/generatekey.cpp index 8da1c5c3ec..e220fc924d 100644 --- a/src/tests/generatekey.cpp +++ b/src/tests/generatekey.cpp @@ -32,13 +32,13 @@ #include "rnp_tests.h" #include "support.h" #include "crypto/common.h" -#include "crypto.h" #include "pgp-key.h" #include "librepgp/stream-ctx.h" #include "librepgp/stream-sig.h" #include "librepgp/stream-key.h" #include "defaults.h" #include +#include "keygen.hpp" static bool generate_test_key(const char *keystore, const char *userid, const char *hash, const char *home) @@ -1001,21 +1001,22 @@ TEST_F(rnp_tests, test_generated_key_sigs) // primary { - pgp_key_t pub; - pgp_key_t sec; - rnp_keygen_primary_desc_t desc; - pgp_signature_t * psig = NULL; - pgp_signature_t * ssig = NULL; - pgp_signature_info_t psiginfo = {}; - pgp_signature_info_t ssiginfo = {}; - - desc.crypto.key_alg = PGP_PKA_RSA; - desc.crypto.rsa.modulus_bit_len = 1024; - desc.crypto.ctx = &global_ctx; - desc.cert.userid = "test"; + pgp_key_t pub; + pgp_key_t sec; + pgp_signature_t * psig = NULL; + pgp_signature_t * ssig = NULL; + pgp_signature_info_t psiginfo = {}; + pgp_signature_info_t ssiginfo = {}; + + rnp::KeygenParams keygen(PGP_PKA_RSA, global_ctx); + auto & rsa = dynamic_cast(keygen.key_params()); + rsa.set_bits(1024); + + rnp::CertParams cert; + cert.userid = "test"; // generate - assert_true(pgp_generate_primary_key(desc, true, sec, pub, PGP_KEY_STORE_GPG)); + assert_true(keygen.generate(cert, sec, pub, PGP_KEY_STORE_GPG)); // add to our rings assert_true(pubring->add_key(pub)); @@ -1085,10 +1086,8 @@ TEST_F(rnp_tests, test_generated_key_sigs) // ensure validation fails with incorrect uid pgp_userid_pkt_t uid; uid.tag = PGP_PKT_USER_ID; - uid.uid = (uint8_t *) malloc(4); - assert_non_null(uid.uid); - uid.uid_len = 4; - memcpy(uid.uid, "fake", 4); + auto fake = "fake"; + uid.uid.assign(fake, fake + strlen(fake)); pub.validate_cert(psiginfo, pub.pkt(), uid, global_ctx); assert_false(psiginfo.valid); @@ -1136,25 +1135,22 @@ TEST_F(rnp_tests, test_generated_key_sigs) // sub { - pgp_key_t pub; - pgp_key_t sec; - rnp_keygen_subkey_desc_t desc = {}; - pgp_signature_t * psig = NULL; - pgp_signature_t * ssig = NULL; - pgp_signature_info_t psiginfo = {}; - pgp_signature_info_t ssiginfo = {}; - -#if defined(ENABLE_CRYPTO_REFRESH) - desc.pgp_version = PGP_V4; -#endif - desc.crypto.key_alg = PGP_PKA_RSA; - desc.crypto.rsa.modulus_bit_len = 1024; - desc.crypto.ctx = &global_ctx; + pgp_key_t pub; + pgp_key_t sec; + pgp_signature_t * psig = NULL; + pgp_signature_t * ssig = NULL; + pgp_signature_info_t psiginfo = {}; + pgp_signature_info_t ssiginfo = {}; + + rnp::KeygenParams keygen(PGP_PKA_RSA, global_ctx); + auto & rsa = dynamic_cast(keygen.key_params()); + rsa.set_bits(1024); // generate pgp_password_provider_t prov = {}; - assert_true(pgp_generate_subkey( - desc, true, *primary_sec, *primary_pub, sec, pub, prov, PGP_KEY_STORE_GPG)); + rnp::BindingParams binding; + assert_true(keygen.generate( + binding, *primary_sec, *primary_pub, sec, pub, prov, PGP_KEY_STORE_GPG)); assert_true(pub.valid()); assert_true(pub.validated()); assert_false(pub.expired()); diff --git a/src/tests/key-add-userid.cpp b/src/tests/key-add-userid.cpp index edd420573a..7e4d7bd1d3 100644 --- a/src/tests/key-add-userid.cpp +++ b/src/tests/key-add-userid.cpp @@ -27,6 +27,7 @@ #include "pgp-key.h" #include "rnp_tests.h" #include "support.h" +#include "keygen.hpp" /* This test loads a pgp keyring and adds a few userids to the key. */ @@ -63,9 +64,9 @@ TEST_F(rnp_tests, test_key_add_userid) unsigned subsigc = key->sig_count(); // add first, non-primary userid - rnp_selfsig_cert_info_t selfsig0; + rnp::CertParams selfsig0; selfsig0.userid = "added0"; - selfsig0.key_flags = 0x2; + selfsig0.flags = 0x2; selfsig0.key_expiration = base_expiry; selfsig0.primary = false; auto curtime = global_ctx.time(); @@ -96,9 +97,9 @@ TEST_F(rnp_tests, test_key_add_userid) assert_true(key->get_uid(uidc).valid); // add a primary userid - rnp_selfsig_cert_info_t selfsig1; + rnp::CertParams selfsig1; selfsig1.userid = "added1"; - selfsig1.key_flags = 0xAB; + selfsig1.flags = 0xAB; selfsig1.key_expiration = base_expiry + 1; selfsig1.primary = 1; key->add_uid_cert(selfsig1, PGP_HASH_SHA256, global_ctx); @@ -111,18 +112,18 @@ TEST_F(rnp_tests, test_key_add_userid) assert_true(key->get_uid(uidc + 1).valid); // try to add the same userid (should fail) - rnp_selfsig_cert_info_t dup_selfsig; + rnp::CertParams dup_selfsig; dup_selfsig.userid = "added1"; assert_throw(key->add_uid_cert(dup_selfsig, PGP_HASH_SHA256, global_ctx)); // try to add another primary userid (should fail) - rnp_selfsig_cert_info_t selfsig2; + rnp::CertParams selfsig2; selfsig2.userid = "added2"; selfsig2.primary = 1; assert_throw(key->add_uid_cert(selfsig2, PGP_HASH_SHA256, global_ctx)); selfsig2.userid = "added2"; - selfsig2.key_flags = 0xCD; + selfsig2.flags = 0xCD; selfsig2.primary = 0; // actually add another userid @@ -140,15 +141,15 @@ TEST_F(rnp_tests, test_key_add_userid) // added0 assert_string_equal(key->get_uid(uidc).str.c_str(), "added0"); assert_int_equal(uidc, key->get_sig(subsigc).uid); - assert_int_equal(0x2, key->get_sig(subsigc).key_flags); + assert_int_equal(0x2, key->get_sig(subsigc).sig.key_flags()); // added1 assert_string_equal(key->get_uid(uidc + 1).str.c_str(), "added1"); assert_int_equal(uidc + 1, key->get_sig(subsigc + 1).uid); - assert_int_equal(0xAB, key->get_sig(subsigc + 1).key_flags); + assert_int_equal(0xAB, key->get_sig(subsigc + 1).sig.key_flags()); // added2 assert_string_equal(key->get_uid(uidc + 2).str.c_str(), "added2"); assert_int_equal(uidc + 2, key->get_sig(subsigc + 2).uid); - assert_int_equal(0xCD, key->get_sig(subsigc + 2).key_flags); + assert_int_equal(0xCD, key->get_sig(subsigc + 2).sig.key_flags()); // save the raw packets for the key (to reload later) assert_rnp_success(init_mem_dest(&dst, NULL, 0)); @@ -179,24 +180,24 @@ TEST_F(rnp_tests, test_key_add_userid) // added0 assert_string_equal(key->get_uid(uidc).str.c_str(), "added0"); assert_int_equal(uidc, key->get_sig(subsigc).uid); - assert_int_equal(0x2, key->get_sig(subsigc).key_flags); + assert_int_equal(0x2, key->get_sig(subsigc).sig.key_flags()); assert_true(key->get_uid(uidc).valid); // added1 assert_string_equal(key->get_uid(uidc + 1).str.c_str(), "added1"); assert_int_equal(uidc + 1, key->get_sig(subsigc + 1).uid); - assert_int_equal(0xAB, key->get_sig(subsigc + 1).key_flags); + assert_int_equal(0xAB, key->get_sig(subsigc + 1).sig.key_flags()); assert_true(key->get_uid(uidc + 1).valid); // added2 assert_string_equal(key->get_uid(uidc + 2).str.c_str(), "added2"); assert_int_equal(uidc + 2, key->get_sig(subsigc + 2).uid); - assert_int_equal(0xCD, key->get_sig(subsigc + 2).key_flags); + assert_int_equal(0xCD, key->get_sig(subsigc + 2).sig.key_flags()); assert_true(key->get_uid(uidc + 2).valid); // delete primary userid and see how flags/expiration changes key->del_uid(uidc + 1); key->revalidate(*ks); assert_string_equal(key->get_uid(uidc + 1).str.c_str(), "added2"); assert_int_equal(uidc + 1, key->get_sig(subsigc + 1).uid); - assert_int_equal(0xCD, key->get_sig(subsigc + 1).key_flags); + assert_int_equal(0xCD, key->get_sig(subsigc + 1).sig.key_flags()); assert_int_equal(key->expiration(), 0); assert_int_equal(key->flags(), 0xCD); // delete first uid @@ -204,7 +205,7 @@ TEST_F(rnp_tests, test_key_add_userid) key->revalidate(*ks); assert_string_equal(key->get_uid(uidc).str.c_str(), "added2"); assert_int_equal(uidc, key->get_sig(subsigc).uid); - assert_int_equal(0xCD, key->get_sig(subsigc).key_flags); + assert_int_equal(0xCD, key->get_sig(subsigc).sig.key_flags()); assert_int_equal(key->expiration(), 0); assert_int_equal(key->flags(), 0xCD); // delete last uid, leaving added0 only @@ -212,7 +213,7 @@ TEST_F(rnp_tests, test_key_add_userid) key->revalidate(*ks); assert_string_equal(key->get_uid(uidc - 1).str.c_str(), "added0"); assert_int_equal(uidc - 1, key->get_sig(subsigc - 1).uid); - assert_int_equal(0x2, key->get_sig(subsigc - 1).key_flags); + assert_int_equal(0x2, key->get_sig(subsigc - 1).sig.key_flags()); assert_int_equal(key->expiration(), base_expiry); assert_int_equal(key->flags(), 0x2); // delete added0 diff --git a/src/tests/key-prefs.cpp b/src/tests/key-prefs.cpp index 5732dd5ac4..6db466afac 100644 --- a/src/tests/key-prefs.cpp +++ b/src/tests/key-prefs.cpp @@ -28,11 +28,12 @@ #include "rnp_tests.h" #include "support.h" +#include "keygen.hpp" TEST_F(rnp_tests, test_key_prefs) { - pgp_user_prefs_t pref1 = {}; - pgp_user_prefs_t pref2 = {}; + rnp::UserPrefs pref1; + rnp::UserPrefs pref2; /* symm algs */ pref1.add_symm_alg(PGP_SA_AES_256); @@ -48,7 +49,7 @@ TEST_F(rnp_tests, test_key_prefs) pref2.add_symm_alg(PGP_SA_CAMELLIA_128); pref2.add_symm_alg(PGP_SA_CAMELLIA_192); pref2.add_symm_alg(PGP_SA_CAMELLIA_256); - pref1.set_symm_algs(pref2.symm_algs); + pref1.symm_algs = pref2.symm_algs; assert_int_equal(pref1.symm_algs.size(), 3); assert_int_equal(pref1.symm_algs[0], PGP_SA_CAMELLIA_128); assert_int_equal(pref1.symm_algs[1], PGP_SA_CAMELLIA_192); @@ -67,7 +68,7 @@ TEST_F(rnp_tests, test_key_prefs) pref2.add_hash_alg(PGP_HASH_SHA3_512); pref2.add_hash_alg(PGP_HASH_SHA3_256); pref2.add_hash_alg(PGP_HASH_SHA1); - pref1.set_hash_algs(pref2.hash_algs); + pref1.hash_algs = pref2.hash_algs; assert_int_equal(pref1.hash_algs.size(), 3); assert_int_equal(pref1.hash_algs[0], PGP_HASH_SHA3_512); assert_int_equal(pref1.hash_algs[1], PGP_HASH_SHA3_256); @@ -84,7 +85,7 @@ TEST_F(rnp_tests, test_key_prefs) assert_int_equal(pref1.z_algs[1], PGP_C_ZLIB); assert_int_equal(pref1.z_algs[2], PGP_C_BZIP2); pref2.add_z_alg(PGP_C_BZIP2); - pref1.set_z_algs(pref2.z_algs); + pref1.z_algs = pref2.z_algs; assert_int_equal(pref1.z_algs.size(), 1); assert_int_equal(pref1.z_algs[0], PGP_C_BZIP2); /* ks prefs */ @@ -93,7 +94,7 @@ TEST_F(rnp_tests, test_key_prefs) assert_int_equal(pref1.ks_prefs[0], PGP_KEY_SERVER_NO_MODIFY); pref2.add_ks_pref((pgp_key_server_prefs_t) 0x20); pref2.add_ks_pref((pgp_key_server_prefs_t) 0x40); - pref1.set_ks_prefs(pref2.ks_prefs); + pref1.ks_prefs = pref2.ks_prefs; assert_int_equal(pref1.ks_prefs.size(), 2); assert_int_equal(pref1.ks_prefs[0], 0x20); assert_int_equal(pref1.ks_prefs[1], 0x40); diff --git a/src/tests/key-protect.cpp b/src/tests/key-protect.cpp index af951c3260..740abffd8f 100644 --- a/src/tests/key-protect.cpp +++ b/src/tests/key-protect.cpp @@ -28,7 +28,7 @@ #include "rnp_tests.h" #include "support.h" -#include "crypto.h" +#include "keygen.hpp" bool rsa_sec_empty(const pgp::KeyMaterial &key) @@ -231,23 +231,20 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) TEST_F(rnp_tests, test_key_protect_sec_data) { - rnp_keygen_primary_desc_t pri_desc = {}; - pri_desc.crypto.key_alg = PGP_PKA_RSA; - pri_desc.crypto.rsa.modulus_bit_len = 1024; - pri_desc.crypto.ctx = &global_ctx; - pri_desc.cert.userid = "test"; + rnp::KeygenParams keygen(PGP_PKA_RSA, global_ctx); + auto & rsa = dynamic_cast(keygen.key_params()); + rsa.set_bits(1024); - rnp_keygen_subkey_desc_t sub_desc = {}; - sub_desc.crypto.key_alg = PGP_PKA_RSA; - sub_desc.crypto.rsa.modulus_bit_len = 1024; - sub_desc.crypto.ctx = &global_ctx; + rnp::CertParams cert; + cert.userid = "test"; + + rnp::BindingParams binding; /* generate raw unprotected keypair */ pgp_key_t skey, pkey, ssub, psub; pgp_password_provider_t prov = {}; - assert_true(pgp_generate_primary_key(pri_desc, true, skey, pkey, PGP_KEY_STORE_GPG)); - assert_true( - pgp_generate_subkey(sub_desc, true, skey, pkey, ssub, psub, prov, PGP_KEY_STORE_GPG)); + assert_true(keygen.generate(cert, skey, pkey, PGP_KEY_STORE_GPG)); + assert_true(keygen.generate(binding, skey, pkey, ssub, psub, prov, PGP_KEY_STORE_GPG)); assert_non_null(skey.pkt().sec_data); assert_non_null(ssub.pkt().sec_data); assert_null(pkey.pkt().sec_data); diff --git a/src/tests/key-store-search.cpp b/src/tests/key-store-search.cpp index af9a67cefb..38095fbb93 100644 --- a/src/tests/key-store-search.cpp +++ b/src/tests/key-store-search.cpp @@ -75,10 +75,8 @@ TEST_F(rnp_tests, test_key_store_search) for (size_t uidn = 0; testdata[i].userids[uidn]; uidn++) { pgp_transferable_userid_t tuid; tuid.uid.tag = PGP_PKT_USER_ID; - tuid.uid.uid_len = strlen(testdata[i].userids[uidn]); - tuid.uid.uid = (uint8_t *) malloc(tuid.uid.uid_len); - assert_non_null(tuid.uid.uid); - memcpy(tuid.uid.uid, testdata[i].userids[uidn], tuid.uid.uid_len); + auto uiddata = testdata[i].userids[uidn]; + tuid.uid.uid.assign(uiddata, uiddata + strlen(uiddata)); key.add_uid(tuid); } // add to the store diff --git a/src/tests/key-validate.cpp b/src/tests/key-validate.cpp index 0a5c924ed8..d3ab059b6f 100644 --- a/src/tests/key-validate.cpp +++ b/src/tests/key-validate.cpp @@ -30,6 +30,7 @@ #include "support.h" #include "../librepgp/stream-packet.h" #include "../librepgp/stream-armor.h" +#include "keygen.hpp" static bool all_keys_valid(const rnp::KeyStore *keyring, pgp_key_t *except = NULL) @@ -665,8 +666,8 @@ TEST_F(rnp_tests, test_key_expiry_direct_sig) assert_false(subpub->expired()); /* add primary userid with smaller expiration date */ - rnp_selfsig_cert_info_t selfsig1 = {}; - const char * boris = "Boris "; + rnp::CertParams selfsig1 = {}; + const char * boris = "Boris "; selfsig1.userid = boris; selfsig1.key_expiration = 100; selfsig1.primary = true; diff --git a/src/tests/load-pgp.cpp b/src/tests/load-pgp.cpp index 888ddbcc28..7e204b9136 100644 --- a/src/tests/load-pgp.cpp +++ b/src/tests/load-pgp.cpp @@ -787,7 +787,7 @@ TEST_F(rnp_tests, test_key_import) assert_int_equal(tkey.userids.size(), 1); assert_non_null(tuid = &tkey.userids.front()); assert_true(tuid->signatures.empty()); - assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15)); + assert_false(memcmp(tuid->uid.uid.data(), "key-merge-uid-1", 15)); assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY); assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID); @@ -807,7 +807,7 @@ TEST_F(rnp_tests, test_key_import) assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY); assert_non_null(tuid = &tkey.userids.front()); assert_int_equal(tuid->signatures.size(), 1); - assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15)); + assert_false(memcmp(tuid->uid.uid.data(), "key-merge-uid-1", 15)); assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID); /* import public key + 1 subkey */ @@ -826,7 +826,7 @@ TEST_F(rnp_tests, test_key_import) assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY); assert_non_null(tuid = &tkey.userids.front()); assert_int_equal(tuid->signatures.size(), 1); - assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15)); + assert_false(memcmp(tuid->uid.uid.data(), "key-merge-uid-1", 15)); assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID); assert_non_null(tskey = &tkey.subkeys.front()); assert_int_equal(tskey->signatures.size(), 1); @@ -848,7 +848,7 @@ TEST_F(rnp_tests, test_key_import) assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY); assert_non_null(tuid = &tkey.userids.front()); assert_int_equal(tuid->signatures.size(), 1); - assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15)); + assert_false(memcmp(tuid->uid.uid.data(), "key-merge-uid-1", 15)); assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID); assert_non_null(tskey = &tkey.subkeys.front()); assert_int_equal(tskey->signatures.size(), 1); @@ -862,7 +862,7 @@ TEST_F(rnp_tests, test_key_import) assert_rnp_success(decrypt_secret_key(&tkey.key, "password")); assert_non_null(tuid = &tkey.userids.front()); assert_int_equal(tuid->signatures.size(), 1); - assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15)); + assert_false(memcmp(tuid->uid.uid.data(), "key-merge-uid-1", 15)); assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID); assert_non_null(tskey = &tkey.subkeys.front()); assert_int_equal(tskey->signatures.size(), 1); @@ -885,11 +885,11 @@ TEST_F(rnp_tests, test_key_import) assert_int_equal(tkey.key.tag, PGP_PKT_PUBLIC_KEY); assert_non_null(tuid = &tkey.userids.front()); assert_int_equal(tuid->signatures.size(), 1); - assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15)); + assert_false(memcmp(tuid->uid.uid.data(), "key-merge-uid-1", 15)); assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID); assert_non_null(tuid = &tkey.userids[1]); assert_int_equal(tuid->signatures.size(), 1); - assert_false(memcmp(tuid->uid.uid, "key-merge-uid-2", 15)); + assert_false(memcmp(tuid->uid.uid.data(), "key-merge-uid-2", 15)); assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID); assert_non_null(tskey = &tkey.subkeys.front()); assert_int_equal(tskey->signatures.size(), 1); @@ -906,11 +906,11 @@ TEST_F(rnp_tests, test_key_import) assert_rnp_success(decrypt_secret_key(&tkey.key, "password")); assert_non_null(tuid = &tkey.userids.front()); assert_int_equal(tuid->signatures.size(), 1); - assert_false(memcmp(tuid->uid.uid, "key-merge-uid-1", 15)); + assert_false(memcmp(tuid->uid.uid.data(), "key-merge-uid-1", 15)); assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID); assert_non_null(tuid = &tkey.userids[1]); assert_int_equal(tuid->signatures.size(), 1); - assert_false(memcmp(tuid->uid.uid, "key-merge-uid-2", 15)); + assert_false(memcmp(tuid->uid.uid.data(), "key-merge-uid-2", 15)); assert_int_equal(tuid->uid.tag, PGP_PKT_USER_ID); assert_non_null(tskey = &tkey.subkeys.front()); assert_int_equal(tskey->signatures.size(), 1); diff --git a/src/tests/support.cpp b/src/tests/support.cpp index 1f6bc32bf2..e9eb7e7963 100644 --- a/src/tests/support.cpp +++ b/src/tests/support.cpp @@ -44,7 +44,6 @@ #include #include -#include #include #include #include diff --git a/src/tests/user-prefs.cpp b/src/tests/user-prefs.cpp index 8511045fb3..e09ab47ed1 100644 --- a/src/tests/user-prefs.cpp +++ b/src/tests/user-prefs.cpp @@ -29,6 +29,7 @@ #include "rnp_tests.h" #include "support.h" #include "pgp-key.h" +#include "keygen.hpp" static const pgp_subsig_t * find_subsig(const pgp_key_t *key, const char *userid) @@ -71,7 +72,7 @@ TEST_F(rnp_tests, test_load_user_prefs) const pgp_subsig_t *subsig = find_subsig(key, userid); assert_non_null(subsig); - const pgp_user_prefs_t &prefs = subsig->prefs; + const rnp::UserPrefs prefs(subsig->sig); // symm algs std::vector expected = {PGP_SA_AES_192, PGP_SA_CAST5}; @@ -99,7 +100,7 @@ TEST_F(rnp_tests, test_load_user_prefs) const pgp_subsig_t *subsig = find_subsig(key, userid); assert_non_null(subsig); - const pgp_user_prefs_t &prefs = subsig->prefs; + const rnp::UserPrefs prefs(subsig->sig); // symm algs std::vector expected = {PGP_SA_AES_256, PGP_SA_AES_192,