1 /*-
2  * Copyright (c) 2017-2021, Ribose Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
18  * CONTRIBUTORS
19  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "crypto.h"
29 #include "crypto/common.h"
30 #include "pgp-key.h"
31 #include "defaults.h"
32 #include <assert.h>
33 #include <json_object.h>
34 #include <json.h>
35 #include <librekey/key_store_pgp.h>
36 #include <librepgp/stream-ctx.h>
37 #include <librepgp/stream-common.h>
38 #include <librepgp/stream-armor.h>
39 #include <librepgp/stream-parse.h>
40 #include <librepgp/stream-write.h>
41 #include <librepgp/stream-sig.h>
42 #include <librepgp/stream-packet.h>
43 #include <librepgp/stream-key.h>
44 #include <librepgp/stream-dump.h>
45 #include <rnp/rnp.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #ifdef _MSC_VER
49 #include "uniwin.h"
50 #include <inttypes.h>
51 #else
52 #include <unistd.h>
53 #endif
54 #include <string.h>
55 #include <sys/stat.h>
56 #include <stdexcept>
57 #include "utils.h"
58 #include "str-utils.h"
59 #include "json-utils.h"
60 #include "version.h"
61 #include "ffi-priv-types.h"
62 #include "file-utils.h"
63 
64 #define FFI_LOG(ffi, ...)            \
65     do {                             \
66         FILE *fp = stderr;           \
67         if (ffi && ffi->errs) {      \
68             fp = ffi->errs;          \
69         }                            \
70         RNP_LOG_FD(fp, __VA_ARGS__); \
71     } while (0)
72 
73 static pgp_key_t *get_key_require_public(rnp_key_handle_t handle);
74 static pgp_key_t *get_key_prefer_public(rnp_key_handle_t handle);
75 static pgp_key_t *get_key_require_secret(rnp_key_handle_t handle);
76 
77 static bool locator_to_str(const pgp_key_search_t *locator,
78                            const char **           identifier_type,
79                            char *                  identifier,
80                            size_t                  identifier_size);
81 
82 static bool rnp_password_cb_bounce(const pgp_password_ctx_t *ctx,
83                                    char *                    password,
84                                    size_t                    password_size,
85                                    void *                    userdata_void);
86 
87 static rnp_result_t rnp_dump_src_to_json(pgp_source_t *src, uint32_t flags, char **result);
88 
89 static pgp_key_t *
find_key(rnp_ffi_t ffi,const pgp_key_search_t * search,key_type_t key_type,bool try_key_provider)90 find_key(rnp_ffi_t               ffi,
91          const pgp_key_search_t *search,
92          key_type_t              key_type,
93          bool                    try_key_provider)
94 {
95     pgp_key_t *key = NULL;
96 
97     switch (key_type) {
98     case KEY_TYPE_PUBLIC:
99         key = rnp_key_store_search(ffi->pubring, search, NULL);
100         break;
101     case KEY_TYPE_SECRET:
102         key = rnp_key_store_search(ffi->secring, search, NULL);
103         break;
104     default:
105         assert(false);
106         break;
107     }
108     if (!key && ffi->getkeycb && try_key_provider) {
109         char        identifier[RNP_LOCATOR_MAX_SIZE];
110         const char *identifier_type = NULL;
111 
112         if (locator_to_str(search, &identifier_type, identifier, sizeof(identifier))) {
113             ffi->getkeycb(ffi,
114                           ffi->getkeycb_ctx,
115                           identifier_type,
116                           identifier,
117                           key_type == KEY_TYPE_SECRET);
118             // recurse and try the store search above once more
119             return find_key(ffi, search, key_type, false);
120         }
121     }
122     return key;
123 }
124 
125 static pgp_key_t *
ffi_key_provider(const pgp_key_request_ctx_t * ctx,void * userdata)126 ffi_key_provider(const pgp_key_request_ctx_t *ctx, void *userdata)
127 {
128     rnp_ffi_t ffi = (rnp_ffi_t) userdata;
129     return find_key(ffi, &ctx->search, ctx->secret ? KEY_TYPE_SECRET : KEY_TYPE_PUBLIC, true);
130 }
131 
132 static void
rnp_ctx_init_ffi(rnp_ctx_t & ctx,rnp_ffi_t ffi)133 rnp_ctx_init_ffi(rnp_ctx_t &ctx, rnp_ffi_t ffi)
134 {
135     ctx.ctx = &ffi->context;
136     ctx.ealg = DEFAULT_PGP_SYMM_ALG;
137 }
138 
139 static const id_str_pair sig_type_map[] = {{PGP_SIG_BINARY, "binary"},
140                                            {PGP_SIG_TEXT, "text"},
141                                            {PGP_SIG_STANDALONE, "standalone"},
142                                            {PGP_CERT_GENERIC, "certification (generic)"},
143                                            {PGP_CERT_PERSONA, "certification (persona)"},
144                                            {PGP_CERT_CASUAL, "certification (casual)"},
145                                            {PGP_CERT_POSITIVE, "certification (positive)"},
146                                            {PGP_SIG_SUBKEY, "subkey binding"},
147                                            {PGP_SIG_PRIMARY, "primary key binding"},
148                                            {PGP_SIG_DIRECT, "direct"},
149                                            {PGP_SIG_REV_KEY, "key revocation"},
150                                            {PGP_SIG_REV_SUBKEY, "subkey revocation"},
151                                            {PGP_SIG_REV_CERT, "certification revocation"},
152                                            {PGP_SIG_TIMESTAMP, "timestamp"},
153                                            {PGP_SIG_3RD_PARTY, "third-party"},
154                                            {0, NULL}};
155 
156 static const id_str_pair pubkey_alg_map[] = {
157   {PGP_PKA_RSA, RNP_ALGNAME_RSA},
158   {PGP_PKA_RSA_ENCRYPT_ONLY, RNP_ALGNAME_RSA},
159   {PGP_PKA_RSA_SIGN_ONLY, RNP_ALGNAME_RSA},
160   {PGP_PKA_ELGAMAL, RNP_ALGNAME_ELGAMAL},
161   {PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN, RNP_ALGNAME_ELGAMAL},
162   {PGP_PKA_DSA, RNP_ALGNAME_DSA},
163   {PGP_PKA_ECDH, RNP_ALGNAME_ECDH},
164   {PGP_PKA_ECDSA, RNP_ALGNAME_ECDSA},
165   {PGP_PKA_EDDSA, RNP_ALGNAME_EDDSA},
166   {PGP_PKA_SM2, RNP_ALGNAME_SM2},
167   {0, NULL}};
168 
169 static const id_str_pair symm_alg_map[] = {{PGP_SA_IDEA, RNP_ALGNAME_IDEA},
170                                            {PGP_SA_TRIPLEDES, RNP_ALGNAME_TRIPLEDES},
171                                            {PGP_SA_CAST5, RNP_ALGNAME_CAST5},
172                                            {PGP_SA_BLOWFISH, RNP_ALGNAME_BLOWFISH},
173                                            {PGP_SA_AES_128, RNP_ALGNAME_AES_128},
174                                            {PGP_SA_AES_192, RNP_ALGNAME_AES_192},
175                                            {PGP_SA_AES_256, RNP_ALGNAME_AES_256},
176                                            {PGP_SA_TWOFISH, RNP_ALGNAME_TWOFISH},
177                                            {PGP_SA_CAMELLIA_128, RNP_ALGNAME_CAMELLIA_128},
178                                            {PGP_SA_CAMELLIA_192, RNP_ALGNAME_CAMELLIA_192},
179                                            {PGP_SA_CAMELLIA_256, RNP_ALGNAME_CAMELLIA_256},
180                                            {PGP_SA_SM4, RNP_ALGNAME_SM4},
181                                            {0, NULL}};
182 
183 static const id_str_pair aead_alg_map[] = {
184   {PGP_AEAD_NONE, "None"}, {PGP_AEAD_EAX, "EAX"}, {PGP_AEAD_OCB, "OCB"}, {0, NULL}};
185 
186 static const id_str_pair cipher_mode_map[] = {{PGP_CIPHER_MODE_CFB, "CFB"},
187                                               {PGP_CIPHER_MODE_CBC, "CBC"},
188                                               {PGP_CIPHER_MODE_OCB, "OCB"},
189                                               {0, NULL}};
190 
191 static const id_str_pair compress_alg_map[] = {{PGP_C_NONE, "Uncompressed"},
192                                                {PGP_C_ZIP, "ZIP"},
193                                                {PGP_C_ZLIB, "ZLIB"},
194                                                {PGP_C_BZIP2, "BZip2"},
195                                                {0, NULL}};
196 
197 static const id_str_pair hash_alg_map[] = {{PGP_HASH_MD5, RNP_ALGNAME_MD5},
198                                            {PGP_HASH_SHA1, RNP_ALGNAME_SHA1},
199                                            {PGP_HASH_RIPEMD, RNP_ALGNAME_RIPEMD160},
200                                            {PGP_HASH_SHA256, RNP_ALGNAME_SHA256},
201                                            {PGP_HASH_SHA384, RNP_ALGNAME_SHA384},
202                                            {PGP_HASH_SHA512, RNP_ALGNAME_SHA512},
203                                            {PGP_HASH_SHA224, RNP_ALGNAME_SHA224},
204                                            {PGP_HASH_SHA3_256, RNP_ALGNAME_SHA3_256},
205                                            {PGP_HASH_SHA3_512, RNP_ALGNAME_SHA3_512},
206                                            {PGP_HASH_SM3, RNP_ALGNAME_SM3},
207                                            {0, NULL}};
208 
209 static const id_str_pair s2k_type_map[] = {
210   {PGP_S2KS_SIMPLE, "Simple"},
211   {PGP_S2KS_SALTED, "Salted"},
212   {PGP_S2KS_ITERATED_AND_SALTED, "Iterated and salted"},
213   {0, NULL}};
214 
215 static const id_str_pair key_usage_map[] = {
216   {PGP_KF_SIGN, "sign"},
217   {PGP_KF_CERTIFY, "certify"},
218   {PGP_KF_ENCRYPT, "encrypt"},
219   {PGP_KF_AUTH, "authenticate"},
220   {0, NULL},
221 };
222 
223 static const id_str_pair key_flags_map[] = {
224   {PGP_KF_SPLIT, "split"},
225   {PGP_KF_SHARED, "shared"},
226   {0, NULL},
227 };
228 
229 static const id_str_pair identifier_type_map[] = {{PGP_KEY_SEARCH_USERID, "userid"},
230                                                   {PGP_KEY_SEARCH_KEYID, "keyid"},
231                                                   {PGP_KEY_SEARCH_FINGERPRINT, "fingerprint"},
232                                                   {PGP_KEY_SEARCH_GRIP, "grip"},
233                                                   {0, NULL}};
234 
235 static const id_str_pair key_server_prefs_map[] = {{PGP_KEY_SERVER_NO_MODIFY, "no-modify"},
236                                                    {0, NULL}};
237 
238 static const id_str_pair armor_type_map[] = {{PGP_ARMORED_MESSAGE, "message"},
239                                              {PGP_ARMORED_PUBLIC_KEY, "public key"},
240                                              {PGP_ARMORED_SECRET_KEY, "secret key"},
241                                              {PGP_ARMORED_SIGNATURE, "signature"},
242                                              {PGP_ARMORED_CLEARTEXT, "cleartext"},
243                                              {0, NULL}};
244 
245 static const id_str_pair key_import_status_map[] = {
246   {PGP_KEY_IMPORT_STATUS_UNKNOWN, "unknown"},
247   {PGP_KEY_IMPORT_STATUS_UNCHANGED, "unchanged"},
248   {PGP_KEY_IMPORT_STATUS_UPDATED, "updated"},
249   {PGP_KEY_IMPORT_STATUS_NEW, "new"},
250   {0, NULL}};
251 
252 static const id_str_pair sig_import_status_map[] = {
253   {PGP_SIG_IMPORT_STATUS_UNKNOWN, "unknown"},
254   {PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY, "unknown key"},
255   {PGP_SIG_IMPORT_STATUS_UNCHANGED, "unchanged"},
256   {PGP_SIG_IMPORT_STATUS_NEW, "new"},
257   {0, NULL}};
258 
259 static const id_str_pair revocation_code_map[] = {
260   {PGP_REVOCATION_NO_REASON, "no"},
261   {PGP_REVOCATION_SUPERSEDED, "superseded"},
262   {PGP_REVOCATION_COMPROMISED, "compromised"},
263   {PGP_REVOCATION_RETIRED, "retired"},
264   {PGP_REVOCATION_NO_LONGER_VALID, "no longer valid"},
265   {0, NULL}};
266 
267 static bool
curve_str_to_type(const char * str,pgp_curve_t * value)268 curve_str_to_type(const char *str, pgp_curve_t *value)
269 {
270     *value = find_curve_by_name(str);
271     return curve_supported(*value);
272 }
273 
274 static bool
curve_type_to_str(pgp_curve_t type,const char ** str)275 curve_type_to_str(pgp_curve_t type, const char **str)
276 {
277     const ec_curve_desc_t *desc = get_curve_desc(type);
278     if (!desc) {
279         return false;
280     }
281     *str = desc->pgp_name;
282     return true;
283 }
284 
285 static bool
str_to_cipher(const char * str,pgp_symm_alg_t * cipher)286 str_to_cipher(const char *str, pgp_symm_alg_t *cipher)
287 {
288     auto alg =
289       static_cast<pgp_symm_alg_t>(id_str_pair::lookup(symm_alg_map, str, PGP_SA_UNKNOWN));
290     if (alg == PGP_SA_UNKNOWN) {
291         return false;
292     }
293 #if !defined(ENABLE_SM2)
294     if (alg == PGP_SA_SM4) {
295         return false;
296     }
297 #endif
298 #if !defined(ENABLE_TWOFISH)
299     if (alg == PGP_SA_TWOFISH) {
300         return false;
301     }
302 #endif
303     *cipher = alg;
304     return true;
305 }
306 
307 static bool
str_to_hash_alg(const char * str,pgp_hash_alg_t * hash_alg)308 str_to_hash_alg(const char *str, pgp_hash_alg_t *hash_alg)
309 {
310     auto alg =
311       static_cast<pgp_hash_alg_t>(id_str_pair::lookup(hash_alg_map, str, PGP_HASH_UNKNOWN));
312     if (alg == PGP_HASH_UNKNOWN) {
313         return false;
314     }
315 #if !defined(ENABLE_SM2)
316     if (alg == PGP_HASH_SM3) {
317         return false;
318     }
319 #endif
320     *hash_alg = alg;
321     return true;
322 }
323 
324 static bool
str_to_aead_alg(const char * str,pgp_aead_alg_t * aead_alg)325 str_to_aead_alg(const char *str, pgp_aead_alg_t *aead_alg)
326 {
327     pgp_aead_alg_t alg =
328       static_cast<pgp_aead_alg_t>(id_str_pair::lookup(aead_alg_map, str, PGP_AEAD_UNKNOWN));
329     if (alg == PGP_AEAD_UNKNOWN) {
330         return false;
331     }
332 #if !defined(ENABLE_AEAD)
333     if (alg != PGP_AEAD_NONE) {
334         return false;
335     }
336 #endif
337     *aead_alg = alg;
338     return true;
339 }
340 
341 static bool
str_to_compression_alg(const char * str,pgp_compression_type_t * zalg)342 str_to_compression_alg(const char *str, pgp_compression_type_t *zalg)
343 {
344     pgp_compression_type_t alg = static_cast<pgp_compression_type_t>(
345       id_str_pair::lookup(compress_alg_map, str, PGP_C_UNKNOWN));
346     if (alg == PGP_C_UNKNOWN) {
347         return false;
348     }
349     *zalg = alg;
350     return true;
351 }
352 
353 static bool
str_to_revocation_type(const char * str,pgp_revocation_type_t * code)354 str_to_revocation_type(const char *str, pgp_revocation_type_t *code)
355 {
356     pgp_revocation_type_t rev = static_cast<pgp_revocation_type_t>(
357       id_str_pair::lookup(revocation_code_map, str, PGP_REVOCATION_NO_REASON));
358     if ((rev == PGP_REVOCATION_NO_REASON) && !rnp::str_case_eq(str, "no")) {
359         return false;
360     }
361     *code = rev;
362     return true;
363 }
364 
365 static bool
str_to_cipher_mode(const char * str,pgp_cipher_mode_t * mode)366 str_to_cipher_mode(const char *str, pgp_cipher_mode_t *mode)
367 {
368     pgp_cipher_mode_t c_mode = static_cast<pgp_cipher_mode_t>(
369       id_str_pair::lookup(cipher_mode_map, str, PGP_CIPHER_MODE_NONE));
370     if (c_mode == PGP_CIPHER_MODE_NONE) {
371         return false;
372     }
373 
374     *mode = c_mode;
375     return true;
376 }
377 
378 static bool
str_to_pubkey_alg(const char * str,pgp_pubkey_alg_t * pub_alg)379 str_to_pubkey_alg(const char *str, pgp_pubkey_alg_t *pub_alg)
380 {
381     pgp_pubkey_alg_t alg =
382       static_cast<pgp_pubkey_alg_t>(id_str_pair::lookup(pubkey_alg_map, str, PGP_PKA_NOTHING));
383     if (alg == PGP_PKA_NOTHING) {
384         return false;
385     }
386 #if !defined(ENABLE_SM2)
387     if (alg == PGP_PKA_SM2) {
388         return false;
389     }
390 #endif
391     *pub_alg = alg;
392     return true;
393 }
394 
395 static bool
str_to_key_flag(const char * str,uint8_t * flag)396 str_to_key_flag(const char *str, uint8_t *flag)
397 {
398     uint8_t _flag = id_str_pair::lookup(key_usage_map, str);
399     if (!_flag) {
400         return false;
401     }
402     *flag = _flag;
403     return true;
404 }
405 
406 static bool
parse_ks_format(pgp_key_store_format_t * key_store_format,const char * format)407 parse_ks_format(pgp_key_store_format_t *key_store_format, const char *format)
408 {
409     if (!strcmp(format, RNP_KEYSTORE_GPG)) {
410         *key_store_format = PGP_KEY_STORE_GPG;
411     } else if (!strcmp(format, RNP_KEYSTORE_KBX)) {
412         *key_store_format = PGP_KEY_STORE_KBX;
413     } else if (!strcmp(format, RNP_KEYSTORE_G10)) {
414         *key_store_format = PGP_KEY_STORE_G10;
415     } else {
416         return false;
417     }
418     return true;
419 }
420 
421 static rnp_result_t
hex_encode_value(const uint8_t * value,size_t len,char ** res,rnp::hex_format_t format=rnp::HEX_UPPERCASE)422 hex_encode_value(const uint8_t *   value,
423                  size_t            len,
424                  char **           res,
425                  rnp::hex_format_t format = rnp::HEX_UPPERCASE)
426 {
427     size_t hex_len = len * 2 + 1;
428     *res = (char *) malloc(hex_len);
429     if (!*res) {
430         return RNP_ERROR_OUT_OF_MEMORY;
431     }
432     if (!rnp::hex_encode(value, len, *res, hex_len, format)) {
433         free(*res);
434         *res = NULL;
435         return RNP_ERROR_GENERIC;
436     }
437     return RNP_SUCCESS;
438 }
439 
440 static rnp_result_t
get_map_value(const id_str_pair * map,int val,char ** res)441 get_map_value(const id_str_pair *map, int val, char **res)
442 {
443     const char *str = id_str_pair::lookup(map, val, NULL);
444     if (!str) {
445         return RNP_ERROR_BAD_PARAMETERS;
446     }
447     char *strcp = strdup(str);
448     if (!strcp) {
449         return RNP_ERROR_OUT_OF_MEMORY;
450     }
451     *res = strcp;
452     return RNP_SUCCESS;
453 }
454 
455 static rnp_result_t
ret_str_value(const char * str,char ** res)456 ret_str_value(const char *str, char **res)
457 {
458     if (!str) {
459         return RNP_ERROR_BAD_PARAMETERS;
460     }
461     char *strcp = strdup(str);
462     if (!strcp) {
463         return RNP_ERROR_OUT_OF_MEMORY;
464     }
465     *res = strcp;
466     return RNP_SUCCESS;
467 }
468 
469 static uint32_t
ffi_exception(FILE * fp,const char * func,const char * msg,uint32_t ret=RNP_ERROR_GENERIC)470 ffi_exception(FILE *fp, const char *func, const char *msg, uint32_t ret = RNP_ERROR_GENERIC)
471 {
472     if (rnp_log_switch()) {
473         fprintf(
474           fp, "[%s()] Error 0x%08X (%s): %s\n", func, ret, rnp_result_to_string(ret), msg);
475     }
476     return ret;
477 }
478 
479 #define FFI_GUARD_FP(fp)                                                            \
480     catch (rnp::rnp_exception & e)                                                  \
481     {                                                                               \
482         return ffi_exception((fp), __func__, e.what(), e.code());                   \
483     }                                                                               \
484     catch (std::bad_alloc &)                                                        \
485     {                                                                               \
486         return ffi_exception((fp), __func__, "bad_alloc", RNP_ERROR_OUT_OF_MEMORY); \
487     }                                                                               \
488     catch (std::exception & e)                                                      \
489     {                                                                               \
490         return ffi_exception((fp), __func__, e.what());                             \
491     }                                                                               \
492     catch (...)                                                                     \
493     {                                                                               \
494         return ffi_exception((fp), __func__, "unknown exception");                  \
495     }
496 
497 #define FFI_GUARD FFI_GUARD_FP((stderr))
498 
rnp_ffi_st(pgp_key_store_format_t pub_fmt,pgp_key_store_format_t sec_fmt)499 rnp_ffi_st::rnp_ffi_st(pgp_key_store_format_t pub_fmt, pgp_key_store_format_t sec_fmt)
500 {
501     errs = stderr;
502     pubring = new rnp_key_store_t(pub_fmt, "", context);
503     secring = new rnp_key_store_t(sec_fmt, "", context);
504     getkeycb = NULL;
505     getkeycb_ctx = NULL;
506     getpasscb = NULL;
507     getpasscb_ctx = NULL;
508     key_provider.callback = ffi_key_provider;
509     key_provider.userdata = this;
510     pass_provider.callback = rnp_password_cb_bounce;
511     pass_provider.userdata = this;
512 }
513 
514 rnp::RNG &
rng()515 rnp_ffi_st::rng() noexcept
516 {
517     return context.rng;
518 }
519 
520 rnp::SecurityProfile &
profile()521 rnp_ffi_st::profile() noexcept
522 {
523     return context.profile;
524 }
525 
526 rnp_result_t
rnp_ffi_create(rnp_ffi_t * ffi,const char * pub_format,const char * sec_format)527 rnp_ffi_create(rnp_ffi_t *ffi, const char *pub_format, const char *sec_format)
528 try {
529     // checks
530     if (!ffi || !pub_format || !sec_format) {
531         return RNP_ERROR_NULL_POINTER;
532     }
533 
534     pgp_key_store_format_t pub_ks_format = PGP_KEY_STORE_UNKNOWN;
535     pgp_key_store_format_t sec_ks_format = PGP_KEY_STORE_UNKNOWN;
536     if (!parse_ks_format(&pub_ks_format, pub_format) ||
537         !parse_ks_format(&sec_ks_format, sec_format)) {
538         return RNP_ERROR_BAD_PARAMETERS;
539     }
540 
541     struct rnp_ffi_st *ob = new rnp_ffi_st(pub_ks_format, sec_ks_format);
542     *ffi = ob;
543     return RNP_SUCCESS;
544 }
545 FFI_GUARD
546 
547 static bool
is_std_file(FILE * fp)548 is_std_file(FILE *fp)
549 {
550     return fp == stdout || fp == stderr;
551 }
552 
553 static void
close_io_file(FILE ** fp)554 close_io_file(FILE **fp)
555 {
556     if (*fp && !is_std_file(*fp)) {
557         fclose(*fp);
558     }
559     *fp = NULL;
560 }
561 
~rnp_ffi_st()562 rnp_ffi_st::~rnp_ffi_st()
563 {
564     close_io_file(&errs);
565     delete pubring;
566     delete secring;
567 }
568 
569 rnp_result_t
rnp_ffi_destroy(rnp_ffi_t ffi)570 rnp_ffi_destroy(rnp_ffi_t ffi)
571 try {
572     if (ffi) {
573         delete ffi;
574     }
575     return RNP_SUCCESS;
576 }
577 FFI_GUARD
578 
579 rnp_result_t
rnp_ffi_set_log_fd(rnp_ffi_t ffi,int fd)580 rnp_ffi_set_log_fd(rnp_ffi_t ffi, int fd)
581 try {
582     // checks
583     if (!ffi) {
584         return RNP_ERROR_NULL_POINTER;
585     }
586 
587     // open
588     FILE *errs = fdopen(fd, "a");
589     if (!errs) {
590         return RNP_ERROR_ACCESS;
591     }
592     // close previous streams and replace them
593     close_io_file(&ffi->errs);
594     ffi->errs = errs;
595     return RNP_SUCCESS;
596 }
597 FFI_GUARD
598 
599 rnp_result_t
rnp_ffi_set_key_provider(rnp_ffi_t ffi,rnp_get_key_cb getkeycb,void * getkeycb_ctx)600 rnp_ffi_set_key_provider(rnp_ffi_t ffi, rnp_get_key_cb getkeycb, void *getkeycb_ctx)
601 try {
602     if (!ffi) {
603         return RNP_ERROR_NULL_POINTER;
604     }
605     ffi->getkeycb = getkeycb;
606     ffi->getkeycb_ctx = getkeycb_ctx;
607     return RNP_SUCCESS;
608 }
609 FFI_GUARD
610 
611 rnp_result_t
rnp_ffi_set_pass_provider(rnp_ffi_t ffi,rnp_password_cb getpasscb,void * getpasscb_ctx)612 rnp_ffi_set_pass_provider(rnp_ffi_t ffi, rnp_password_cb getpasscb, void *getpasscb_ctx)
613 try {
614     if (!ffi) {
615         return RNP_ERROR_NULL_POINTER;
616     }
617     ffi->getpasscb = getpasscb;
618     ffi->getpasscb_ctx = getpasscb_ctx;
619     return RNP_SUCCESS;
620 }
621 FFI_GUARD
622 
623 static const char *
operation_description(uint8_t op)624 operation_description(uint8_t op)
625 {
626     switch (op) {
627     case PGP_OP_ADD_SUBKEY:
628         return "add subkey";
629     case PGP_OP_ADD_USERID:
630         return "add userid";
631     case PGP_OP_SIGN:
632         return "sign";
633     case PGP_OP_DECRYPT:
634         return "decrypt";
635     case PGP_OP_UNLOCK:
636         return "unlock";
637     case PGP_OP_PROTECT:
638         return "protect";
639     case PGP_OP_UNPROTECT:
640         return "unprotect";
641     case PGP_OP_DECRYPT_SYM:
642         return "decrypt (symmetric)";
643     case PGP_OP_ENCRYPT_SYM:
644         return "encrypt (symmetric)";
645     default:
646         return "unknown";
647     }
648 }
649 
650 static bool
rnp_password_cb_bounce(const pgp_password_ctx_t * ctx,char * password,size_t password_size,void * userdata_void)651 rnp_password_cb_bounce(const pgp_password_ctx_t *ctx,
652                        char *                    password,
653                        size_t                    password_size,
654                        void *                    userdata_void)
655 {
656     rnp_ffi_t ffi = (rnp_ffi_t) userdata_void;
657 
658     if (!ffi || !ffi->getpasscb) {
659         return false;
660     }
661 
662     struct rnp_key_handle_st key = {};
663     key.ffi = ffi;
664     key.sec = (pgp_key_t *) ctx->key;
665     return ffi->getpasscb(ffi,
666                           ffi->getpasscb_ctx,
667                           ctx->key ? &key : NULL,
668                           operation_description(ctx->op),
669                           password,
670                           password_size);
671 }
672 
673 const char *
rnp_result_to_string(rnp_result_t result)674 rnp_result_to_string(rnp_result_t result)
675 {
676     switch (result) {
677     case RNP_SUCCESS:
678         return "Success";
679 
680     case RNP_ERROR_GENERIC:
681         return "Unknown error";
682     case RNP_ERROR_BAD_FORMAT:
683         return "Bad format";
684     case RNP_ERROR_BAD_PARAMETERS:
685         return "Bad parameters";
686     case RNP_ERROR_NOT_IMPLEMENTED:
687         return "Not implemented";
688     case RNP_ERROR_NOT_SUPPORTED:
689         return "Not supported";
690     case RNP_ERROR_OUT_OF_MEMORY:
691         return "Out of memory";
692     case RNP_ERROR_SHORT_BUFFER:
693         return "Buffer too short";
694     case RNP_ERROR_NULL_POINTER:
695         return "Null pointer";
696 
697     case RNP_ERROR_ACCESS:
698         return "Error accessing file";
699     case RNP_ERROR_READ:
700         return "Error reading file";
701     case RNP_ERROR_WRITE:
702         return "Error writing file";
703 
704     case RNP_ERROR_BAD_STATE:
705         return "Bad state";
706     case RNP_ERROR_MAC_INVALID:
707         return "Invalid MAC";
708     case RNP_ERROR_SIGNATURE_INVALID:
709         return "Invalid signature";
710     case RNP_ERROR_KEY_GENERATION:
711         return "Error during key generation";
712     case RNP_ERROR_BAD_PASSWORD:
713         return "Bad password";
714     case RNP_ERROR_KEY_NOT_FOUND:
715         return "Key not found";
716     case RNP_ERROR_NO_SUITABLE_KEY:
717         return "No suitable key";
718     case RNP_ERROR_DECRYPT_FAILED:
719         return "Decryption failed";
720     case RNP_ERROR_NO_SIGNATURES_FOUND:
721         return "No signatures found cannot verify";
722 
723     case RNP_ERROR_NOT_ENOUGH_DATA:
724         return "Not enough data";
725     case RNP_ERROR_UNKNOWN_TAG:
726         return "Unknown tag";
727     case RNP_ERROR_PACKET_NOT_CONSUMED:
728         return "Packet not consumed";
729     case RNP_ERROR_NO_USERID:
730         return "No userid";
731     case RNP_ERROR_EOF:
732         return "EOF detected";
733     }
734 
735     return "Unknown error";
736 }
737 
738 const char *
rnp_version_string()739 rnp_version_string()
740 {
741     return RNP_VERSION_STRING;
742 }
743 
744 const char *
rnp_version_string_full()745 rnp_version_string_full()
746 {
747     return RNP_VERSION_STRING_FULL;
748 }
749 
750 uint32_t
rnp_version()751 rnp_version()
752 {
753     return RNP_VERSION_CODE;
754 }
755 
756 uint32_t
rnp_version_for(uint32_t major,uint32_t minor,uint32_t patch)757 rnp_version_for(uint32_t major, uint32_t minor, uint32_t patch)
758 {
759     if (major > RNP_VERSION_COMPONENT_MASK || minor > RNP_VERSION_COMPONENT_MASK ||
760         patch > RNP_VERSION_COMPONENT_MASK) {
761         RNP_LOG("invalid version, out of range: %d.%d.%d", major, minor, patch);
762         return 0;
763     }
764     return RNP_VERSION_CODE_FOR(major, minor, patch);
765 }
766 
767 uint32_t
rnp_version_major(uint32_t version)768 rnp_version_major(uint32_t version)
769 {
770     return (version >> RNP_VERSION_MAJOR_SHIFT) & RNP_VERSION_COMPONENT_MASK;
771 }
772 
773 uint32_t
rnp_version_minor(uint32_t version)774 rnp_version_minor(uint32_t version)
775 {
776     return (version >> RNP_VERSION_MINOR_SHIFT) & RNP_VERSION_COMPONENT_MASK;
777 }
778 
779 uint32_t
rnp_version_patch(uint32_t version)780 rnp_version_patch(uint32_t version)
781 {
782     return (version >> RNP_VERSION_PATCH_SHIFT) & RNP_VERSION_COMPONENT_MASK;
783 }
784 
785 uint64_t
rnp_version_commit_timestamp()786 rnp_version_commit_timestamp()
787 {
788     return RNP_VERSION_COMMIT_TIMESTAMP;
789 }
790 
791 #ifndef RNP_NO_DEPRECATED
792 rnp_result_t
rnp_enable_debug(const char * file)793 rnp_enable_debug(const char *file)
794 try {
795     return RNP_SUCCESS;
796 }
797 FFI_GUARD
798 #endif
799 
800 #ifndef RNP_NO_DEPRECATED
801 rnp_result_t
rnp_disable_debug()802 rnp_disable_debug()
803 try {
804     return RNP_SUCCESS;
805 }
806 FFI_GUARD
807 #endif
808 
809 rnp_result_t
rnp_get_default_homedir(char ** homedir)810 rnp_get_default_homedir(char **homedir)
811 try {
812     // checks
813     if (!homedir) {
814         return RNP_ERROR_NULL_POINTER;
815     }
816 
817     // get the users home dir
818     char *home = getenv("HOME");
819     if (!home) {
820         return RNP_ERROR_NOT_SUPPORTED;
821     }
822     if (!rnp_compose_path_ex(homedir, NULL, home, ".rnp", NULL)) {
823         return RNP_ERROR_OUT_OF_MEMORY;
824     }
825     return RNP_SUCCESS;
826 }
827 FFI_GUARD
828 
829 rnp_result_t
rnp_detect_homedir_info(const char * homedir,char ** pub_format,char ** pub_path,char ** sec_format,char ** sec_path)830 rnp_detect_homedir_info(
831   const char *homedir, char **pub_format, char **pub_path, char **sec_format, char **sec_path)
832 try {
833     rnp_result_t ret = RNP_ERROR_GENERIC;
834     char *       path = NULL;
835     size_t       path_size = 0;
836 
837     // checks
838     if (!homedir || !pub_format || !pub_path || !sec_format || !sec_path) {
839         return RNP_ERROR_NULL_POINTER;
840     }
841 
842     // we only support the common cases of GPG+GPG or GPG+G10, we don't
843     // support unused combinations like KBX+KBX
844 
845     *pub_format = NULL;
846     *pub_path = NULL;
847     *sec_format = NULL;
848     *sec_path = NULL;
849 
850     const char *pub_format_guess = NULL;
851     const char *pub_path_guess = NULL;
852     const char *sec_format_guess = NULL;
853     const char *sec_path_guess = NULL;
854     // check for pubring.kbx file
855     if (!rnp_compose_path_ex(&path, &path_size, homedir, "pubring.kbx", NULL)) {
856         goto done;
857     }
858     if (rnp_file_exists(path)) {
859         // we have a pubring.kbx, now check for private-keys-v1.d dir
860         if (!rnp_compose_path_ex(&path, &path_size, homedir, "private-keys-v1.d", NULL)) {
861             goto done;
862         }
863         if (rnp_dir_exists(path)) {
864             pub_format_guess = "KBX";
865             pub_path_guess = "pubring.kbx";
866             sec_format_guess = "G10";
867             sec_path_guess = "private-keys-v1.d";
868         }
869     } else {
870         // check for pubring.gpg
871         if (!rnp_compose_path_ex(&path, &path_size, homedir, "pubring.gpg", NULL)) {
872             goto done;
873         }
874         if (rnp_file_exists(path)) {
875             // we have a pubring.gpg, now check for secring.gpg
876             if (!rnp_compose_path_ex(&path, &path_size, homedir, "secring.gpg", NULL)) {
877                 goto done;
878             }
879             if (rnp_file_exists(path)) {
880                 pub_format_guess = "GPG";
881                 pub_path_guess = "pubring.gpg";
882                 sec_format_guess = "GPG";
883                 sec_path_guess = "secring.gpg";
884             }
885         }
886     }
887 
888     // set our results
889     if (pub_format_guess) {
890         *pub_format = strdup(pub_format_guess);
891         *pub_path = rnp_compose_path(homedir, pub_path_guess, NULL);
892         if (!*pub_format || !*pub_path) {
893             ret = RNP_ERROR_OUT_OF_MEMORY;
894             goto done;
895         }
896     }
897     if (sec_format_guess) {
898         *sec_format = strdup(sec_format_guess);
899         *sec_path = rnp_compose_path(homedir, sec_path_guess, NULL);
900         if (!*sec_format || !*sec_path) {
901             ret = RNP_ERROR_OUT_OF_MEMORY;
902             goto done;
903         }
904     }
905     // we leave the *formats as NULL if we were not able to determine the format
906     // (but no error occurred)
907 
908     ret = RNP_SUCCESS;
909 done:
910     if (ret) {
911         free(*pub_format);
912         *pub_format = NULL;
913         free(*pub_path);
914         *pub_path = NULL;
915 
916         free(*sec_format);
917         *sec_format = NULL;
918         free(*sec_path);
919         *sec_path = NULL;
920     }
921     free(path);
922     return ret;
923 }
924 FFI_GUARD
925 
926 rnp_result_t
rnp_detect_key_format(const uint8_t buf[],size_t buf_len,char ** format)927 rnp_detect_key_format(const uint8_t buf[], size_t buf_len, char **format)
928 try {
929     rnp_result_t ret = RNP_ERROR_GENERIC;
930 
931     // checks
932     if (!buf || !format) {
933         return RNP_ERROR_NULL_POINTER;
934     }
935     if (!buf_len) {
936         return RNP_ERROR_SHORT_BUFFER;
937     }
938 
939     *format = NULL;
940     // ordered from most reliable detection to least
941     const char *guess = NULL;
942     if (buf_len >= 12 && memcmp(buf + 8, "KBXf", 4) == 0) {
943         // KBX has a magic KBXf marker
944         guess = "KBX";
945     } else if (buf_len >= 5 && memcmp(buf, "-----", 5) == 0) {
946         // likely armored GPG
947         guess = "GPG";
948     } else if (buf[0] == '(') {
949         // G10 is s-exprs and should start end end with parentheses
950         guess = "G10";
951     } else if (buf[0] & PGP_PTAG_ALWAYS_SET) {
952         // this is harder to reliably determine, but could likely be improved
953         guess = "GPG";
954     }
955     if (guess) {
956         *format = strdup(guess);
957         if (!*format) {
958             ret = RNP_ERROR_OUT_OF_MEMORY;
959             goto done;
960         }
961     }
962 
963     // success
964     ret = RNP_SUCCESS;
965 done:
966     return ret;
967 }
968 FFI_GUARD
969 
970 rnp_result_t
rnp_calculate_iterations(const char * hash,size_t msec,size_t * iterations)971 rnp_calculate_iterations(const char *hash, size_t msec, size_t *iterations)
972 try {
973     if (!hash || !iterations) {
974         return RNP_ERROR_NULL_POINTER;
975     }
976     pgp_hash_alg_t halg = PGP_HASH_UNKNOWN;
977     if (!str_to_hash_alg(hash, &halg)) {
978         return RNP_ERROR_BAD_PARAMETERS;
979     }
980 
981     *iterations = pgp_s2k_compute_iters(halg, msec, 0);
982     return RNP_SUCCESS;
983 }
984 FFI_GUARD
985 
986 rnp_result_t
rnp_supports_feature(const char * type,const char * name,bool * supported)987 rnp_supports_feature(const char *type, const char *name, bool *supported)
988 try {
989     if (!type || !name || !supported) {
990         return RNP_ERROR_NULL_POINTER;
991     }
992     if (rnp::str_case_eq(type, RNP_FEATURE_SYMM_ALG)) {
993         pgp_symm_alg_t alg = PGP_SA_UNKNOWN;
994         *supported = str_to_cipher(name, &alg);
995     } else if (rnp::str_case_eq(type, RNP_FEATURE_AEAD_ALG)) {
996         pgp_aead_alg_t alg = PGP_AEAD_UNKNOWN;
997         *supported = str_to_aead_alg(name, &alg);
998     } else if (rnp::str_case_eq(type, RNP_FEATURE_PROT_MODE)) {
999         // for now we support only CFB for key encryption
1000         *supported = rnp::str_case_eq(name, "CFB");
1001     } else if (rnp::str_case_eq(type, RNP_FEATURE_PK_ALG)) {
1002         pgp_pubkey_alg_t alg = PGP_PKA_NOTHING;
1003         *supported = str_to_pubkey_alg(name, &alg);
1004     } else if (rnp::str_case_eq(type, RNP_FEATURE_HASH_ALG)) {
1005         pgp_hash_alg_t alg = PGP_HASH_UNKNOWN;
1006         *supported = str_to_hash_alg(name, &alg);
1007     } else if (rnp::str_case_eq(type, RNP_FEATURE_COMP_ALG)) {
1008         pgp_compression_type_t alg = PGP_C_UNKNOWN;
1009         *supported = str_to_compression_alg(name, &alg);
1010     } else if (rnp::str_case_eq(type, RNP_FEATURE_CURVE)) {
1011         pgp_curve_t curve = PGP_CURVE_UNKNOWN;
1012         *supported = curve_str_to_type(name, &curve);
1013     } else {
1014         return RNP_ERROR_BAD_PARAMETERS;
1015     }
1016     return RNP_SUCCESS;
1017 }
1018 FFI_GUARD
1019 
1020 static rnp_result_t
json_array_add_id_str(json_object * arr,const id_str_pair * map,int from,int to)1021 json_array_add_id_str(json_object *arr, const id_str_pair *map, int from, int to)
1022 {
1023     while (map->str && (map->id < from)) {
1024         map++;
1025     }
1026     while (map->str && (map->id <= to)) {
1027         if (!array_add_element_json(arr, json_object_new_string(map->str))) {
1028             return RNP_ERROR_OUT_OF_MEMORY;
1029         }
1030         map++;
1031     }
1032     return RNP_SUCCESS;
1033 }
1034 
1035 rnp_result_t
rnp_supported_features(const char * type,char ** result)1036 rnp_supported_features(const char *type, char **result)
1037 try {
1038     if (!type || !result) {
1039         return RNP_ERROR_NULL_POINTER;
1040     }
1041 
1042     json_object *features = json_object_new_array();
1043     if (!features) {
1044         return RNP_ERROR_OUT_OF_MEMORY;
1045     }
1046 
1047     rnp_result_t ret = RNP_ERROR_BAD_PARAMETERS;
1048 
1049     if (rnp::str_case_eq(type, RNP_FEATURE_SYMM_ALG)) {
1050         ret = json_array_add_id_str(features, symm_alg_map, PGP_SA_IDEA, PGP_SA_AES_256);
1051 #if defined(ENABLE_TWOFISH)
1052         ret = json_array_add_id_str(features, symm_alg_map, PGP_SA_TWOFISH, PGP_SA_TWOFISH);
1053 #endif
1054         ret = json_array_add_id_str(
1055           features, symm_alg_map, PGP_SA_CAMELLIA_128, PGP_SA_CAMELLIA_256);
1056 #if defined(ENABLE_SM2)
1057         ret = json_array_add_id_str(features, symm_alg_map, PGP_SA_SM4, PGP_SA_SM4);
1058 #endif
1059     } else if (rnp::str_case_eq(type, RNP_FEATURE_AEAD_ALG)) {
1060 #if defined(ENABLE_AEAD)
1061         ret = json_array_add_id_str(features, aead_alg_map, PGP_AEAD_NONE, PGP_AEAD_OCB);
1062 #else
1063         ret = json_array_add_id_str(features, aead_alg_map, PGP_AEAD_NONE, PGP_AEAD_NONE);
1064 #endif
1065     } else if (rnp::str_case_eq(type, RNP_FEATURE_PROT_MODE)) {
1066         ret = json_array_add_id_str(
1067           features, cipher_mode_map, PGP_CIPHER_MODE_CFB, PGP_CIPHER_MODE_CFB);
1068     } else if (rnp::str_case_eq(type, RNP_FEATURE_PK_ALG)) {
1069         // workaround to avoid duplicates, maybe there is a better solution
1070         (void) json_array_add_id_str(features, pubkey_alg_map, PGP_PKA_RSA, PGP_PKA_RSA);
1071         ret = json_array_add_id_str(features, pubkey_alg_map, PGP_PKA_DSA, PGP_PKA_EDDSA);
1072 #if defined(ENABLE_SM2)
1073         ret = json_array_add_id_str(features, pubkey_alg_map, PGP_PKA_SM2, PGP_PKA_SM2);
1074 #endif
1075     } else if (rnp::str_case_eq(type, RNP_FEATURE_HASH_ALG)) {
1076         ret = json_array_add_id_str(features, hash_alg_map, PGP_HASH_MD5, PGP_HASH_SHA3_512);
1077 #if defined(ENABLE_SM2)
1078         ret = json_array_add_id_str(features, hash_alg_map, PGP_HASH_SM3, PGP_HASH_SM3);
1079 #endif
1080     } else if (rnp::str_case_eq(type, RNP_FEATURE_COMP_ALG)) {
1081         ret = json_array_add_id_str(features, compress_alg_map, PGP_C_NONE, PGP_C_BZIP2);
1082     } else if (rnp::str_case_eq(type, RNP_FEATURE_CURVE)) {
1083         for (pgp_curve_t curve = PGP_CURVE_NIST_P_256; curve < PGP_CURVE_MAX;
1084              curve = (pgp_curve_t)(curve + 1)) {
1085             const ec_curve_desc_t *desc = get_curve_desc(curve);
1086             if (!desc) {
1087                 ret = RNP_ERROR_BAD_STATE;
1088                 goto done;
1089             }
1090             if (!desc->supported) {
1091                 continue;
1092             }
1093             if (!array_add_element_json(features, json_object_new_string(desc->pgp_name))) {
1094                 ret = RNP_ERROR_OUT_OF_MEMORY;
1095                 goto done;
1096             }
1097         }
1098         ret = RNP_SUCCESS;
1099     }
1100 
1101     if (ret) {
1102         goto done;
1103     }
1104 
1105     *result = (char *) json_object_to_json_string_ext(features, JSON_C_TO_STRING_PRETTY);
1106     if (!*result) {
1107         ret = RNP_ERROR_BAD_STATE;
1108         goto done;
1109     }
1110     *result = strdup(*result);
1111     if (!*result) {
1112         ret = RNP_ERROR_OUT_OF_MEMORY;
1113     }
1114 done:
1115     json_object_put(features);
1116     return ret;
1117 }
1118 FFI_GUARD
1119 
1120 static bool
get_feature_sec_value(rnp_ffi_t ffi,const char * stype,const char * sname,rnp::FeatureType & type,int & value)1121 get_feature_sec_value(
1122   rnp_ffi_t ffi, const char *stype, const char *sname, rnp::FeatureType &type, int &value)
1123 {
1124     /* check type */
1125     if (!rnp::str_case_eq(stype, RNP_FEATURE_HASH_ALG)) {
1126         FFI_LOG(ffi, "Unsupported feature type: %s", stype);
1127         return false;
1128     }
1129     type = rnp::FeatureType::Hash;
1130     /* check feature name */
1131     pgp_hash_alg_t alg = PGP_HASH_UNKNOWN;
1132     if (sname && !str_to_hash_alg(sname, &alg)) {
1133         FFI_LOG(ffi, "Unknown hash algorithm: %s", sname);
1134         return false;
1135     }
1136     value = alg;
1137     return true;
1138 }
1139 
1140 static bool
get_feature_sec_level(rnp_ffi_t ffi,uint32_t flevel,rnp::SecurityLevel & level)1141 get_feature_sec_level(rnp_ffi_t ffi, uint32_t flevel, rnp::SecurityLevel &level)
1142 {
1143     switch (flevel) {
1144     case RNP_SECURITY_PROHIBITED:
1145         level = rnp::SecurityLevel::Disabled;
1146         break;
1147     case RNP_SECURITY_INSECURE:
1148         level = rnp::SecurityLevel::Insecure;
1149         break;
1150     case RNP_SECURITY_DEFAULT:
1151         level = rnp::SecurityLevel::Default;
1152         break;
1153     default:
1154         FFI_LOG(ffi, "Invalid security level : %" PRIu32, flevel);
1155         return false;
1156     }
1157     return true;
1158 }
1159 
1160 rnp_result_t
rnp_add_security_rule(rnp_ffi_t ffi,const char * type,const char * name,uint32_t flags,uint64_t from,uint32_t level)1161 rnp_add_security_rule(rnp_ffi_t   ffi,
1162                       const char *type,
1163                       const char *name,
1164                       uint32_t    flags,
1165                       uint64_t    from,
1166                       uint32_t    level)
1167 try {
1168     if (!ffi || !type || !name) {
1169         return RNP_ERROR_NULL_POINTER;
1170     }
1171     /* convert values */
1172     rnp::FeatureType   ftype;
1173     int                fvalue;
1174     rnp::SecurityLevel sec_level;
1175     if (!get_feature_sec_value(ffi, type, name, ftype, fvalue) ||
1176         !get_feature_sec_level(ffi, level, sec_level)) {
1177         return RNP_ERROR_BAD_PARAMETERS;
1178     }
1179     /* check flags */
1180     bool rule_override = flags & RNP_SECURITY_OVERRIDE;
1181     flags &= ~RNP_SECURITY_OVERRIDE;
1182     if (flags) {
1183         FFI_LOG(ffi, "Unknown flags: %" PRIu32, flags);
1184         return RNP_ERROR_BAD_PARAMETERS;
1185     }
1186     /* add rule */
1187     rnp::SecurityRule newrule(ftype, fvalue, sec_level, from);
1188     newrule.override = rule_override;
1189     ffi->profile().add_rule(newrule);
1190     return RNP_SUCCESS;
1191 }
1192 FFI_GUARD
1193 
1194 rnp_result_t
rnp_get_security_rule(rnp_ffi_t ffi,const char * type,const char * name,uint64_t time,uint32_t * flags,uint64_t * from,uint32_t * level)1195 rnp_get_security_rule(rnp_ffi_t   ffi,
1196                       const char *type,
1197                       const char *name,
1198                       uint64_t    time,
1199                       uint32_t *  flags,
1200                       uint64_t *  from,
1201                       uint32_t *  level)
1202 try {
1203     if (!ffi || !type || !name || !level) {
1204         return RNP_ERROR_NULL_POINTER;
1205     }
1206     /* convert values */
1207     rnp::FeatureType ftype;
1208     int              fvalue;
1209     if (!get_feature_sec_value(ffi, type, name, ftype, fvalue)) {
1210         return RNP_ERROR_BAD_PARAMETERS;
1211     }
1212     /* init default rule */
1213     rnp::SecurityRule rule(ftype, fvalue, ffi->profile().def_level());
1214     /* check whether rule exists */
1215     if (ffi->profile().has_rule(ftype, fvalue, time)) {
1216         rule = ffi->profile().get_rule(ftype, fvalue, time);
1217     }
1218     /* fill the results */
1219     if (flags) {
1220         *flags = rule.override ? RNP_SECURITY_OVERRIDE : 0;
1221     }
1222     if (from) {
1223         *from = rule.from;
1224     }
1225     switch (rule.level) {
1226     case rnp::SecurityLevel::Disabled:
1227         *level = RNP_SECURITY_PROHIBITED;
1228         break;
1229     case rnp::SecurityLevel::Insecure:
1230         *level = RNP_SECURITY_INSECURE;
1231         break;
1232     case rnp::SecurityLevel::Default:
1233         *level = RNP_SECURITY_DEFAULT;
1234         break;
1235     default:
1236         FFI_LOG(ffi, "Invalid security level.");
1237         return RNP_ERROR_BAD_STATE;
1238     }
1239     return RNP_SUCCESS;
1240 }
1241 FFI_GUARD
1242 
1243 rnp_result_t
rnp_remove_security_rule(rnp_ffi_t ffi,const char * type,const char * name,uint32_t level,uint32_t flags,uint64_t from,size_t * removed)1244 rnp_remove_security_rule(rnp_ffi_t   ffi,
1245                          const char *type,
1246                          const char *name,
1247                          uint32_t    level,
1248                          uint32_t    flags,
1249                          uint64_t    from,
1250                          size_t *    removed)
1251 try {
1252     if (!ffi) {
1253         return RNP_ERROR_NULL_POINTER;
1254     }
1255     /* check flags */
1256     bool remove_all = flags & RNP_SECURITY_REMOVE_ALL;
1257     flags &= ~RNP_SECURITY_REMOVE_ALL;
1258     bool rule_override = flags & RNP_SECURITY_OVERRIDE;
1259     flags &= ~RNP_SECURITY_OVERRIDE;
1260     if (flags) {
1261         FFI_LOG(ffi, "Unknown flags: %" PRIu32, flags);
1262         return RNP_ERROR_BAD_PARAMETERS;
1263     }
1264     /* remove all rules */
1265     size_t rules = ffi->profile().size();
1266     if (!type) {
1267         ffi->profile().clear_rules();
1268         goto success;
1269     }
1270     rnp::FeatureType   ftype;
1271     int                fvalue;
1272     rnp::SecurityLevel flevel;
1273     if (!get_feature_sec_value(ffi, type, name, ftype, fvalue) ||
1274         !get_feature_sec_level(ffi, level, flevel)) {
1275         return RNP_ERROR_BAD_PARAMETERS;
1276     }
1277     /* remove all rules for the specified type */
1278     if (!name) {
1279         ffi->profile().clear_rules(ftype);
1280         goto success;
1281     }
1282     if (remove_all) {
1283         /* remove all rules for the specified type and name */
1284         ffi->profile().clear_rules(ftype, fvalue);
1285     } else {
1286         /* remove specific rule */
1287         rnp::SecurityRule rule(ftype, fvalue, flevel, from);
1288         rule.override = rule_override;
1289         ffi->profile().del_rule(rule);
1290     }
1291 success:
1292     if (removed) {
1293         *removed = rules - ffi->profile().size();
1294     }
1295     return RNP_SUCCESS;
1296 }
1297 FFI_GUARD
1298 
1299 rnp_result_t
rnp_request_password(rnp_ffi_t ffi,rnp_key_handle_t key,const char * context,char ** password)1300 rnp_request_password(rnp_ffi_t ffi, rnp_key_handle_t key, const char *context, char **password)
1301 {
1302     if (!ffi || !password || !ffi->getpasscb) {
1303         return RNP_ERROR_NULL_POINTER;
1304     }
1305 
1306     rnp::secure_vector<char> pass(MAX_PASSWORD_LENGTH, '\0');
1307     bool                     req_res =
1308       ffi->getpasscb(ffi, ffi->getpasscb_ctx, key, context, pass.data(), pass.size());
1309     if (!req_res) {
1310         return RNP_ERROR_GENERIC;
1311     }
1312     size_t pass_len = strlen(pass.data()) + 1;
1313     *password = (char *) malloc(pass_len);
1314     if (!*password) {
1315         return RNP_ERROR_OUT_OF_MEMORY;
1316     }
1317     memcpy(*password, pass.data(), pass_len);
1318     return RNP_SUCCESS;
1319 }
1320 
1321 static rnp_result_t
load_keys_from_input(rnp_ffi_t ffi,rnp_input_t input,rnp_key_store_t * store)1322 load_keys_from_input(rnp_ffi_t ffi, rnp_input_t input, rnp_key_store_t *store)
1323 {
1324     rnp_result_t ret = RNP_ERROR_GENERIC;
1325 
1326     pgp_key_provider_t chained;
1327     chained.callback = rnp_key_provider_store;
1328     chained.userdata = store;
1329 
1330     const pgp_key_provider_t *key_providers[] = {&chained, &ffi->key_provider, NULL};
1331 
1332     const pgp_key_provider_t key_provider = {.callback = rnp_key_provider_chained,
1333                                              .userdata = key_providers};
1334 
1335     if (input->src_directory) {
1336         // load the keys
1337         try {
1338             store->path = input->src_directory;
1339         } catch (const std::exception &e) {
1340             FFI_LOG(ffi, "%s", e.what());
1341             ret = RNP_ERROR_OUT_OF_MEMORY;
1342             goto done;
1343         }
1344         if (!rnp_key_store_load_from_path(store, &key_provider)) {
1345             ret = RNP_ERROR_BAD_FORMAT;
1346             goto done;
1347         }
1348     } else {
1349         // load the keys
1350         if (!rnp_key_store_load_from_src(store, &input->src, &key_provider)) {
1351             ret = RNP_ERROR_BAD_FORMAT;
1352             goto done;
1353         }
1354     }
1355 
1356     ret = RNP_SUCCESS;
1357 done:
1358     return ret;
1359 }
1360 
1361 static bool
key_needs_conversion(const pgp_key_t * key,const rnp_key_store_t * store)1362 key_needs_conversion(const pgp_key_t *key, const rnp_key_store_t *store)
1363 {
1364     pgp_key_store_format_t key_format = key->format;
1365     pgp_key_store_format_t store_format = store->format;
1366     /* pgp_key_t->format is only ever GPG or G10.
1367      *
1368      * The key store, however, could have a format of KBX, GPG, or G10.
1369      * A KBX (and GPG) key store can only handle a pgp_key_t with a format of GPG.
1370      * A G10 key store can only handle a pgp_key_t with a format of G10.
1371      */
1372     // should never be the case
1373     assert(key_format != PGP_KEY_STORE_KBX);
1374     // normalize the store format
1375     if (store_format == PGP_KEY_STORE_KBX) {
1376         store_format = PGP_KEY_STORE_GPG;
1377     }
1378     // from here, both the key and store formats can only be GPG or G10
1379     return key_format != store_format;
1380 }
1381 
1382 static rnp_result_t
do_load_keys(rnp_ffi_t ffi,rnp_input_t input,pgp_key_store_format_t format,key_type_t key_type)1383 do_load_keys(rnp_ffi_t              ffi,
1384              rnp_input_t            input,
1385              pgp_key_store_format_t format,
1386              key_type_t             key_type)
1387 {
1388     rnp_result_t     ret = RNP_ERROR_GENERIC;
1389     rnp_key_store_t *tmp_store = NULL;
1390     pgp_key_t        keycp;
1391     rnp_result_t     tmpret;
1392 
1393     // create a temporary key store to hold the keys
1394     try {
1395         tmp_store = new rnp_key_store_t(format, "", ffi->context);
1396     } catch (const std::invalid_argument &e) {
1397         FFI_LOG(ffi, "Failed to create key store of format: %d", (int) format);
1398         return RNP_ERROR_BAD_PARAMETERS;
1399     } catch (const std::exception &e) {
1400         FFI_LOG(ffi, "%s", e.what());
1401         return RNP_ERROR_OUT_OF_MEMORY;
1402     }
1403 
1404     // load keys into our temporary store
1405     tmpret = load_keys_from_input(ffi, input, tmp_store);
1406     if (tmpret) {
1407         ret = tmpret;
1408         goto done;
1409     }
1410     // go through all the loaded keys
1411     for (auto &key : tmp_store->keys) {
1412         // check that the key is the correct type and has not already been loaded
1413         // add secret key part if it is and we need it
1414         if (key.is_secret() && ((key_type == KEY_TYPE_SECRET) || (key_type == KEY_TYPE_ANY))) {
1415             if (key_needs_conversion(&key, ffi->secring)) {
1416                 FFI_LOG(ffi, "This key format conversion is not yet supported");
1417                 ret = RNP_ERROR_NOT_IMPLEMENTED;
1418                 goto done;
1419             }
1420 
1421             if (!rnp_key_store_add_key(ffi->secring, &key)) {
1422                 FFI_LOG(ffi, "Failed to add secret key");
1423                 ret = RNP_ERROR_GENERIC;
1424                 goto done;
1425             }
1426         }
1427 
1428         // add public key part if needed
1429         if ((key.format == PGP_KEY_STORE_G10) ||
1430             ((key_type != KEY_TYPE_ANY) && (key_type != KEY_TYPE_PUBLIC))) {
1431             continue;
1432         }
1433 
1434         try {
1435             keycp = pgp_key_t(key, true);
1436         } catch (const std::exception &e) {
1437             RNP_LOG("Failed to copy public key part: %s", e.what());
1438             ret = RNP_ERROR_GENERIC;
1439             goto done;
1440         }
1441 
1442         /* TODO: We could do this a few different ways. There isn't an obvious reason
1443          * to restrict what formats we load, so we don't necessarily need to require a
1444          * conversion just to load and use a G10 key when using GPG keyrings, for
1445          * example. We could just convert when saving.
1446          */
1447 
1448         if (key_needs_conversion(&key, ffi->pubring)) {
1449             FFI_LOG(ffi, "This key format conversion is not yet supported");
1450             ret = RNP_ERROR_NOT_IMPLEMENTED;
1451             goto done;
1452         }
1453 
1454         if (!rnp_key_store_add_key(ffi->pubring, &keycp)) {
1455             FFI_LOG(ffi, "Failed to add public key");
1456             ret = RNP_ERROR_GENERIC;
1457             goto done;
1458         }
1459     }
1460 
1461     // success, even if we didn't actually load any
1462     ret = RNP_SUCCESS;
1463 done:
1464     delete tmp_store;
1465     return ret;
1466 }
1467 
1468 static key_type_t
flags_to_key_type(uint32_t * flags)1469 flags_to_key_type(uint32_t *flags)
1470 {
1471     key_type_t type = KEY_TYPE_NONE;
1472     // figure out what type of keys to operate on, based on flags
1473     if ((*flags & RNP_LOAD_SAVE_PUBLIC_KEYS) && (*flags & RNP_LOAD_SAVE_SECRET_KEYS)) {
1474         type = KEY_TYPE_ANY;
1475         *flags &= ~(RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS);
1476     } else if (*flags & RNP_LOAD_SAVE_PUBLIC_KEYS) {
1477         type = KEY_TYPE_PUBLIC;
1478         *flags &= ~RNP_LOAD_SAVE_PUBLIC_KEYS;
1479     } else if (*flags & RNP_LOAD_SAVE_SECRET_KEYS) {
1480         type = KEY_TYPE_SECRET;
1481         *flags &= ~RNP_LOAD_SAVE_SECRET_KEYS;
1482     }
1483     return type;
1484 }
1485 
1486 rnp_result_t
rnp_load_keys(rnp_ffi_t ffi,const char * format,rnp_input_t input,uint32_t flags)1487 rnp_load_keys(rnp_ffi_t ffi, const char *format, rnp_input_t input, uint32_t flags)
1488 try {
1489     // checks
1490     if (!ffi || !format || !input) {
1491         return RNP_ERROR_NULL_POINTER;
1492     }
1493     key_type_t type = flags_to_key_type(&flags);
1494     if (!type) {
1495         FFI_LOG(ffi, "invalid flags - must have public and/or secret keys");
1496         return RNP_ERROR_BAD_PARAMETERS;
1497     }
1498     pgp_key_store_format_t ks_format = PGP_KEY_STORE_UNKNOWN;
1499     if (!parse_ks_format(&ks_format, format)) {
1500         FFI_LOG(ffi, "invalid key store format: %s", format);
1501         return RNP_ERROR_BAD_PARAMETERS;
1502     }
1503 
1504     // check for any unrecognized flags (not forward-compat, but maybe still a good idea)
1505     if (flags) {
1506         FFI_LOG(ffi, "unexpected flags remaining: 0x%X", flags);
1507         return RNP_ERROR_BAD_PARAMETERS;
1508     }
1509     return do_load_keys(ffi, input, ks_format, type);
1510 }
1511 FFI_GUARD
1512 
1513 rnp_result_t
rnp_unload_keys(rnp_ffi_t ffi,uint32_t flags)1514 rnp_unload_keys(rnp_ffi_t ffi, uint32_t flags)
1515 try {
1516     if (!ffi) {
1517         return RNP_ERROR_NULL_POINTER;
1518     }
1519 
1520     if (flags & ~(RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET)) {
1521         return RNP_ERROR_BAD_PARAMETERS;
1522     }
1523 
1524     if (flags & RNP_KEY_UNLOAD_PUBLIC) {
1525         rnp_key_store_clear(ffi->pubring);
1526     }
1527     if (flags & RNP_KEY_UNLOAD_SECRET) {
1528         rnp_key_store_clear(ffi->secring);
1529     }
1530 
1531     return RNP_SUCCESS;
1532 }
1533 FFI_GUARD
1534 
1535 static rnp_result_t
rnp_input_dearmor_if_needed(rnp_input_t input)1536 rnp_input_dearmor_if_needed(rnp_input_t input)
1537 {
1538     if (!input) {
1539         return RNP_ERROR_NULL_POINTER;
1540     }
1541     if (input->src_directory) {
1542         return RNP_ERROR_BAD_PARAMETERS;
1543     }
1544     bool require_armor = false;
1545     /* check whether we already have armored stream */
1546     if (input->src.type == PGP_STREAM_ARMORED) {
1547         if (!src_eof(&input->src)) {
1548             return RNP_SUCCESS;
1549         }
1550         /* eof - probably next we have another armored message */
1551         src_close(&input->src);
1552         void *app_ctx = input->app_ctx;
1553         *input = *(rnp_input_t) app_ctx;
1554         free(app_ctx);
1555         /* we should not mix armored data with binary */
1556         require_armor = true;
1557     }
1558     if (src_eof(&input->src)) {
1559         return RNP_ERROR_EOF;
1560     }
1561     if (!is_armored_source(&input->src)) {
1562         return require_armor ? RNP_ERROR_BAD_FORMAT : RNP_SUCCESS;
1563     }
1564 
1565     rnp_input_t app_ctx = (rnp_input_t) calloc(1, sizeof(*input));
1566     if (!app_ctx) {
1567         return RNP_ERROR_OUT_OF_MEMORY;
1568     }
1569     *app_ctx = *input;
1570 
1571     pgp_source_t armored;
1572     rnp_result_t ret = init_armored_src(&armored, &app_ctx->src);
1573     if (ret) {
1574         /* original src may be changed during init_armored_src call, so copy it back */
1575         input->src = app_ctx->src;
1576         free(app_ctx);
1577         return ret;
1578     }
1579 
1580     input->src = armored;
1581     input->app_ctx = app_ctx;
1582     return RNP_SUCCESS;
1583 }
1584 
1585 static const char *
key_status_to_str(pgp_key_import_status_t status)1586 key_status_to_str(pgp_key_import_status_t status)
1587 {
1588     if (status == PGP_KEY_IMPORT_STATUS_UNKNOWN) {
1589         return "none";
1590     }
1591     return id_str_pair::lookup(key_import_status_map, status, "none");
1592 }
1593 
1594 static rnp_result_t
add_key_status(json_object * keys,const pgp_key_t * key,pgp_key_import_status_t pub,pgp_key_import_status_t sec)1595 add_key_status(json_object *           keys,
1596                const pgp_key_t *       key,
1597                pgp_key_import_status_t pub,
1598                pgp_key_import_status_t sec)
1599 {
1600     json_object *jsokey = json_object_new_object();
1601     if (!jsokey) {
1602         return RNP_ERROR_OUT_OF_MEMORY;
1603     }
1604 
1605     if (!obj_add_field_json(
1606           jsokey, "public", json_object_new_string(key_status_to_str(pub))) ||
1607         !obj_add_field_json(
1608           jsokey, "secret", json_object_new_string(key_status_to_str(sec))) ||
1609         !obj_add_hex_json(jsokey, "fingerprint", key->fp().fingerprint, key->fp().length) ||
1610         !array_add_element_json(keys, jsokey)) {
1611         json_object_put(jsokey);
1612         return RNP_ERROR_OUT_OF_MEMORY;
1613     }
1614 
1615     return RNP_SUCCESS;
1616 }
1617 
1618 rnp_result_t
rnp_import_keys(rnp_ffi_t ffi,rnp_input_t input,uint32_t flags,char ** results)1619 rnp_import_keys(rnp_ffi_t ffi, rnp_input_t input, uint32_t flags, char **results)
1620 try {
1621     if (!ffi || !input) {
1622         return RNP_ERROR_NULL_POINTER;
1623     }
1624     bool sec = false;
1625     bool pub = false;
1626     if (flags & RNP_LOAD_SAVE_SECRET_KEYS) {
1627         sec = true;
1628         flags &= ~RNP_LOAD_SAVE_SECRET_KEYS;
1629     }
1630     if (flags & RNP_LOAD_SAVE_PUBLIC_KEYS) {
1631         pub = true;
1632         flags &= ~RNP_LOAD_SAVE_PUBLIC_KEYS;
1633     }
1634     if (!pub && !sec) {
1635         FFI_LOG(ffi, "bad flags: need to specify public and/or secret keys");
1636         return RNP_ERROR_BAD_PARAMETERS;
1637     }
1638     bool skipbad = false;
1639     if (flags & RNP_LOAD_SAVE_PERMISSIVE) {
1640         skipbad = true;
1641         flags &= ~RNP_LOAD_SAVE_PERMISSIVE;
1642     }
1643     bool single = false;
1644     if (flags & RNP_LOAD_SAVE_SINGLE) {
1645         single = true;
1646         flags &= ~RNP_LOAD_SAVE_SINGLE;
1647     }
1648     if (flags) {
1649         FFI_LOG(ffi, "unexpected flags remaining: 0x%X", flags);
1650         return RNP_ERROR_BAD_PARAMETERS;
1651     }
1652 
1653     rnp_result_t     ret = RNP_ERROR_GENERIC;
1654     rnp_key_store_t *tmp_store = NULL;
1655     rnp_result_t     tmpret;
1656     json_object *    jsores = NULL;
1657     json_object *    jsokeys = NULL;
1658 
1659     // load keys to temporary keystore.
1660     try {
1661         tmp_store = new rnp_key_store_t(PGP_KEY_STORE_GPG, "", ffi->context);
1662     } catch (const std::exception &e) {
1663         FFI_LOG(ffi, "Failed to create key store: %s.", e.what());
1664         return RNP_ERROR_OUT_OF_MEMORY;
1665     }
1666 
1667     if (single) {
1668         /* we need to init and handle dearmor on this layer since it may be used for the next
1669          * keys import */
1670         ret = rnp_input_dearmor_if_needed(input);
1671         if (ret == RNP_ERROR_EOF) {
1672             goto done;
1673         }
1674         if (ret) {
1675             FFI_LOG(ffi, "Failed to init/check dearmor.");
1676             goto done;
1677         }
1678         ret = rnp_key_store_pgp_read_key_from_src(*tmp_store, input->src, skipbad);
1679         if (ret) {
1680             goto done;
1681         }
1682     } else {
1683         ret = rnp_key_store_pgp_read_from_src(tmp_store, &input->src, skipbad);
1684         if (ret) {
1685             goto done;
1686         }
1687     }
1688     jsores = json_object_new_object();
1689     if (!jsores) {
1690         ret = RNP_ERROR_OUT_OF_MEMORY;
1691         goto done;
1692     }
1693     jsokeys = json_object_new_array();
1694     if (!obj_add_field_json(jsores, "keys", jsokeys)) {
1695         ret = RNP_ERROR_OUT_OF_MEMORY;
1696         goto done;
1697     }
1698 
1699     // import keys to the main keystore.
1700     for (auto &key : tmp_store->keys) {
1701         pgp_key_import_status_t pub_status = PGP_KEY_IMPORT_STATUS_UNKNOWN;
1702         pgp_key_import_status_t sec_status = PGP_KEY_IMPORT_STATUS_UNKNOWN;
1703         if (!pub && key.is_public()) {
1704             continue;
1705         }
1706         // if we got here then we add public key itself or public part of the secret key
1707         if (!rnp_key_store_import_key(ffi->pubring, &key, true, &pub_status)) {
1708             ret = RNP_ERROR_BAD_PARAMETERS;
1709             goto done;
1710         }
1711         // import secret key part if available and requested
1712         if (sec && key.is_secret()) {
1713             if (!rnp_key_store_import_key(ffi->secring, &key, false, &sec_status)) {
1714                 ret = RNP_ERROR_BAD_PARAMETERS;
1715                 goto done;
1716             }
1717             // add uids, certifications and other stuff from the public key if any
1718             pgp_key_t *expub = rnp_key_store_get_key_by_fpr(ffi->pubring, key.fp());
1719             if (expub && !rnp_key_store_import_key(ffi->secring, expub, true, NULL)) {
1720                 ret = RNP_ERROR_BAD_PARAMETERS;
1721                 goto done;
1722             }
1723         }
1724         // now add key fingerprint to json based on statuses
1725         if ((tmpret = add_key_status(jsokeys, &key, pub_status, sec_status))) {
1726             ret = tmpret;
1727             goto done;
1728         }
1729     }
1730 
1731     if (results) {
1732         *results = (char *) json_object_to_json_string_ext(jsores, JSON_C_TO_STRING_PRETTY);
1733         if (!*results) {
1734             goto done;
1735         }
1736         *results = strdup(*results);
1737         if (!*results) {
1738             ret = RNP_ERROR_OUT_OF_MEMORY;
1739             goto done;
1740         }
1741     }
1742 
1743     ret = RNP_SUCCESS;
1744 done:
1745     delete tmp_store;
1746     json_object_put(jsores);
1747     return ret;
1748 }
1749 FFI_GUARD
1750 
1751 static const char *
sig_status_to_str(pgp_sig_import_status_t status)1752 sig_status_to_str(pgp_sig_import_status_t status)
1753 {
1754     if (status == PGP_SIG_IMPORT_STATUS_UNKNOWN) {
1755         return "none";
1756     }
1757     return id_str_pair::lookup(sig_import_status_map, status, "none");
1758 }
1759 
1760 static rnp_result_t
add_sig_status(json_object * sigs,const pgp_key_t * signer,pgp_sig_import_status_t pub,pgp_sig_import_status_t sec)1761 add_sig_status(json_object *           sigs,
1762                const pgp_key_t *       signer,
1763                pgp_sig_import_status_t pub,
1764                pgp_sig_import_status_t sec)
1765 {
1766     json_object *jsosig = json_object_new_object();
1767     if (!jsosig) {
1768         return RNP_ERROR_OUT_OF_MEMORY;
1769     }
1770 
1771     if (!obj_add_field_json(
1772           jsosig, "public", json_object_new_string(sig_status_to_str(pub))) ||
1773         !obj_add_field_json(
1774           jsosig, "secret", json_object_new_string(sig_status_to_str(sec)))) {
1775         json_object_put(jsosig);
1776         return RNP_ERROR_OUT_OF_MEMORY;
1777     }
1778 
1779     if (signer) {
1780         const pgp_fingerprint_t &fp = signer->fp();
1781         if (!obj_add_hex_json(jsosig, "signer fingerprint", fp.fingerprint, fp.length)) {
1782             json_object_put(jsosig);
1783             return RNP_ERROR_OUT_OF_MEMORY;
1784         }
1785     }
1786 
1787     if (!array_add_element_json(sigs, jsosig)) {
1788         json_object_put(jsosig);
1789         return RNP_ERROR_OUT_OF_MEMORY;
1790     }
1791 
1792     return RNP_SUCCESS;
1793 }
1794 
1795 rnp_result_t
rnp_import_signatures(rnp_ffi_t ffi,rnp_input_t input,uint32_t flags,char ** results)1796 rnp_import_signatures(rnp_ffi_t ffi, rnp_input_t input, uint32_t flags, char **results)
1797 try {
1798     if (!ffi || !input) {
1799         return RNP_ERROR_NULL_POINTER;
1800     }
1801     if (flags) {
1802         FFI_LOG(ffi, "wrong flags: %d", (int) flags);
1803         return RNP_ERROR_BAD_PARAMETERS;
1804     }
1805 
1806     rnp_result_t         ret = RNP_ERROR_GENERIC;
1807     json_object *        jsores = NULL;
1808     json_object *        jsosigs = NULL;
1809     pgp_signature_list_t sigs;
1810     rnp_result_t         sigret = process_pgp_signatures(&input->src, sigs);
1811     if (sigret) {
1812         ret = sigret;
1813         FFI_LOG(ffi, "failed to parse signature(s)");
1814         goto done;
1815     }
1816 
1817     jsores = json_object_new_object();
1818     if (!jsores) {
1819         ret = RNP_ERROR_OUT_OF_MEMORY;
1820         goto done;
1821     }
1822     jsosigs = json_object_new_array();
1823     if (!obj_add_field_json(jsores, "sigs", jsosigs)) {
1824         ret = RNP_ERROR_OUT_OF_MEMORY;
1825         goto done;
1826     }
1827 
1828     for (auto &sig : sigs) {
1829         pgp_sig_import_status_t pub_status = PGP_SIG_IMPORT_STATUS_UNKNOWN;
1830         pgp_sig_import_status_t sec_status = PGP_SIG_IMPORT_STATUS_UNKNOWN;
1831         pgp_key_t *pkey = rnp_key_store_import_signature(ffi->pubring, &sig, &pub_status);
1832         pgp_key_t *skey = rnp_key_store_import_signature(ffi->secring, &sig, &sec_status);
1833         sigret = add_sig_status(jsosigs, pkey ? pkey : skey, pub_status, sec_status);
1834         if (sigret) {
1835             ret = sigret;
1836             goto done;
1837         }
1838     }
1839 
1840     if (results) {
1841         *results = (char *) json_object_to_json_string_ext(jsores, JSON_C_TO_STRING_PRETTY);
1842         if (!*results) {
1843             ret = RNP_ERROR_OUT_OF_MEMORY;
1844             goto done;
1845         }
1846         *results = strdup(*results);
1847         if (!*results) {
1848             ret = RNP_ERROR_OUT_OF_MEMORY;
1849             goto done;
1850         }
1851     }
1852     ret = RNP_SUCCESS;
1853 done:
1854     json_object_put(jsores);
1855     return ret;
1856 }
1857 FFI_GUARD
1858 
1859 static bool
copy_store_keys(rnp_ffi_t ffi,rnp_key_store_t * dest,rnp_key_store_t * src)1860 copy_store_keys(rnp_ffi_t ffi, rnp_key_store_t *dest, rnp_key_store_t *src)
1861 {
1862     for (auto &key : src->keys) {
1863         if (!rnp_key_store_add_key(dest, &key)) {
1864             FFI_LOG(ffi, "failed to add key to the store");
1865             return false;
1866         }
1867     }
1868     return true;
1869 }
1870 
1871 static rnp_result_t
do_save_keys(rnp_ffi_t ffi,rnp_output_t output,pgp_key_store_format_t format,key_type_t key_type)1872 do_save_keys(rnp_ffi_t              ffi,
1873              rnp_output_t           output,
1874              pgp_key_store_format_t format,
1875              key_type_t             key_type)
1876 {
1877     rnp_result_t ret = RNP_ERROR_GENERIC;
1878 
1879     // create a temporary key store to hold the keys
1880     rnp_key_store_t *tmp_store = NULL;
1881     try {
1882         tmp_store = new rnp_key_store_t(format, "", ffi->context);
1883     } catch (const std::invalid_argument &e) {
1884         FFI_LOG(ffi, "Failed to create key store of format: %d", (int) format);
1885         return RNP_ERROR_BAD_PARAMETERS;
1886     } catch (const std::exception &e) {
1887         FFI_LOG(ffi, "%s", e.what());
1888         return RNP_ERROR_OUT_OF_MEMORY;
1889     }
1890     // include the public keys, if desired
1891     if (key_type == KEY_TYPE_PUBLIC || key_type == KEY_TYPE_ANY) {
1892         if (!copy_store_keys(ffi, tmp_store, ffi->pubring)) {
1893             ret = RNP_ERROR_OUT_OF_MEMORY;
1894             goto done;
1895         }
1896     }
1897     // include the secret keys, if desired
1898     if (key_type == KEY_TYPE_SECRET || key_type == KEY_TYPE_ANY) {
1899         if (!copy_store_keys(ffi, tmp_store, ffi->secring)) {
1900             ret = RNP_ERROR_OUT_OF_MEMORY;
1901             goto done;
1902         }
1903     }
1904     // preliminary check on the format
1905     for (auto &key : tmp_store->keys) {
1906         if (key_needs_conversion(&key, tmp_store)) {
1907             FFI_LOG(ffi, "This key format conversion is not yet supported");
1908             ret = RNP_ERROR_NOT_IMPLEMENTED;
1909             goto done;
1910         }
1911     }
1912     // write
1913     if (output->dst_directory) {
1914         try {
1915             tmp_store->path = output->dst_directory;
1916         } catch (const std::exception &e) {
1917             FFI_LOG(ffi, "%s", e.what());
1918             ret = RNP_ERROR_OUT_OF_MEMORY;
1919             goto done;
1920         }
1921         if (!rnp_key_store_write_to_path(tmp_store)) {
1922             ret = RNP_ERROR_WRITE;
1923             goto done;
1924         }
1925         ret = RNP_SUCCESS;
1926     } else {
1927         if (!rnp_key_store_write_to_dst(tmp_store, &output->dst)) {
1928             ret = RNP_ERROR_WRITE;
1929             goto done;
1930         }
1931         dst_flush(&output->dst);
1932         output->keep = (output->dst.werr == RNP_SUCCESS);
1933         ret = output->dst.werr;
1934     }
1935 
1936 done:
1937     delete tmp_store;
1938     return ret;
1939 }
1940 
1941 rnp_result_t
rnp_save_keys(rnp_ffi_t ffi,const char * format,rnp_output_t output,uint32_t flags)1942 rnp_save_keys(rnp_ffi_t ffi, const char *format, rnp_output_t output, uint32_t flags)
1943 try {
1944     // checks
1945     if (!ffi || !format || !output) {
1946         return RNP_ERROR_NULL_POINTER;
1947     }
1948     key_type_t type = flags_to_key_type(&flags);
1949     if (!type) {
1950         FFI_LOG(ffi, "invalid flags - must have public and/or secret keys");
1951         return RNP_ERROR_BAD_PARAMETERS;
1952     }
1953     // check for any unrecognized flags (not forward-compat, but maybe still a good idea)
1954     if (flags) {
1955         FFI_LOG(ffi, "unexpected flags remaining: 0x%X", flags);
1956         return RNP_ERROR_BAD_PARAMETERS;
1957     }
1958     pgp_key_store_format_t ks_format = PGP_KEY_STORE_UNKNOWN;
1959     if (!parse_ks_format(&ks_format, format)) {
1960         FFI_LOG(ffi, "unknown key store format: %s", format);
1961         return RNP_ERROR_BAD_PARAMETERS;
1962     }
1963     return do_save_keys(ffi, output, ks_format, type);
1964 }
1965 FFI_GUARD
1966 
1967 rnp_result_t
rnp_get_public_key_count(rnp_ffi_t ffi,size_t * count)1968 rnp_get_public_key_count(rnp_ffi_t ffi, size_t *count)
1969 try {
1970     if (!ffi || !count) {
1971         return RNP_ERROR_NULL_POINTER;
1972     }
1973     *count = rnp_key_store_get_key_count(ffi->pubring);
1974     return RNP_SUCCESS;
1975 }
1976 FFI_GUARD
1977 
1978 rnp_result_t
rnp_get_secret_key_count(rnp_ffi_t ffi,size_t * count)1979 rnp_get_secret_key_count(rnp_ffi_t ffi, size_t *count)
1980 try {
1981     if (!ffi || !count) {
1982         return RNP_ERROR_NULL_POINTER;
1983     }
1984     *count = rnp_key_store_get_key_count(ffi->secring);
1985     return RNP_SUCCESS;
1986 }
1987 FFI_GUARD
1988 
1989 rnp_result_t
rnp_input_from_path(rnp_input_t * input,const char * path)1990 rnp_input_from_path(rnp_input_t *input, const char *path)
1991 try {
1992     struct rnp_input_st *ob = NULL;
1993     struct stat          st = {0};
1994 
1995     if (!input || !path) {
1996         return RNP_ERROR_NULL_POINTER;
1997     }
1998     ob = (rnp_input_st *) calloc(1, sizeof(*ob));
1999     if (!ob) {
2000         return RNP_ERROR_OUT_OF_MEMORY;
2001     }
2002     if (rnp_stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
2003         // a bit hacky, just save the directory path
2004         ob->src_directory = strdup(path);
2005         if (!ob->src_directory) {
2006             free(ob);
2007             return RNP_ERROR_OUT_OF_MEMORY;
2008         }
2009         // return error on attempt to read from this source
2010         (void) init_null_src(&ob->src);
2011     } else {
2012         // simple input from a file
2013         rnp_result_t ret = init_file_src(&ob->src, path);
2014         if (ret) {
2015             free(ob);
2016             return ret;
2017         }
2018     }
2019     *input = ob;
2020     return RNP_SUCCESS;
2021 }
2022 FFI_GUARD
2023 
2024 rnp_result_t
rnp_input_from_memory(rnp_input_t * input,const uint8_t buf[],size_t buf_len,bool do_copy)2025 rnp_input_from_memory(rnp_input_t *input, const uint8_t buf[], size_t buf_len, bool do_copy)
2026 try {
2027     if (!input || !buf) {
2028         return RNP_ERROR_NULL_POINTER;
2029     }
2030     if (!buf_len) {
2031         return RNP_ERROR_SHORT_BUFFER;
2032     }
2033     *input = (rnp_input_t) calloc(1, sizeof(**input));
2034     if (!*input) {
2035         return RNP_ERROR_OUT_OF_MEMORY;
2036     }
2037     uint8_t *data = (uint8_t *) buf;
2038     if (do_copy) {
2039         data = (uint8_t *) malloc(buf_len);
2040         if (!data) {
2041             free(*input);
2042             *input = NULL;
2043             return RNP_ERROR_OUT_OF_MEMORY;
2044         }
2045         memcpy(data, buf, buf_len);
2046     }
2047     rnp_result_t ret = init_mem_src(&(*input)->src, data, buf_len, do_copy);
2048     if (ret) {
2049         if (do_copy) {
2050             free(data);
2051         }
2052         free(*input);
2053         *input = NULL;
2054         return ret;
2055     }
2056     return RNP_SUCCESS;
2057 }
2058 FFI_GUARD
2059 
2060 static bool
input_reader_bounce(pgp_source_t * src,void * buf,size_t len,size_t * read)2061 input_reader_bounce(pgp_source_t *src, void *buf, size_t len, size_t *read)
2062 {
2063     rnp_input_t input = (rnp_input_t) src->param;
2064     if (!input->reader) {
2065         return false;
2066     }
2067     return input->reader(input->app_ctx, buf, len, read);
2068 }
2069 
2070 static void
input_closer_bounce(pgp_source_t * src)2071 input_closer_bounce(pgp_source_t *src)
2072 {
2073     rnp_input_t input = (rnp_input_t) src->param;
2074     if (input->closer) {
2075         input->closer(input->app_ctx);
2076     }
2077 }
2078 
2079 rnp_result_t
rnp_input_from_callback(rnp_input_t * input,rnp_input_reader_t * reader,rnp_input_closer_t * closer,void * app_ctx)2080 rnp_input_from_callback(rnp_input_t *       input,
2081                         rnp_input_reader_t *reader,
2082                         rnp_input_closer_t *closer,
2083                         void *              app_ctx)
2084 try {
2085     struct rnp_input_st *obj = NULL;
2086 
2087     // checks
2088     if (!input || !reader) {
2089         return RNP_ERROR_NULL_POINTER;
2090     }
2091     obj = (rnp_input_st *) calloc(1, sizeof(*obj));
2092     if (!obj) {
2093         return RNP_ERROR_OUT_OF_MEMORY;
2094     }
2095     pgp_source_t *src = &obj->src;
2096     obj->reader = reader;
2097     obj->closer = closer;
2098     obj->app_ctx = app_ctx;
2099     if (!init_src_common(src, 0)) {
2100         free(obj);
2101         return RNP_ERROR_OUT_OF_MEMORY;
2102     }
2103     src->param = obj;
2104     src->read = input_reader_bounce;
2105     src->close = input_closer_bounce;
2106     src->type = PGP_STREAM_MEMORY;
2107     *input = obj;
2108     return RNP_SUCCESS;
2109 }
2110 FFI_GUARD
2111 
2112 rnp_result_t
rnp_input_destroy(rnp_input_t input)2113 rnp_input_destroy(rnp_input_t input)
2114 try {
2115     if (input) {
2116         bool armored = input->src.type == PGP_STREAM_ARMORED;
2117         src_close(&input->src);
2118         if (armored) {
2119             rnp_input_destroy((rnp_input_t) input->app_ctx);
2120         }
2121         free(input->src_directory);
2122         free(input);
2123     }
2124     return RNP_SUCCESS;
2125 }
2126 FFI_GUARD
2127 
2128 rnp_result_t
rnp_output_to_path(rnp_output_t * output,const char * path)2129 rnp_output_to_path(rnp_output_t *output, const char *path)
2130 try {
2131     struct rnp_output_st *ob = NULL;
2132     struct stat           st = {0};
2133 
2134     if (!output || !path) {
2135         return RNP_ERROR_NULL_POINTER;
2136     }
2137     ob = (rnp_output_st *) calloc(1, sizeof(*ob));
2138     if (!ob) {
2139         return RNP_ERROR_OUT_OF_MEMORY;
2140     }
2141     if (rnp_stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
2142         // a bit hacky, just save the directory path
2143         ob->dst_directory = strdup(path);
2144         if (!ob->dst_directory) {
2145             free(ob);
2146             return RNP_ERROR_OUT_OF_MEMORY;
2147         }
2148     } else {
2149         // simple output to a file
2150         rnp_result_t ret = init_file_dest(&ob->dst, path, true);
2151         if (ret) {
2152             free(ob);
2153             return ret;
2154         }
2155     }
2156     *output = ob;
2157     return RNP_SUCCESS;
2158 }
2159 FFI_GUARD
2160 
2161 rnp_result_t
rnp_output_to_file(rnp_output_t * output,const char * path,uint32_t flags)2162 rnp_output_to_file(rnp_output_t *output, const char *path, uint32_t flags)
2163 try {
2164     if (!output || !path) {
2165         return RNP_ERROR_NULL_POINTER;
2166     }
2167     bool overwrite = false;
2168     bool random = false;
2169     if (flags & RNP_OUTPUT_FILE_OVERWRITE) {
2170         overwrite = true;
2171         flags &= ~RNP_OUTPUT_FILE_OVERWRITE;
2172     }
2173     if (flags & RNP_OUTPUT_FILE_RANDOM) {
2174         random = true;
2175         flags &= ~RNP_OUTPUT_FILE_RANDOM;
2176     }
2177     if (flags) {
2178         return RNP_ERROR_BAD_PARAMETERS;
2179     }
2180     rnp_output_t res = (rnp_output_t) calloc(1, sizeof(*res));
2181     if (!res) {
2182         return RNP_ERROR_OUT_OF_MEMORY;
2183     }
2184     rnp_result_t ret = RNP_ERROR_GENERIC;
2185     if (random) {
2186         ret = init_tmpfile_dest(&res->dst, path, overwrite);
2187     } else {
2188         ret = init_file_dest(&res->dst, path, overwrite);
2189     }
2190     if (ret) {
2191         free(res);
2192         return ret;
2193     }
2194     *output = res;
2195     return RNP_SUCCESS;
2196 }
2197 FFI_GUARD
2198 
2199 rnp_result_t
rnp_output_to_memory(rnp_output_t * output,size_t max_alloc)2200 rnp_output_to_memory(rnp_output_t *output, size_t max_alloc)
2201 try {
2202     // checks
2203     if (!output) {
2204         return RNP_ERROR_NULL_POINTER;
2205     }
2206 
2207     *output = (rnp_output_t) calloc(1, sizeof(**output));
2208     if (!*output) {
2209         return RNP_ERROR_OUT_OF_MEMORY;
2210     }
2211     rnp_result_t ret = init_mem_dest(&(*output)->dst, NULL, max_alloc);
2212     if (ret) {
2213         free(*output);
2214         *output = NULL;
2215         return ret;
2216     }
2217     return RNP_SUCCESS;
2218 }
2219 FFI_GUARD
2220 
2221 rnp_result_t
rnp_output_to_armor(rnp_output_t base,rnp_output_t * output,const char * type)2222 rnp_output_to_armor(rnp_output_t base, rnp_output_t *output, const char *type)
2223 try {
2224     if (!base || !output) {
2225         return RNP_ERROR_NULL_POINTER;
2226     }
2227     pgp_armored_msg_t msgtype = PGP_ARMORED_MESSAGE;
2228     if (type) {
2229         msgtype = static_cast<pgp_armored_msg_t>(
2230           id_str_pair::lookup(armor_type_map, type, PGP_ARMORED_UNKNOWN));
2231         if (msgtype == PGP_ARMORED_UNKNOWN) {
2232             RNP_LOG("Unsupported armor type: %s", type);
2233             return RNP_ERROR_BAD_PARAMETERS;
2234         }
2235     }
2236     *output = (rnp_output_t) calloc(1, sizeof(**output));
2237     if (!*output) {
2238         return RNP_ERROR_OUT_OF_MEMORY;
2239     }
2240     rnp_result_t ret = init_armored_dst(&(*output)->dst, &base->dst, msgtype);
2241     if (ret) {
2242         free(*output);
2243         *output = NULL;
2244         return ret;
2245     }
2246     (*output)->app_ctx = base;
2247     return RNP_SUCCESS;
2248 }
2249 FFI_GUARD
2250 
2251 rnp_result_t
rnp_output_memory_get_buf(rnp_output_t output,uint8_t ** buf,size_t * len,bool do_copy)2252 rnp_output_memory_get_buf(rnp_output_t output, uint8_t **buf, size_t *len, bool do_copy)
2253 try {
2254     if (!output || !buf || !len) {
2255         return RNP_ERROR_NULL_POINTER;
2256     }
2257 
2258     *len = output->dst.writeb;
2259     *buf = (uint8_t *) mem_dest_get_memory(&output->dst);
2260     if (!*buf) {
2261         return RNP_ERROR_BAD_PARAMETERS;
2262     }
2263     if (do_copy) {
2264         uint8_t *tmp_buf = *buf;
2265         *buf = (uint8_t *) malloc(*len);
2266         if (!*buf) {
2267             return RNP_ERROR_OUT_OF_MEMORY;
2268         }
2269         memcpy(*buf, tmp_buf, *len);
2270     }
2271     return RNP_SUCCESS;
2272 }
2273 FFI_GUARD
2274 
2275 static rnp_result_t
output_writer_bounce(pgp_dest_t * dst,const void * buf,size_t len)2276 output_writer_bounce(pgp_dest_t *dst, const void *buf, size_t len)
2277 {
2278     rnp_output_t output = (rnp_output_t) dst->param;
2279     if (!output->writer) {
2280         return RNP_ERROR_NULL_POINTER;
2281     }
2282     if (!output->writer(output->app_ctx, buf, len)) {
2283         return RNP_ERROR_WRITE;
2284     }
2285     return RNP_SUCCESS;
2286 }
2287 
2288 static void
output_closer_bounce(pgp_dest_t * dst,bool discard)2289 output_closer_bounce(pgp_dest_t *dst, bool discard)
2290 {
2291     rnp_output_t output = (rnp_output_t) dst->param;
2292     if (output->closer) {
2293         output->closer(output->app_ctx, discard);
2294     }
2295 }
2296 
2297 rnp_result_t
rnp_output_to_null(rnp_output_t * output)2298 rnp_output_to_null(rnp_output_t *output)
2299 try {
2300     // checks
2301     if (!output) {
2302         return RNP_ERROR_NULL_POINTER;
2303     }
2304 
2305     *output = (rnp_output_t) calloc(1, sizeof(**output));
2306     if (!*output) {
2307         return RNP_ERROR_OUT_OF_MEMORY;
2308     }
2309     rnp_result_t ret = init_null_dest(&(*output)->dst);
2310     if (ret) {
2311         free(*output);
2312         *output = NULL;
2313         return ret;
2314     }
2315     return RNP_SUCCESS;
2316 }
2317 FFI_GUARD
2318 
2319 rnp_result_t
rnp_output_write(rnp_output_t output,const void * data,size_t size,size_t * written)2320 rnp_output_write(rnp_output_t output, const void *data, size_t size, size_t *written)
2321 try {
2322     if (!output || (!data && size)) {
2323         return RNP_ERROR_NULL_POINTER;
2324     }
2325     if (!data && !size) {
2326         if (written) {
2327             *written = 0;
2328         }
2329         return RNP_SUCCESS;
2330     }
2331     size_t old = output->dst.writeb + output->dst.clen;
2332     dst_write(&output->dst, data, size);
2333     if (!output->dst.werr && written) {
2334         *written = output->dst.writeb + output->dst.clen - old;
2335     }
2336     output->keep = !output->dst.werr;
2337     return output->dst.werr;
2338 }
2339 FFI_GUARD
2340 
2341 rnp_result_t
rnp_output_to_callback(rnp_output_t * output,rnp_output_writer_t * writer,rnp_output_closer_t * closer,void * app_ctx)2342 rnp_output_to_callback(rnp_output_t *       output,
2343                        rnp_output_writer_t *writer,
2344                        rnp_output_closer_t *closer,
2345                        void *               app_ctx)
2346 try {
2347     // checks
2348     if (!output || !writer) {
2349         return RNP_ERROR_NULL_POINTER;
2350     }
2351 
2352     *output = (rnp_output_t) calloc(1, sizeof(**output));
2353     if (!*output) {
2354         return RNP_ERROR_OUT_OF_MEMORY;
2355     }
2356     (*output)->writer = writer;
2357     (*output)->closer = closer;
2358     (*output)->app_ctx = app_ctx;
2359 
2360     pgp_dest_t *dst = &(*output)->dst;
2361     dst->write = output_writer_bounce;
2362     dst->close = output_closer_bounce;
2363     dst->param = *output;
2364     dst->type = PGP_STREAM_MEMORY;
2365     dst->writeb = 0;
2366     dst->werr = RNP_SUCCESS;
2367     return RNP_SUCCESS;
2368 }
2369 FFI_GUARD
2370 
2371 rnp_result_t
rnp_output_finish(rnp_output_t output)2372 rnp_output_finish(rnp_output_t output)
2373 try {
2374     if (!output) {
2375         return RNP_ERROR_NULL_POINTER;
2376     }
2377     return dst_finish(&output->dst);
2378 }
2379 FFI_GUARD
2380 
2381 rnp_result_t
rnp_output_destroy(rnp_output_t output)2382 rnp_output_destroy(rnp_output_t output)
2383 try {
2384     if (output) {
2385         if (output->dst.type == PGP_STREAM_ARMORED) {
2386             ((rnp_output_t) output->app_ctx)->keep = output->keep;
2387         }
2388         dst_close(&output->dst, !output->keep);
2389         free(output->dst_directory);
2390         free(output);
2391     }
2392     return RNP_SUCCESS;
2393 }
2394 FFI_GUARD
2395 
2396 static rnp_result_t
rnp_op_add_signature(rnp_ffi_t ffi,rnp_op_sign_signatures_t & signatures,rnp_key_handle_t key,rnp_ctx_t & ctx,rnp_op_sign_signature_t * sig)2397 rnp_op_add_signature(rnp_ffi_t                 ffi,
2398                      rnp_op_sign_signatures_t &signatures,
2399                      rnp_key_handle_t          key,
2400                      rnp_ctx_t &               ctx,
2401                      rnp_op_sign_signature_t * sig)
2402 {
2403     if (!key) {
2404         return RNP_ERROR_NULL_POINTER;
2405     }
2406 
2407     pgp_key_t *signkey = find_suitable_key(
2408       PGP_OP_SIGN, get_key_prefer_public(key), &key->ffi->key_provider, PGP_KF_SIGN);
2409     if (signkey && !signkey->is_secret()) {
2410         pgp_key_request_ctx_t keyctx = {.op = PGP_OP_SIGN, .secret = true};
2411         keyctx.search.type = PGP_KEY_SEARCH_GRIP;
2412         keyctx.search.by.grip = signkey->grip();
2413         signkey = pgp_request_key(&key->ffi->key_provider, &keyctx);
2414     }
2415     if (!signkey) {
2416         return RNP_ERROR_NO_SUITABLE_KEY;
2417     }
2418 
2419     try {
2420         signatures.emplace_back();
2421     } catch (const std::exception &e) {
2422         FFI_LOG(ffi, "%s", e.what());
2423         return RNP_ERROR_BAD_PARAMETERS;
2424     }
2425     rnp_op_sign_signature_t newsig = &signatures.back();
2426     newsig->signer.key = signkey;
2427     /* set default create/expire times */
2428     newsig->signer.sigcreate = ctx.sigcreate;
2429     newsig->signer.sigexpire = ctx.sigexpire;
2430     newsig->ffi = ffi;
2431 
2432     if (sig) {
2433         *sig = newsig;
2434     }
2435     return RNP_SUCCESS;
2436 }
2437 
2438 static rnp_result_t
rnp_op_set_armor(rnp_ctx_t & ctx,bool armored)2439 rnp_op_set_armor(rnp_ctx_t &ctx, bool armored)
2440 {
2441     ctx.armor = armored;
2442     return RNP_SUCCESS;
2443 }
2444 
2445 static rnp_result_t
rnp_op_set_compression(rnp_ffi_t ffi,rnp_ctx_t & ctx,const char * compression,int level)2446 rnp_op_set_compression(rnp_ffi_t ffi, rnp_ctx_t &ctx, const char *compression, int level)
2447 {
2448     if (!compression) {
2449         return RNP_ERROR_NULL_POINTER;
2450     }
2451 
2452     pgp_compression_type_t zalg = PGP_C_UNKNOWN;
2453     if (!str_to_compression_alg(compression, &zalg)) {
2454         FFI_LOG(ffi, "Invalid compression: %s", compression);
2455         return RNP_ERROR_BAD_PARAMETERS;
2456     }
2457     ctx.zalg = (int) zalg;
2458     ctx.zlevel = level;
2459     return RNP_SUCCESS;
2460 }
2461 
2462 static rnp_result_t
rnp_op_set_hash(rnp_ffi_t ffi,rnp_ctx_t & ctx,const char * hash)2463 rnp_op_set_hash(rnp_ffi_t ffi, rnp_ctx_t &ctx, const char *hash)
2464 {
2465     if (!hash) {
2466         return RNP_ERROR_NULL_POINTER;
2467     }
2468 
2469     if (!str_to_hash_alg(hash, &ctx.halg)) {
2470         FFI_LOG(ffi, "Invalid hash: %s", hash);
2471         return RNP_ERROR_BAD_PARAMETERS;
2472     }
2473     return RNP_SUCCESS;
2474 }
2475 
2476 static rnp_result_t
rnp_op_set_creation_time(rnp_ctx_t & ctx,uint32_t create)2477 rnp_op_set_creation_time(rnp_ctx_t &ctx, uint32_t create)
2478 {
2479     ctx.sigcreate = create;
2480     return RNP_SUCCESS;
2481 }
2482 
2483 static rnp_result_t
rnp_op_set_expiration_time(rnp_ctx_t & ctx,uint32_t expire)2484 rnp_op_set_expiration_time(rnp_ctx_t &ctx, uint32_t expire)
2485 {
2486     ctx.sigexpire = expire;
2487     return RNP_SUCCESS;
2488 }
2489 
2490 static rnp_result_t
rnp_op_set_file_name(rnp_ctx_t & ctx,const char * filename)2491 rnp_op_set_file_name(rnp_ctx_t &ctx, const char *filename)
2492 {
2493     ctx.filename = filename ? filename : "";
2494     return RNP_SUCCESS;
2495 }
2496 
2497 static rnp_result_t
rnp_op_set_file_mtime(rnp_ctx_t & ctx,uint32_t mtime)2498 rnp_op_set_file_mtime(rnp_ctx_t &ctx, uint32_t mtime)
2499 {
2500     ctx.filemtime = mtime;
2501     return RNP_SUCCESS;
2502 }
2503 
2504 rnp_result_t
rnp_op_encrypt_create(rnp_op_encrypt_t * op,rnp_ffi_t ffi,rnp_input_t input,rnp_output_t output)2505 rnp_op_encrypt_create(rnp_op_encrypt_t *op,
2506                       rnp_ffi_t         ffi,
2507                       rnp_input_t       input,
2508                       rnp_output_t      output)
2509 try {
2510     // checks
2511     if (!op || !ffi || !input || !output) {
2512         return RNP_ERROR_NULL_POINTER;
2513     }
2514 
2515     *op = new rnp_op_encrypt_st();
2516     rnp_ctx_init_ffi((*op)->rnpctx, ffi);
2517     (*op)->ffi = ffi;
2518     (*op)->input = input;
2519     (*op)->output = output;
2520     return RNP_SUCCESS;
2521 }
2522 FFI_GUARD
2523 
2524 rnp_result_t
rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op,rnp_key_handle_t handle)2525 rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op, rnp_key_handle_t handle)
2526 try {
2527     // checks
2528     if (!op || !handle) {
2529         return RNP_ERROR_NULL_POINTER;
2530     }
2531 
2532     pgp_key_t *key = find_suitable_key(PGP_OP_ENCRYPT,
2533                                        get_key_prefer_public(handle),
2534                                        &handle->ffi->key_provider,
2535                                        PGP_KF_ENCRYPT);
2536     if (!key) {
2537         key = get_key_prefer_public(handle);
2538     }
2539     op->rnpctx.recipients.push_back(key);
2540     return RNP_SUCCESS;
2541 }
2542 FFI_GUARD
2543 
2544 rnp_result_t
rnp_op_encrypt_add_signature(rnp_op_encrypt_t op,rnp_key_handle_t key,rnp_op_sign_signature_t * sig)2545 rnp_op_encrypt_add_signature(rnp_op_encrypt_t         op,
2546                              rnp_key_handle_t         key,
2547                              rnp_op_sign_signature_t *sig)
2548 try {
2549     if (!op) {
2550         return RNP_ERROR_NULL_POINTER;
2551     }
2552     return rnp_op_add_signature(op->ffi, op->signatures, key, op->rnpctx, sig);
2553 }
2554 FFI_GUARD
2555 
2556 rnp_result_t
rnp_op_encrypt_set_hash(rnp_op_encrypt_t op,const char * hash)2557 rnp_op_encrypt_set_hash(rnp_op_encrypt_t op, const char *hash)
2558 try {
2559     if (!op) {
2560         return RNP_ERROR_NULL_POINTER;
2561     }
2562     return rnp_op_set_hash(op->ffi, op->rnpctx, hash);
2563 }
2564 FFI_GUARD
2565 
2566 rnp_result_t
rnp_op_encrypt_set_creation_time(rnp_op_encrypt_t op,uint32_t create)2567 rnp_op_encrypt_set_creation_time(rnp_op_encrypt_t op, uint32_t create)
2568 try {
2569     if (!op) {
2570         return RNP_ERROR_NULL_POINTER;
2571     }
2572     return rnp_op_set_creation_time(op->rnpctx, create);
2573 }
2574 FFI_GUARD
2575 
2576 rnp_result_t
rnp_op_encrypt_set_expiration_time(rnp_op_encrypt_t op,uint32_t expire)2577 rnp_op_encrypt_set_expiration_time(rnp_op_encrypt_t op, uint32_t expire)
2578 try {
2579     if (!op) {
2580         return RNP_ERROR_NULL_POINTER;
2581     }
2582     return rnp_op_set_expiration_time(op->rnpctx, expire);
2583 }
2584 FFI_GUARD
2585 
2586 rnp_result_t
rnp_op_encrypt_add_password(rnp_op_encrypt_t op,const char * password,const char * s2k_hash,size_t iterations,const char * s2k_cipher)2587 rnp_op_encrypt_add_password(rnp_op_encrypt_t op,
2588                             const char *     password,
2589                             const char *     s2k_hash,
2590                             size_t           iterations,
2591                             const char *     s2k_cipher)
2592 try {
2593     // checks
2594     if (!op) {
2595         return RNP_ERROR_NULL_POINTER;
2596     }
2597     if (password && !*password) {
2598         // no blank passwords
2599         FFI_LOG(op->ffi, "Blank password");
2600         return RNP_ERROR_BAD_PARAMETERS;
2601     }
2602 
2603     // set some defaults
2604     if (!s2k_hash) {
2605         s2k_hash = DEFAULT_HASH_ALG;
2606     }
2607     if (!s2k_cipher) {
2608         s2k_cipher = DEFAULT_SYMM_ALG;
2609     }
2610     // parse
2611     pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN;
2612     if (!str_to_hash_alg(s2k_hash, &hash_alg)) {
2613         FFI_LOG(op->ffi, "Invalid hash: %s", s2k_hash);
2614         return RNP_ERROR_BAD_PARAMETERS;
2615     }
2616     pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN;
2617     if (!str_to_cipher(s2k_cipher, &symm_alg)) {
2618         FFI_LOG(op->ffi, "Invalid cipher: %s", s2k_cipher);
2619         return RNP_ERROR_BAD_PARAMETERS;
2620     }
2621     try {
2622         rnp::secure_vector<char> ask_pass(MAX_PASSWORD_LENGTH, '\0');
2623         if (!password) {
2624             pgp_password_ctx_t pswdctx = {.op = PGP_OP_ENCRYPT_SYM, .key = NULL};
2625             if (!pgp_request_password(
2626                   &op->ffi->pass_provider, &pswdctx, ask_pass.data(), ask_pass.size())) {
2627                 return RNP_ERROR_BAD_PASSWORD;
2628             }
2629             password = ask_pass.data();
2630         }
2631         return rnp_ctx_add_encryption_password(
2632           op->rnpctx, password, hash_alg, symm_alg, iterations);
2633     } catch (const std::exception &e) {
2634         FFI_LOG(op->ffi, "%s", e.what());
2635         return RNP_ERROR_OUT_OF_MEMORY;
2636     }
2637 }
2638 FFI_GUARD
2639 
2640 rnp_result_t
rnp_op_encrypt_set_armor(rnp_op_encrypt_t op,bool armored)2641 rnp_op_encrypt_set_armor(rnp_op_encrypt_t op, bool armored)
2642 try {
2643     // checks
2644     if (!op) {
2645         return RNP_ERROR_NULL_POINTER;
2646     }
2647     return rnp_op_set_armor(op->rnpctx, armored);
2648 }
2649 FFI_GUARD
2650 
2651 rnp_result_t
rnp_op_encrypt_set_cipher(rnp_op_encrypt_t op,const char * cipher)2652 rnp_op_encrypt_set_cipher(rnp_op_encrypt_t op, const char *cipher)
2653 try {
2654     // checks
2655     if (!op || !cipher) {
2656         return RNP_ERROR_NULL_POINTER;
2657     }
2658     if (!str_to_cipher(cipher, &op->rnpctx.ealg)) {
2659         FFI_LOG(op->ffi, "Invalid cipher: %s", cipher);
2660         return RNP_ERROR_BAD_PARAMETERS;
2661     }
2662     return RNP_SUCCESS;
2663 }
2664 FFI_GUARD
2665 
2666 rnp_result_t
rnp_op_encrypt_set_aead(rnp_op_encrypt_t op,const char * alg)2667 rnp_op_encrypt_set_aead(rnp_op_encrypt_t op, const char *alg)
2668 try {
2669     // checks
2670     if (!op || !alg) {
2671         return RNP_ERROR_NULL_POINTER;
2672     }
2673     if (!str_to_aead_alg(alg, &op->rnpctx.aalg)) {
2674         FFI_LOG(op->ffi, "Invalid AEAD algorithm: %s", alg);
2675         return RNP_ERROR_BAD_PARAMETERS;
2676     }
2677     return RNP_SUCCESS;
2678 }
2679 FFI_GUARD
2680 
2681 rnp_result_t
rnp_op_encrypt_set_aead_bits(rnp_op_encrypt_t op,int bits)2682 rnp_op_encrypt_set_aead_bits(rnp_op_encrypt_t op, int bits)
2683 try {
2684     if (!op) {
2685         return RNP_ERROR_NULL_POINTER;
2686     }
2687     if ((bits < 0) || (bits > 56)) {
2688         return RNP_ERROR_BAD_PARAMETERS;
2689     }
2690     op->rnpctx.abits = bits;
2691     return RNP_SUCCESS;
2692 }
2693 FFI_GUARD
2694 
2695 rnp_result_t
rnp_op_encrypt_set_compression(rnp_op_encrypt_t op,const char * compression,int level)2696 rnp_op_encrypt_set_compression(rnp_op_encrypt_t op, const char *compression, int level)
2697 try {
2698     // checks
2699     if (!op) {
2700         return RNP_ERROR_NULL_POINTER;
2701     }
2702     return rnp_op_set_compression(op->ffi, op->rnpctx, compression, level);
2703 }
2704 FFI_GUARD
2705 
2706 rnp_result_t
rnp_op_encrypt_set_file_name(rnp_op_encrypt_t op,const char * filename)2707 rnp_op_encrypt_set_file_name(rnp_op_encrypt_t op, const char *filename)
2708 try {
2709     if (!op) {
2710         return RNP_ERROR_NULL_POINTER;
2711     }
2712     return rnp_op_set_file_name(op->rnpctx, filename);
2713 }
2714 FFI_GUARD
2715 
2716 rnp_result_t
rnp_op_encrypt_set_file_mtime(rnp_op_encrypt_t op,uint32_t mtime)2717 rnp_op_encrypt_set_file_mtime(rnp_op_encrypt_t op, uint32_t mtime)
2718 try {
2719     if (!op) {
2720         return RNP_ERROR_NULL_POINTER;
2721     }
2722     return rnp_op_set_file_mtime(op->rnpctx, mtime);
2723 }
2724 FFI_GUARD
2725 
2726 static pgp_write_handler_t
pgp_write_handler(pgp_password_provider_t * pass_provider,rnp_ctx_t * rnpctx,void * param,pgp_key_provider_t * key_provider)2727 pgp_write_handler(pgp_password_provider_t *pass_provider,
2728                   rnp_ctx_t *              rnpctx,
2729                   void *                   param,
2730                   pgp_key_provider_t *     key_provider)
2731 {
2732     pgp_write_handler_t handler;
2733     memset(&handler, 0, sizeof(handler));
2734     handler.password_provider = pass_provider;
2735     handler.ctx = rnpctx;
2736     handler.param = param;
2737     handler.key_provider = key_provider;
2738     return handler;
2739 }
2740 
2741 static rnp_result_t
rnp_op_add_signatures(rnp_op_sign_signatures_t & opsigs,rnp_ctx_t & ctx)2742 rnp_op_add_signatures(rnp_op_sign_signatures_t &opsigs, rnp_ctx_t &ctx)
2743 {
2744     for (auto &sig : opsigs) {
2745         if (!sig.signer.key) {
2746             return RNP_ERROR_NO_SUITABLE_KEY;
2747         }
2748 
2749         rnp_signer_info_t sinfo = sig.signer;
2750         if (!sig.hash_set) {
2751             sinfo.halg = ctx.halg;
2752         }
2753         if (!sig.expiry_set) {
2754             sinfo.sigexpire = ctx.sigexpire;
2755         }
2756         if (!sig.create_set) {
2757             sinfo.sigcreate = ctx.sigcreate;
2758         }
2759         ctx.signers.push_back(sinfo);
2760     }
2761     return RNP_SUCCESS;
2762 }
2763 
2764 rnp_result_t
rnp_op_encrypt_execute(rnp_op_encrypt_t op)2765 rnp_op_encrypt_execute(rnp_op_encrypt_t op)
2766 try {
2767     // checks
2768     if (!op || !op->input || !op->output) {
2769         return RNP_ERROR_NULL_POINTER;
2770     }
2771 
2772     // set the default hash alg if none was specified
2773     if (!op->rnpctx.halg) {
2774         op->rnpctx.halg = DEFAULT_PGP_HASH_ALG;
2775     }
2776     pgp_write_handler_t handler =
2777       pgp_write_handler(&op->ffi->pass_provider, &op->rnpctx, NULL, &op->ffi->key_provider);
2778 
2779     rnp_result_t ret;
2780     if (!op->signatures.empty()) {
2781         if ((ret = rnp_op_add_signatures(op->signatures, op->rnpctx))) {
2782             return ret;
2783         }
2784         ret = rnp_encrypt_sign_src(&handler, &op->input->src, &op->output->dst);
2785     } else {
2786         ret = rnp_encrypt_src(&handler, &op->input->src, &op->output->dst);
2787     }
2788 
2789     dst_flush(&op->output->dst);
2790     op->output->keep = ret == RNP_SUCCESS;
2791     op->input = NULL;
2792     op->output = NULL;
2793     return ret;
2794 }
2795 FFI_GUARD
2796 
2797 rnp_result_t
rnp_op_encrypt_destroy(rnp_op_encrypt_t op)2798 rnp_op_encrypt_destroy(rnp_op_encrypt_t op)
2799 try {
2800     delete op;
2801     return RNP_SUCCESS;
2802 }
2803 FFI_GUARD
2804 
2805 rnp_result_t
rnp_op_sign_create(rnp_op_sign_t * op,rnp_ffi_t ffi,rnp_input_t input,rnp_output_t output)2806 rnp_op_sign_create(rnp_op_sign_t *op, rnp_ffi_t ffi, rnp_input_t input, rnp_output_t output)
2807 try {
2808     // checks
2809     if (!op || !ffi || !input || !output) {
2810         return RNP_ERROR_NULL_POINTER;
2811     }
2812 
2813     *op = new rnp_op_sign_st();
2814     rnp_ctx_init_ffi((*op)->rnpctx, ffi);
2815     (*op)->ffi = ffi;
2816     (*op)->input = input;
2817     (*op)->output = output;
2818     return RNP_SUCCESS;
2819 }
2820 FFI_GUARD
2821 
2822 rnp_result_t
rnp_op_sign_cleartext_create(rnp_op_sign_t * op,rnp_ffi_t ffi,rnp_input_t input,rnp_output_t output)2823 rnp_op_sign_cleartext_create(rnp_op_sign_t *op,
2824                              rnp_ffi_t      ffi,
2825                              rnp_input_t    input,
2826                              rnp_output_t   output)
2827 try {
2828     rnp_result_t res = rnp_op_sign_create(op, ffi, input, output);
2829     if (!res) {
2830         (*op)->rnpctx.clearsign = true;
2831     }
2832     return res;
2833 }
2834 FFI_GUARD
2835 
2836 rnp_result_t
rnp_op_sign_detached_create(rnp_op_sign_t * op,rnp_ffi_t ffi,rnp_input_t input,rnp_output_t signature)2837 rnp_op_sign_detached_create(rnp_op_sign_t *op,
2838                             rnp_ffi_t      ffi,
2839                             rnp_input_t    input,
2840                             rnp_output_t   signature)
2841 try {
2842     rnp_result_t res = rnp_op_sign_create(op, ffi, input, signature);
2843     if (!res) {
2844         (*op)->rnpctx.detached = true;
2845     }
2846     return res;
2847 }
2848 FFI_GUARD
2849 
2850 rnp_result_t
rnp_op_sign_add_signature(rnp_op_sign_t op,rnp_key_handle_t key,rnp_op_sign_signature_t * sig)2851 rnp_op_sign_add_signature(rnp_op_sign_t op, rnp_key_handle_t key, rnp_op_sign_signature_t *sig)
2852 try {
2853     if (!op) {
2854         return RNP_ERROR_NULL_POINTER;
2855     }
2856     return rnp_op_add_signature(op->ffi, op->signatures, key, op->rnpctx, sig);
2857 }
2858 FFI_GUARD
2859 
2860 rnp_result_t
rnp_op_sign_signature_set_hash(rnp_op_sign_signature_t sig,const char * hash)2861 rnp_op_sign_signature_set_hash(rnp_op_sign_signature_t sig, const char *hash)
2862 try {
2863     if (!sig) {
2864         return RNP_ERROR_NULL_POINTER;
2865     }
2866     if (!str_to_hash_alg(hash, &sig->signer.halg)) {
2867         FFI_LOG(sig->ffi, "Invalid hash: %s", hash);
2868         return RNP_ERROR_BAD_PARAMETERS;
2869     }
2870     sig->hash_set = true;
2871     return RNP_SUCCESS;
2872 }
2873 FFI_GUARD
2874 
2875 rnp_result_t
rnp_op_sign_signature_set_creation_time(rnp_op_sign_signature_t sig,uint32_t create)2876 rnp_op_sign_signature_set_creation_time(rnp_op_sign_signature_t sig, uint32_t create)
2877 try {
2878     if (!sig) {
2879         return RNP_ERROR_NULL_POINTER;
2880     }
2881     sig->signer.sigcreate = create;
2882     sig->create_set = true;
2883     return RNP_SUCCESS;
2884 }
2885 FFI_GUARD
2886 
2887 rnp_result_t
rnp_op_sign_signature_set_expiration_time(rnp_op_sign_signature_t sig,uint32_t expires)2888 rnp_op_sign_signature_set_expiration_time(rnp_op_sign_signature_t sig, uint32_t expires)
2889 try {
2890     if (!sig) {
2891         return RNP_ERROR_NULL_POINTER;
2892     }
2893     sig->signer.sigexpire = expires;
2894     sig->expiry_set = true;
2895     return RNP_SUCCESS;
2896 }
2897 FFI_GUARD
2898 
2899 rnp_result_t
rnp_op_sign_set_armor(rnp_op_sign_t op,bool armored)2900 rnp_op_sign_set_armor(rnp_op_sign_t op, bool armored)
2901 try {
2902     if (!op) {
2903         return RNP_ERROR_NULL_POINTER;
2904     }
2905     return rnp_op_set_armor(op->rnpctx, armored);
2906 }
2907 FFI_GUARD
2908 
2909 rnp_result_t
rnp_op_sign_set_compression(rnp_op_sign_t op,const char * compression,int level)2910 rnp_op_sign_set_compression(rnp_op_sign_t op, const char *compression, int level)
2911 try {
2912     if (!op) {
2913         return RNP_ERROR_NULL_POINTER;
2914     }
2915     return rnp_op_set_compression(op->ffi, op->rnpctx, compression, level);
2916 }
2917 FFI_GUARD
2918 
2919 rnp_result_t
rnp_op_sign_set_hash(rnp_op_sign_t op,const char * hash)2920 rnp_op_sign_set_hash(rnp_op_sign_t op, const char *hash)
2921 try {
2922     if (!op) {
2923         return RNP_ERROR_NULL_POINTER;
2924     }
2925     return rnp_op_set_hash(op->ffi, op->rnpctx, hash);
2926 }
2927 FFI_GUARD
2928 
2929 rnp_result_t
rnp_op_sign_set_creation_time(rnp_op_sign_t op,uint32_t create)2930 rnp_op_sign_set_creation_time(rnp_op_sign_t op, uint32_t create)
2931 try {
2932     if (!op) {
2933         return RNP_ERROR_NULL_POINTER;
2934     }
2935     return rnp_op_set_creation_time(op->rnpctx, create);
2936 }
2937 FFI_GUARD
2938 
2939 rnp_result_t
rnp_op_sign_set_expiration_time(rnp_op_sign_t op,uint32_t expire)2940 rnp_op_sign_set_expiration_time(rnp_op_sign_t op, uint32_t expire)
2941 try {
2942     if (!op) {
2943         return RNP_ERROR_NULL_POINTER;
2944     }
2945     return rnp_op_set_expiration_time(op->rnpctx, expire);
2946 }
2947 FFI_GUARD
2948 
2949 rnp_result_t
rnp_op_sign_set_file_name(rnp_op_sign_t op,const char * filename)2950 rnp_op_sign_set_file_name(rnp_op_sign_t op, const char *filename)
2951 try {
2952     if (!op) {
2953         return RNP_ERROR_NULL_POINTER;
2954     }
2955     return rnp_op_set_file_name(op->rnpctx, filename);
2956 }
2957 FFI_GUARD
2958 
2959 rnp_result_t
rnp_op_sign_set_file_mtime(rnp_op_sign_t op,uint32_t mtime)2960 rnp_op_sign_set_file_mtime(rnp_op_sign_t op, uint32_t mtime)
2961 try {
2962     if (!op) {
2963         return RNP_ERROR_NULL_POINTER;
2964     }
2965     return rnp_op_set_file_mtime(op->rnpctx, mtime);
2966 }
2967 FFI_GUARD
2968 
2969 rnp_result_t
rnp_op_sign_execute(rnp_op_sign_t op)2970 rnp_op_sign_execute(rnp_op_sign_t op)
2971 try {
2972     // checks
2973     if (!op || !op->input || !op->output) {
2974         return RNP_ERROR_NULL_POINTER;
2975     }
2976 
2977     // set the default hash alg if none was specified
2978     if (!op->rnpctx.halg) {
2979         op->rnpctx.halg = DEFAULT_PGP_HASH_ALG;
2980     }
2981     pgp_write_handler_t handler =
2982       pgp_write_handler(&op->ffi->pass_provider, &op->rnpctx, NULL, &op->ffi->key_provider);
2983 
2984     rnp_result_t ret;
2985     if ((ret = rnp_op_add_signatures(op->signatures, op->rnpctx))) {
2986         return ret;
2987     }
2988     ret = rnp_sign_src(&handler, &op->input->src, &op->output->dst);
2989 
2990     dst_flush(&op->output->dst);
2991     op->output->keep = ret == RNP_SUCCESS;
2992     op->input = NULL;
2993     op->output = NULL;
2994     return ret;
2995 }
2996 FFI_GUARD
2997 
2998 rnp_result_t
rnp_op_sign_destroy(rnp_op_sign_t op)2999 rnp_op_sign_destroy(rnp_op_sign_t op)
3000 try {
3001     delete op;
3002     return RNP_SUCCESS;
3003 }
3004 FFI_GUARD
3005 
3006 static void
rnp_op_verify_on_signatures(const std::vector<pgp_signature_info_t> & sigs,void * param)3007 rnp_op_verify_on_signatures(const std::vector<pgp_signature_info_t> &sigs, void *param)
3008 {
3009     rnp_op_verify_t op = (rnp_op_verify_t) param;
3010 
3011     try {
3012         /* in case we have multiple signed layers */
3013         delete[] op->signatures;
3014         op->signatures = new rnp_op_verify_signature_st[sigs.size()];
3015     } catch (const std::exception &e) {
3016         FFI_LOG(op->ffi, "%s", e.what());
3017         return;
3018     }
3019     op->signature_count = sigs.size();
3020 
3021     size_t i = 0;
3022     for (const auto &sinfo : sigs) {
3023         rnp_op_verify_signature_t res = &op->signatures[i++];
3024         /* sinfo.sig may be NULL */
3025         if (sinfo.sig) {
3026             try {
3027                 res->sig_pkt = *sinfo.sig;
3028             } catch (const std::exception &e) {
3029                 FFI_LOG(op->ffi, "%s", e.what());
3030             }
3031         }
3032 
3033         if (sinfo.unknown) {
3034             res->verify_status = RNP_ERROR_SIGNATURE_INVALID;
3035         } else if (sinfo.valid) {
3036             res->verify_status = sinfo.expired ? RNP_ERROR_SIGNATURE_EXPIRED : RNP_SUCCESS;
3037         } else {
3038             res->verify_status =
3039               sinfo.no_signer ? RNP_ERROR_KEY_NOT_FOUND : RNP_ERROR_SIGNATURE_INVALID;
3040         }
3041         res->ffi = op->ffi;
3042     }
3043 }
3044 
3045 static bool
rnp_verify_src_provider(pgp_parse_handler_t * handler,pgp_source_t * src)3046 rnp_verify_src_provider(pgp_parse_handler_t *handler, pgp_source_t *src)
3047 {
3048     /* this one is called only when input for detached signature is needed */
3049     rnp_op_verify_t op = (rnp_op_verify_t) handler->param;
3050     if (!op->detached_input) {
3051         return false;
3052     }
3053     *src = op->detached_input->src;
3054     /* we should give ownership on src to caller */
3055     memset(&op->detached_input->src, 0, sizeof(op->detached_input->src));
3056     return true;
3057 };
3058 
3059 static bool
rnp_verify_dest_provider(pgp_parse_handler_t * handler,pgp_dest_t ** dst,bool * closedst,const char * filename,uint32_t mtime)3060 rnp_verify_dest_provider(pgp_parse_handler_t *handler,
3061                          pgp_dest_t **        dst,
3062                          bool *               closedst,
3063                          const char *         filename,
3064                          uint32_t             mtime)
3065 {
3066     rnp_op_verify_t op = (rnp_op_verify_t) handler->param;
3067     if (!op->output) {
3068         return false;
3069     }
3070     *dst = &(op->output->dst);
3071     *closedst = false;
3072     op->filename = filename ? strdup(filename) : NULL;
3073     op->file_mtime = mtime;
3074     return true;
3075 }
3076 
3077 static void
recipient_handle_from_pk_sesskey(rnp_recipient_handle_t handle,const pgp_pk_sesskey_t & sesskey)3078 recipient_handle_from_pk_sesskey(rnp_recipient_handle_t  handle,
3079                                  const pgp_pk_sesskey_t &sesskey)
3080 {
3081     static_assert(sizeof(handle->keyid) == PGP_KEY_ID_SIZE, "Keyid size mismatch");
3082     memcpy(handle->keyid, sesskey.key_id.data(), PGP_KEY_ID_SIZE);
3083     handle->palg = sesskey.alg;
3084 }
3085 
3086 static void
symenc_handle_from_sk_sesskey(rnp_symenc_handle_t handle,const pgp_sk_sesskey_t & sesskey)3087 symenc_handle_from_sk_sesskey(rnp_symenc_handle_t handle, const pgp_sk_sesskey_t &sesskey)
3088 {
3089     handle->alg = sesskey.alg;
3090     handle->halg = sesskey.s2k.hash_alg;
3091     handle->s2k_type = sesskey.s2k.specifier;
3092     if (sesskey.s2k.specifier == PGP_S2KS_ITERATED_AND_SALTED) {
3093         handle->iterations = pgp_s2k_decode_iterations(sesskey.s2k.iterations);
3094     } else {
3095         handle->iterations = 1;
3096     }
3097     handle->aalg = sesskey.aalg;
3098 }
3099 
3100 static void
rnp_verify_on_recipients(const std::vector<pgp_pk_sesskey_t> & recipients,const std::vector<pgp_sk_sesskey_t> & passwords,void * param)3101 rnp_verify_on_recipients(const std::vector<pgp_pk_sesskey_t> &recipients,
3102                          const std::vector<pgp_sk_sesskey_t> &passwords,
3103                          void *                               param)
3104 {
3105     rnp_op_verify_t op = (rnp_op_verify_t) param;
3106     /* store only top-level encrypted stream recipients info for now */
3107     if (op->encrypted_layers++) {
3108         return;
3109     }
3110     if (!recipients.empty()) {
3111         op->recipients =
3112           (rnp_recipient_handle_t) calloc(recipients.size(), sizeof(*op->recipients));
3113         if (!op->recipients) {
3114             FFI_LOG(op->ffi, "allocation failed");
3115             return;
3116         }
3117         for (size_t i = 0; i < recipients.size(); i++) {
3118             recipient_handle_from_pk_sesskey(&op->recipients[i], recipients[i]);
3119         }
3120     }
3121     op->recipient_count = recipients.size();
3122     if (!passwords.empty()) {
3123         op->symencs = (rnp_symenc_handle_t) calloc(passwords.size(), sizeof(*op->symencs));
3124         if (!op->symencs) {
3125             FFI_LOG(op->ffi, "allocation failed");
3126             return;
3127         }
3128         for (size_t i = 0; i < passwords.size(); i++) {
3129             symenc_handle_from_sk_sesskey(&op->symencs[i], passwords[i]);
3130         }
3131     }
3132     op->symenc_count = passwords.size();
3133 }
3134 
3135 static void
rnp_verify_on_decryption_start(pgp_pk_sesskey_t * pubenc,pgp_sk_sesskey_t * symenc,void * param)3136 rnp_verify_on_decryption_start(pgp_pk_sesskey_t *pubenc, pgp_sk_sesskey_t *symenc, void *param)
3137 {
3138     rnp_op_verify_t op = (rnp_op_verify_t) param;
3139     /* store only top-level encrypted stream info */
3140     if (op->encrypted_layers > 1) {
3141         return;
3142     }
3143     if (pubenc) {
3144         op->used_recipient = (rnp_recipient_handle_t) calloc(1, sizeof(*op->used_recipient));
3145         if (!op->used_recipient) {
3146             FFI_LOG(op->ffi, "allocation failed");
3147             return;
3148         }
3149         recipient_handle_from_pk_sesskey(op->used_recipient, *pubenc);
3150         return;
3151     }
3152     if (symenc) {
3153         op->used_symenc = (rnp_symenc_handle_t) calloc(1, sizeof(*op->used_symenc));
3154         if (!op->used_symenc) {
3155             FFI_LOG(op->ffi, "allocation failed");
3156             return;
3157         }
3158         symenc_handle_from_sk_sesskey(op->used_symenc, *symenc);
3159         return;
3160     }
3161     FFI_LOG(op->ffi, "Warning! Both pubenc and symenc are NULL.");
3162 }
3163 
3164 static void
rnp_verify_on_decryption_info(bool mdc,pgp_aead_alg_t aead,pgp_symm_alg_t salg,void * param)3165 rnp_verify_on_decryption_info(bool mdc, pgp_aead_alg_t aead, pgp_symm_alg_t salg, void *param)
3166 {
3167     rnp_op_verify_t op = (rnp_op_verify_t) param;
3168     /* store only top-level encrypted stream info for now */
3169     if (op->encrypted_layers > 1) {
3170         return;
3171     }
3172     op->mdc = mdc;
3173     op->aead = aead;
3174     op->salg = salg;
3175     op->encrypted = true;
3176 }
3177 
3178 static void
rnp_verify_on_decryption_done(bool validated,void * param)3179 rnp_verify_on_decryption_done(bool validated, void *param)
3180 {
3181     rnp_op_verify_t op = (rnp_op_verify_t) param;
3182     if (op->encrypted_layers > 1) {
3183         return;
3184     }
3185     op->validated = validated;
3186 }
3187 
3188 rnp_result_t
rnp_op_verify_create(rnp_op_verify_t * op,rnp_ffi_t ffi,rnp_input_t input,rnp_output_t output)3189 rnp_op_verify_create(rnp_op_verify_t *op,
3190                      rnp_ffi_t        ffi,
3191                      rnp_input_t      input,
3192                      rnp_output_t     output)
3193 try {
3194     if (!op || !ffi || !input || !output) {
3195         return RNP_ERROR_NULL_POINTER;
3196     }
3197 
3198     *op = new rnp_op_verify_st();
3199     rnp_ctx_init_ffi((*op)->rnpctx, ffi);
3200     (*op)->ffi = ffi;
3201     (*op)->input = input;
3202     (*op)->output = output;
3203 
3204     return RNP_SUCCESS;
3205 }
3206 FFI_GUARD
3207 
3208 rnp_result_t
rnp_op_verify_detached_create(rnp_op_verify_t * op,rnp_ffi_t ffi,rnp_input_t input,rnp_input_t signature)3209 rnp_op_verify_detached_create(rnp_op_verify_t *op,
3210                               rnp_ffi_t        ffi,
3211                               rnp_input_t      input,
3212                               rnp_input_t      signature)
3213 try {
3214     if (!op || !ffi || !input || !signature) {
3215         return RNP_ERROR_NULL_POINTER;
3216     }
3217 
3218     *op = new rnp_op_verify_st();
3219     rnp_ctx_init_ffi((*op)->rnpctx, ffi);
3220     (*op)->rnpctx.detached = true;
3221     (*op)->ffi = ffi;
3222     (*op)->input = signature;
3223     (*op)->detached_input = input;
3224 
3225     return RNP_SUCCESS;
3226 }
3227 FFI_GUARD
3228 
3229 rnp_result_t
rnp_op_verify_execute(rnp_op_verify_t op)3230 rnp_op_verify_execute(rnp_op_verify_t op)
3231 try {
3232     if (!op) {
3233         return RNP_ERROR_NULL_POINTER;
3234     }
3235 
3236     pgp_parse_handler_t handler;
3237 
3238     handler.password_provider = &op->ffi->pass_provider;
3239     handler.key_provider = &op->ffi->key_provider;
3240     handler.on_signatures = rnp_op_verify_on_signatures;
3241     handler.src_provider = rnp_verify_src_provider;
3242     handler.dest_provider = rnp_verify_dest_provider;
3243     handler.on_recipients = rnp_verify_on_recipients;
3244     handler.on_decryption_start = rnp_verify_on_decryption_start;
3245     handler.on_decryption_info = rnp_verify_on_decryption_info;
3246     handler.on_decryption_done = rnp_verify_on_decryption_done;
3247     handler.param = op;
3248     handler.ctx = &op->rnpctx;
3249 
3250     rnp_result_t ret = process_pgp_source(&handler, op->input->src);
3251     if (op->output) {
3252         dst_flush(&op->output->dst);
3253         op->output->keep = ret == RNP_SUCCESS;
3254     }
3255     return ret;
3256 }
3257 FFI_GUARD
3258 
3259 rnp_result_t
rnp_op_verify_get_signature_count(rnp_op_verify_t op,size_t * count)3260 rnp_op_verify_get_signature_count(rnp_op_verify_t op, size_t *count)
3261 try {
3262     if (!op || !count) {
3263         return RNP_ERROR_NULL_POINTER;
3264     }
3265 
3266     *count = op->signature_count;
3267     return RNP_SUCCESS;
3268 }
3269 FFI_GUARD
3270 
3271 rnp_result_t
rnp_op_verify_get_signature_at(rnp_op_verify_t op,size_t idx,rnp_op_verify_signature_t * sig)3272 rnp_op_verify_get_signature_at(rnp_op_verify_t op, size_t idx, rnp_op_verify_signature_t *sig)
3273 try {
3274     if (!op || !sig) {
3275         return RNP_ERROR_NULL_POINTER;
3276     }
3277     if (idx >= op->signature_count) {
3278         FFI_LOG(op->ffi, "Invalid signature index: %zu", idx);
3279         return RNP_ERROR_BAD_PARAMETERS;
3280     }
3281     *sig = &op->signatures[idx];
3282     return RNP_SUCCESS;
3283 }
3284 FFI_GUARD
3285 
3286 rnp_result_t
rnp_op_verify_get_file_info(rnp_op_verify_t op,char ** filename,uint32_t * mtime)3287 rnp_op_verify_get_file_info(rnp_op_verify_t op, char **filename, uint32_t *mtime)
3288 try {
3289     if (!op) {
3290         return RNP_ERROR_NULL_POINTER;
3291     }
3292     if (mtime) {
3293         *mtime = op->file_mtime;
3294     }
3295     if (filename) {
3296         if (op->filename) {
3297             *filename = strdup(op->filename);
3298         } else {
3299             *filename = NULL;
3300         }
3301     }
3302     return RNP_SUCCESS;
3303 }
3304 FFI_GUARD
3305 
3306 static const char *
get_protection_mode(rnp_op_verify_t op)3307 get_protection_mode(rnp_op_verify_t op)
3308 {
3309     if (!op->encrypted) {
3310         return "none";
3311     }
3312     if (op->mdc) {
3313         return "cfb-mdc";
3314     }
3315     if (op->aead == PGP_AEAD_NONE) {
3316         return "cfb";
3317     }
3318     switch (op->aead) {
3319     case PGP_AEAD_EAX:
3320         return "aead-eax";
3321     case PGP_AEAD_OCB:
3322         return "aead-ocb";
3323     default:
3324         return "aead-unknown";
3325     }
3326 }
3327 
3328 static const char *
get_protection_cipher(rnp_op_verify_t op)3329 get_protection_cipher(rnp_op_verify_t op)
3330 {
3331     if (!op->encrypted) {
3332         return "none";
3333     }
3334     return id_str_pair::lookup(symm_alg_map, op->salg);
3335 }
3336 
3337 rnp_result_t
rnp_op_verify_get_protection_info(rnp_op_verify_t op,char ** mode,char ** cipher,bool * valid)3338 rnp_op_verify_get_protection_info(rnp_op_verify_t op, char **mode, char **cipher, bool *valid)
3339 try {
3340     if (!op || (!mode && !cipher && !valid)) {
3341         return RNP_ERROR_NULL_POINTER;
3342     }
3343 
3344     if (mode) {
3345         *mode = strdup(get_protection_mode(op));
3346         if (!*mode) {
3347             return RNP_ERROR_OUT_OF_MEMORY;
3348         }
3349     }
3350     if (cipher) {
3351         *cipher = strdup(get_protection_cipher(op));
3352         if (!*cipher) {
3353             return RNP_ERROR_OUT_OF_MEMORY;
3354         }
3355     }
3356     if (valid) {
3357         *valid = op->validated;
3358     }
3359     return RNP_SUCCESS;
3360 }
3361 FFI_GUARD
3362 
3363 rnp_result_t
rnp_op_verify_get_recipient_count(rnp_op_verify_t op,size_t * count)3364 rnp_op_verify_get_recipient_count(rnp_op_verify_t op, size_t *count)
3365 try {
3366     if (!op || !count) {
3367         return RNP_ERROR_NULL_POINTER;
3368     }
3369     *count = op->recipient_count;
3370     return RNP_SUCCESS;
3371 }
3372 FFI_GUARD
3373 
3374 rnp_result_t
rnp_op_verify_get_used_recipient(rnp_op_verify_t op,rnp_recipient_handle_t * recipient)3375 rnp_op_verify_get_used_recipient(rnp_op_verify_t op, rnp_recipient_handle_t *recipient)
3376 try {
3377     if (!op || !recipient) {
3378         return RNP_ERROR_NULL_POINTER;
3379     }
3380     *recipient = op->used_recipient;
3381     return RNP_SUCCESS;
3382 }
3383 FFI_GUARD
3384 
3385 rnp_result_t
rnp_op_verify_get_recipient_at(rnp_op_verify_t op,size_t idx,rnp_recipient_handle_t * recipient)3386 rnp_op_verify_get_recipient_at(rnp_op_verify_t         op,
3387                                size_t                  idx,
3388                                rnp_recipient_handle_t *recipient)
3389 try {
3390     if (!op || !recipient) {
3391         return RNP_ERROR_NULL_POINTER;
3392     }
3393     if (idx >= op->recipient_count) {
3394         return RNP_ERROR_BAD_PARAMETERS;
3395     }
3396     *recipient = &op->recipients[idx];
3397     return RNP_SUCCESS;
3398 }
3399 FFI_GUARD
3400 
3401 rnp_result_t
rnp_recipient_get_keyid(rnp_recipient_handle_t recipient,char ** keyid)3402 rnp_recipient_get_keyid(rnp_recipient_handle_t recipient, char **keyid)
3403 try {
3404     if (!recipient || !keyid) {
3405         return RNP_ERROR_NULL_POINTER;
3406     }
3407     static_assert(sizeof(recipient->keyid) == PGP_KEY_ID_SIZE,
3408                   "rnp_recipient_handle_t.keyid size mismatch");
3409     return hex_encode_value(recipient->keyid, PGP_KEY_ID_SIZE, keyid);
3410 }
3411 FFI_GUARD
3412 
3413 rnp_result_t
rnp_recipient_get_alg(rnp_recipient_handle_t recipient,char ** alg)3414 rnp_recipient_get_alg(rnp_recipient_handle_t recipient, char **alg)
3415 try {
3416     if (!recipient || !alg) {
3417         return RNP_ERROR_NULL_POINTER;
3418     }
3419     return get_map_value(pubkey_alg_map, recipient->palg, alg);
3420 }
3421 FFI_GUARD
3422 
3423 rnp_result_t
rnp_op_verify_get_symenc_count(rnp_op_verify_t op,size_t * count)3424 rnp_op_verify_get_symenc_count(rnp_op_verify_t op, size_t *count)
3425 try {
3426     if (!op || !count) {
3427         return RNP_ERROR_NULL_POINTER;
3428     }
3429     *count = op->symenc_count;
3430     return RNP_SUCCESS;
3431 }
3432 FFI_GUARD
3433 
3434 rnp_result_t
rnp_op_verify_get_used_symenc(rnp_op_verify_t op,rnp_symenc_handle_t * symenc)3435 rnp_op_verify_get_used_symenc(rnp_op_verify_t op, rnp_symenc_handle_t *symenc)
3436 try {
3437     if (!op || !symenc) {
3438         return RNP_ERROR_NULL_POINTER;
3439     }
3440     *symenc = op->used_symenc;
3441     return RNP_SUCCESS;
3442 }
3443 FFI_GUARD
3444 
3445 rnp_result_t
rnp_op_verify_get_symenc_at(rnp_op_verify_t op,size_t idx,rnp_symenc_handle_t * symenc)3446 rnp_op_verify_get_symenc_at(rnp_op_verify_t op, size_t idx, rnp_symenc_handle_t *symenc)
3447 try {
3448     if (!op || !symenc) {
3449         return RNP_ERROR_NULL_POINTER;
3450     }
3451     if (idx >= op->symenc_count) {
3452         return RNP_ERROR_BAD_PARAMETERS;
3453     }
3454     *symenc = &op->symencs[idx];
3455     return RNP_SUCCESS;
3456 }
3457 FFI_GUARD
3458 
3459 rnp_result_t
rnp_symenc_get_cipher(rnp_symenc_handle_t symenc,char ** cipher)3460 rnp_symenc_get_cipher(rnp_symenc_handle_t symenc, char **cipher)
3461 try {
3462     if (!symenc || !cipher) {
3463         return RNP_ERROR_NULL_POINTER;
3464     }
3465     return get_map_value(symm_alg_map, symenc->alg, cipher);
3466 }
3467 FFI_GUARD
3468 
3469 rnp_result_t
rnp_symenc_get_aead_alg(rnp_symenc_handle_t symenc,char ** alg)3470 rnp_symenc_get_aead_alg(rnp_symenc_handle_t symenc, char **alg)
3471 try {
3472     if (!symenc || !alg) {
3473         return RNP_ERROR_NULL_POINTER;
3474     }
3475     return get_map_value(aead_alg_map, symenc->aalg, alg);
3476 }
3477 FFI_GUARD
3478 
3479 rnp_result_t
rnp_symenc_get_hash_alg(rnp_symenc_handle_t symenc,char ** alg)3480 rnp_symenc_get_hash_alg(rnp_symenc_handle_t symenc, char **alg)
3481 try {
3482     if (!symenc || !alg) {
3483         return RNP_ERROR_NULL_POINTER;
3484     }
3485     return get_map_value(hash_alg_map, symenc->halg, alg);
3486 }
3487 FFI_GUARD
3488 
3489 rnp_result_t
rnp_symenc_get_s2k_type(rnp_symenc_handle_t symenc,char ** type)3490 rnp_symenc_get_s2k_type(rnp_symenc_handle_t symenc, char **type)
3491 try {
3492     if (!symenc || !type) {
3493         return RNP_ERROR_NULL_POINTER;
3494     }
3495     return get_map_value(s2k_type_map, symenc->s2k_type, type);
3496 }
3497 FFI_GUARD
3498 
3499 rnp_result_t
rnp_symenc_get_s2k_iterations(rnp_symenc_handle_t symenc,uint32_t * iterations)3500 rnp_symenc_get_s2k_iterations(rnp_symenc_handle_t symenc, uint32_t *iterations)
3501 try {
3502     if (!symenc || !iterations) {
3503         return RNP_ERROR_NULL_POINTER;
3504     }
3505     *iterations = symenc->iterations;
3506     return RNP_SUCCESS;
3507 }
3508 FFI_GUARD
3509 
3510 rnp_result_t
rnp_op_verify_destroy(rnp_op_verify_t op)3511 rnp_op_verify_destroy(rnp_op_verify_t op)
3512 try {
3513     delete op;
3514     return RNP_SUCCESS;
3515 }
3516 FFI_GUARD
3517 
~rnp_op_verify_st()3518 rnp_op_verify_st::~rnp_op_verify_st()
3519 {
3520     delete[] signatures;
3521     free(filename);
3522     free(recipients);
3523     free(used_recipient);
3524     free(symencs);
3525     free(used_symenc);
3526 }
3527 
3528 rnp_result_t
rnp_op_verify_signature_get_status(rnp_op_verify_signature_t sig)3529 rnp_op_verify_signature_get_status(rnp_op_verify_signature_t sig)
3530 try {
3531     if (!sig) {
3532         return RNP_ERROR_NULL_POINTER;
3533     }
3534     return sig->verify_status;
3535 }
3536 FFI_GUARD
3537 
3538 rnp_result_t
rnp_op_verify_signature_get_handle(rnp_op_verify_signature_t sig,rnp_signature_handle_t * handle)3539 rnp_op_verify_signature_get_handle(rnp_op_verify_signature_t sig,
3540                                    rnp_signature_handle_t *  handle)
3541 try {
3542     if (!sig || !handle) {
3543         return RNP_ERROR_NULL_POINTER;
3544     }
3545 
3546     *handle = (rnp_signature_handle_t) calloc(1, sizeof(**handle));
3547     if (!*handle) {
3548         return RNP_ERROR_OUT_OF_MEMORY;
3549     }
3550 
3551     try {
3552         (*handle)->sig = new pgp_subsig_t(sig->sig_pkt);
3553     } catch (const std::exception &e) {
3554         FFI_LOG(sig->ffi, "%s", e.what());
3555         free(*handle);
3556         return RNP_ERROR_OUT_OF_MEMORY;
3557     }
3558     (*handle)->ffi = sig->ffi;
3559     (*handle)->key = NULL;
3560     (*handle)->own_sig = true;
3561     return RNP_SUCCESS;
3562 }
3563 FFI_GUARD
3564 
3565 rnp_result_t
rnp_op_verify_signature_get_hash(rnp_op_verify_signature_t sig,char ** hash)3566 rnp_op_verify_signature_get_hash(rnp_op_verify_signature_t sig, char **hash)
3567 try {
3568     if (!sig || !hash) {
3569         return RNP_ERROR_NULL_POINTER;
3570     }
3571     return get_map_value(hash_alg_map, sig->sig_pkt.halg, hash);
3572 }
3573 FFI_GUARD
3574 
3575 rnp_result_t
rnp_op_verify_signature_get_key(rnp_op_verify_signature_t sig,rnp_key_handle_t * key)3576 rnp_op_verify_signature_get_key(rnp_op_verify_signature_t sig, rnp_key_handle_t *key)
3577 try {
3578     rnp_ffi_t        ffi = sig->ffi;
3579     pgp_key_search_t search = {};
3580 
3581     if (!sig->sig_pkt.has_keyid()) {
3582         return RNP_ERROR_BAD_PARAMETERS;
3583     }
3584     search.by.keyid = sig->sig_pkt.keyid();
3585     // create a search (since we'll use this later anyways)
3586     search.type = PGP_KEY_SEARCH_KEYID;
3587 
3588     // search the stores
3589     pgp_key_t *pub = rnp_key_store_search(ffi->pubring, &search, NULL);
3590     pgp_key_t *sec = rnp_key_store_search(ffi->secring, &search, NULL);
3591     if (!pub && !sec) {
3592         return RNP_ERROR_KEY_NOT_FOUND;
3593     }
3594 
3595     struct rnp_key_handle_st *handle = (rnp_key_handle_st *) calloc(1, sizeof(*handle));
3596     if (!handle) {
3597         return RNP_ERROR_OUT_OF_MEMORY;
3598     }
3599     handle->ffi = ffi;
3600     handle->pub = pub;
3601     handle->sec = sec;
3602     handle->locator = search;
3603     *key = handle;
3604     return RNP_SUCCESS;
3605 }
3606 FFI_GUARD
3607 
3608 rnp_result_t
rnp_op_verify_signature_get_times(rnp_op_verify_signature_t sig,uint32_t * create,uint32_t * expires)3609 rnp_op_verify_signature_get_times(rnp_op_verify_signature_t sig,
3610                                   uint32_t *                create,
3611                                   uint32_t *                expires)
3612 try {
3613     if (create) {
3614         *create = sig->sig_pkt.creation();
3615     }
3616     if (expires) {
3617         *expires = sig->sig_pkt.expiration();
3618     }
3619 
3620     return RNP_SUCCESS;
3621 }
3622 FFI_GUARD
3623 
3624 static bool
rnp_decrypt_dest_provider(pgp_parse_handler_t * handler,pgp_dest_t ** dst,bool * closedst,const char * filename,uint32_t mtime)3625 rnp_decrypt_dest_provider(pgp_parse_handler_t *handler,
3626                           pgp_dest_t **        dst,
3627                           bool *               closedst,
3628                           const char *         filename,
3629                           uint32_t             mtime)
3630 {
3631     *dst = &((rnp_output_t) handler->param)->dst;
3632     *closedst = false;
3633     return true;
3634 }
3635 
3636 rnp_result_t
rnp_decrypt(rnp_ffi_t ffi,rnp_input_t input,rnp_output_t output)3637 rnp_decrypt(rnp_ffi_t ffi, rnp_input_t input, rnp_output_t output)
3638 try {
3639     // checks
3640     if (!ffi || !input || !output) {
3641         return RNP_ERROR_NULL_POINTER;
3642     }
3643 
3644     rnp_ctx_t rnpctx;
3645     rnp_ctx_init_ffi(rnpctx, ffi);
3646     pgp_parse_handler_t handler;
3647     memset(&handler, 0, sizeof(handler));
3648     handler.password_provider = &ffi->pass_provider;
3649     handler.key_provider = &ffi->key_provider;
3650     handler.dest_provider = rnp_decrypt_dest_provider;
3651     handler.param = output;
3652     handler.ctx = &rnpctx;
3653 
3654     rnp_result_t ret = process_pgp_source(&handler, input->src);
3655     dst_flush(&output->dst);
3656     output->keep = (ret == RNP_SUCCESS);
3657     return ret;
3658 }
3659 FFI_GUARD
3660 
3661 static rnp_result_t
str_to_locator(rnp_ffi_t ffi,pgp_key_search_t * locator,const char * identifier_type,const char * identifier)3662 str_to_locator(rnp_ffi_t         ffi,
3663                pgp_key_search_t *locator,
3664                const char *      identifier_type,
3665                const char *      identifier)
3666 {
3667     // parse the identifier type
3668     locator->type = static_cast<pgp_key_search_type_t>(
3669       id_str_pair::lookup(identifier_type_map, identifier_type, PGP_KEY_SEARCH_UNKNOWN));
3670     if (locator->type == PGP_KEY_SEARCH_UNKNOWN) {
3671         FFI_LOG(ffi, "Invalid identifier type: %s", identifier_type);
3672         return RNP_ERROR_BAD_PARAMETERS;
3673     }
3674     // see what type we have
3675     switch (locator->type) {
3676     case PGP_KEY_SEARCH_USERID:
3677         if (snprintf(locator->by.userid, sizeof(locator->by.userid), "%s", identifier) >=
3678             (int) sizeof(locator->by.userid)) {
3679             FFI_LOG(ffi, "UserID too long");
3680             return RNP_ERROR_BAD_PARAMETERS;
3681         }
3682         break;
3683     case PGP_KEY_SEARCH_KEYID: {
3684         if (strlen(identifier) != (PGP_KEY_ID_SIZE * 2) ||
3685             !rnp::hex_decode(identifier, locator->by.keyid.data(), locator->by.keyid.size())) {
3686             FFI_LOG(ffi, "Invalid keyid: %s", identifier);
3687             return RNP_ERROR_BAD_PARAMETERS;
3688         }
3689     } break;
3690     case PGP_KEY_SEARCH_FINGERPRINT: {
3691         // TODO: support v5 fingerprints
3692         // Note: v2/v3 fingerprint are 16 bytes (32 chars) long.
3693         if ((strlen(identifier) != (PGP_FINGERPRINT_SIZE * 2)) && (strlen(identifier) != 32)) {
3694             FFI_LOG(ffi, "Invalid fingerprint: %s", identifier);
3695             return RNP_ERROR_BAD_PARAMETERS;
3696         }
3697         locator->by.fingerprint.length = rnp::hex_decode(
3698           identifier, locator->by.fingerprint.fingerprint, PGP_FINGERPRINT_SIZE);
3699         if (!locator->by.fingerprint.length) {
3700             FFI_LOG(ffi, "Invalid fingerprint: %s", identifier);
3701             return RNP_ERROR_BAD_PARAMETERS;
3702         }
3703     } break;
3704     case PGP_KEY_SEARCH_GRIP: {
3705         if (strlen(identifier) != (PGP_KEY_GRIP_SIZE * 2) ||
3706             !rnp::hex_decode(identifier, locator->by.grip.data(), locator->by.grip.size())) {
3707             FFI_LOG(ffi, "Invalid grip: %s", identifier);
3708             return RNP_ERROR_BAD_PARAMETERS;
3709         }
3710     } break;
3711     default:
3712         // should never happen
3713         assert(false);
3714         return RNP_ERROR_BAD_STATE;
3715     }
3716     return RNP_SUCCESS;
3717 }
3718 
3719 static bool
locator_to_str(const pgp_key_search_t * locator,const char ** identifier_type,char * identifier,size_t identifier_size)3720 locator_to_str(const pgp_key_search_t *locator,
3721                const char **           identifier_type,
3722                char *                  identifier,
3723                size_t                  identifier_size)
3724 {
3725     // find the identifier type string with the map
3726     *identifier_type = id_str_pair::lookup(identifier_type_map, locator->type, NULL);
3727     if (!*identifier_type) {
3728         return false;
3729     }
3730     // fill in the actual identifier
3731     switch (locator->type) {
3732     case PGP_KEY_SEARCH_USERID:
3733         if (snprintf(identifier, identifier_size, "%s", locator->by.userid) >=
3734             (int) identifier_size) {
3735             return false;
3736         }
3737         break;
3738     case PGP_KEY_SEARCH_KEYID:
3739         if (!rnp::hex_encode(locator->by.keyid.data(),
3740                              locator->by.keyid.size(),
3741                              identifier,
3742                              identifier_size)) {
3743             return false;
3744         }
3745         break;
3746     case PGP_KEY_SEARCH_FINGERPRINT:
3747         if (!rnp::hex_encode(locator->by.fingerprint.fingerprint,
3748                              locator->by.fingerprint.length,
3749                              identifier,
3750                              identifier_size)) {
3751             return false;
3752         }
3753         break;
3754     case PGP_KEY_SEARCH_GRIP:
3755         if (!rnp::hex_encode(
3756               locator->by.grip.data(), locator->by.grip.size(), identifier, identifier_size)) {
3757             return false;
3758         }
3759         break;
3760     default:
3761         assert(false);
3762         return false;
3763     }
3764     return true;
3765 }
3766 
3767 static rnp_result_t
rnp_locate_key_int(rnp_ffi_t ffi,const pgp_key_search_t & locator,rnp_key_handle_t * handle,bool require_secret=false)3768 rnp_locate_key_int(rnp_ffi_t               ffi,
3769                    const pgp_key_search_t &locator,
3770                    rnp_key_handle_t *      handle,
3771                    bool                    require_secret = false)
3772 {
3773     // search pubring
3774     pgp_key_t *pub = rnp_key_store_search(ffi->pubring, &locator, NULL);
3775     // search secring
3776     pgp_key_t *sec = rnp_key_store_search(ffi->secring, &locator, NULL);
3777 
3778     if (require_secret && !sec) {
3779         *handle = NULL;
3780         return RNP_SUCCESS;
3781     }
3782 
3783     if (pub || sec) {
3784         *handle = (rnp_key_handle_t) malloc(sizeof(**handle));
3785         if (!*handle) {
3786             return RNP_ERROR_OUT_OF_MEMORY;
3787         }
3788         (*handle)->ffi = ffi;
3789         (*handle)->pub = pub;
3790         (*handle)->sec = sec;
3791         (*handle)->locator = locator;
3792     } else {
3793         *handle = NULL;
3794     }
3795     return RNP_SUCCESS;
3796 }
3797 
3798 rnp_result_t
rnp_locate_key(rnp_ffi_t ffi,const char * identifier_type,const char * identifier,rnp_key_handle_t * handle)3799 rnp_locate_key(rnp_ffi_t         ffi,
3800                const char *      identifier_type,
3801                const char *      identifier,
3802                rnp_key_handle_t *handle)
3803 try {
3804     // checks
3805     if (!ffi || !identifier_type || !identifier || !handle) {
3806         return RNP_ERROR_NULL_POINTER;
3807     }
3808 
3809     // figure out the identifier type
3810     pgp_key_search_t locator = {(pgp_key_search_type_t) 0};
3811     rnp_result_t     ret = str_to_locator(ffi, &locator, identifier_type, identifier);
3812     if (ret) {
3813         return ret;
3814     }
3815 
3816     return rnp_locate_key_int(ffi, locator, handle);
3817 }
3818 FFI_GUARD
3819 
3820 rnp_result_t
rnp_key_export(rnp_key_handle_t handle,rnp_output_t output,uint32_t flags)3821 rnp_key_export(rnp_key_handle_t handle, rnp_output_t output, uint32_t flags)
3822 try {
3823     pgp_dest_t *     dst = NULL;
3824     pgp_dest_t       armordst = {};
3825     pgp_key_t *      key = NULL;
3826     rnp_key_store_t *store = NULL;
3827     bool             export_subs = false;
3828     bool             armored = false;
3829 
3830     // checks
3831     if (!handle || !output) {
3832         return RNP_ERROR_NULL_POINTER;
3833     }
3834     dst = &output->dst;
3835     if ((flags & RNP_KEY_EXPORT_PUBLIC) && (flags & RNP_KEY_EXPORT_SECRET)) {
3836         FFI_LOG(handle->ffi, "Invalid export flags, select only public or secret, not both.");
3837         return RNP_ERROR_BAD_PARAMETERS;
3838     }
3839 
3840     // handle flags
3841     if (flags & RNP_KEY_EXPORT_ARMORED) {
3842         flags &= ~RNP_KEY_EXPORT_ARMORED;
3843         armored = true;
3844     }
3845     if (flags & RNP_KEY_EXPORT_PUBLIC) {
3846         flags &= ~RNP_KEY_EXPORT_PUBLIC;
3847         key = get_key_require_public(handle);
3848         store = handle->ffi->pubring;
3849     } else if (flags & RNP_KEY_EXPORT_SECRET) {
3850         flags &= ~RNP_KEY_EXPORT_SECRET;
3851         key = get_key_require_secret(handle);
3852         store = handle->ffi->secring;
3853     } else {
3854         FFI_LOG(handle->ffi, "must specify public or secret key for export");
3855         return RNP_ERROR_BAD_PARAMETERS;
3856     }
3857     if (flags & RNP_KEY_EXPORT_SUBKEYS) {
3858         flags &= ~RNP_KEY_EXPORT_SUBKEYS;
3859         export_subs = true;
3860     }
3861     // check for any unrecognized flags
3862     if (flags) {
3863         FFI_LOG(handle->ffi, "unrecognized flags remaining: 0x%X", flags);
3864         return RNP_ERROR_BAD_PARAMETERS;
3865     }
3866     // make sure we found our key
3867     if (!key) {
3868         FFI_LOG(handle->ffi, "no suitable key found");
3869         return RNP_ERROR_NO_SUITABLE_KEY;
3870     }
3871     // only PGP packets supported for now
3872     if (key->format != PGP_KEY_STORE_GPG && key->format != PGP_KEY_STORE_KBX) {
3873         return RNP_ERROR_NOT_IMPLEMENTED;
3874     }
3875     if (armored) {
3876         auto msgtype = key->is_secret() ? PGP_ARMORED_SECRET_KEY : PGP_ARMORED_PUBLIC_KEY;
3877         rnp_result_t res = init_armored_dst(&armordst, &output->dst, msgtype);
3878         if (res) {
3879             return res;
3880         }
3881         dst = &armordst;
3882     }
3883     // write
3884     if (key->is_primary()) {
3885         // primary key, write just the primary or primary and all subkeys
3886         key->write_xfer(*dst, export_subs ? store : NULL);
3887         if (dst->werr) {
3888             return RNP_ERROR_WRITE;
3889         }
3890     } else {
3891         // subkeys flag is only valid for primary
3892         if (export_subs) {
3893             FFI_LOG(handle->ffi, "export with subkeys requested but key is not primary");
3894             return RNP_ERROR_BAD_PARAMETERS;
3895         }
3896         // subkey, write the primary + this subkey only
3897         pgp_key_t *primary = rnp_key_store_get_primary_key(store, key);
3898         if (!primary) {
3899             // shouldn't happen
3900             return RNP_ERROR_GENERIC;
3901         }
3902         primary->write_xfer(*dst);
3903         if (dst->werr) {
3904             return RNP_ERROR_WRITE;
3905         }
3906         key->write_xfer(*dst);
3907         if (dst->werr) {
3908             return RNP_ERROR_WRITE;
3909         }
3910     }
3911     if (armored) {
3912         dst_finish(&armordst);
3913         dst_close(&armordst, false);
3914     }
3915     output->keep = true;
3916     return RNP_SUCCESS;
3917 }
3918 FFI_GUARD
3919 
3920 rnp_result_t
rnp_key_export_autocrypt(rnp_key_handle_t key,rnp_key_handle_t subkey,const char * uid,rnp_output_t output,uint32_t flags)3921 rnp_key_export_autocrypt(rnp_key_handle_t key,
3922                          rnp_key_handle_t subkey,
3923                          const char *     uid,
3924                          rnp_output_t     output,
3925                          uint32_t         flags)
3926 try {
3927     if (!key || !output) {
3928         return RNP_ERROR_NULL_POINTER;
3929     }
3930     if (flags) {
3931         return RNP_ERROR_BAD_PARAMETERS;
3932     }
3933     /* Get the primary key */
3934     pgp_key_t *primary = get_key_prefer_public(key);
3935     if (!primary || !primary->is_primary() || !primary->valid() || !primary->can_sign()) {
3936         FFI_LOG(key->ffi, "No valid signing primary key");
3937         return RNP_ERROR_BAD_PARAMETERS;
3938     }
3939     /* Get encrypting subkey */
3940     pgp_key_t *sub = NULL;
3941     if (subkey) {
3942         sub = get_key_prefer_public(subkey);
3943         if (sub && (!sub->valid() || !sub->can_encrypt())) {
3944             FFI_LOG(key->ffi, "Invalid or non-encrypting subkey");
3945             return RNP_ERROR_BAD_PARAMETERS;
3946         }
3947     } else {
3948         sub = find_suitable_key(
3949           PGP_OP_ENCRYPT, primary, &key->ffi->key_provider, PGP_KF_ENCRYPT, true);
3950     }
3951     if (!sub || sub->is_primary()) {
3952         FFI_LOG(key->ffi, "No encrypting subkey");
3953         return RNP_ERROR_KEY_NOT_FOUND;
3954     }
3955     /* Get userid */
3956     size_t uididx = primary->uid_count();
3957     if (uid) {
3958         for (size_t idx = 0; idx < primary->uid_count(); idx++) {
3959             if (primary->get_uid(idx).str == uid) {
3960                 uididx = idx;
3961                 break;
3962             }
3963         }
3964     } else {
3965         if (primary->uid_count() > 1) {
3966             FFI_LOG(key->ffi, "Ambiguous userid");
3967             return RNP_ERROR_BAD_PARAMETERS;
3968         }
3969         uididx = 0;
3970     }
3971     if (uididx >= primary->uid_count()) {
3972         FFI_LOG(key->ffi, "Userid not found");
3973         return RNP_ERROR_BAD_PARAMETERS;
3974     }
3975 
3976     if (!primary->write_autocrypt(output->dst, *sub, uididx)) {
3977         return RNP_ERROR_BAD_PARAMETERS;
3978     }
3979     return RNP_SUCCESS;
3980 }
3981 FFI_GUARD
3982 
3983 static pgp_key_t *
rnp_key_get_revoker(rnp_key_handle_t key)3984 rnp_key_get_revoker(rnp_key_handle_t key)
3985 {
3986     pgp_key_t *exkey = get_key_prefer_public(key);
3987     if (!exkey) {
3988         return NULL;
3989     }
3990     if (exkey->is_subkey()) {
3991         return rnp_key_store_get_primary_key(key->ffi->secring, exkey);
3992     }
3993     // TODO: search through revocation key subpackets as well
3994     return get_key_require_secret(key);
3995 }
3996 
3997 static rnp_result_t
rnp_key_get_revocation(rnp_ffi_t ffi,pgp_key_t * key,pgp_key_t * revoker,const char * hash,const char * code,const char * reason,pgp_signature_t & sig)3998 rnp_key_get_revocation(rnp_ffi_t        ffi,
3999                        pgp_key_t *      key,
4000                        pgp_key_t *      revoker,
4001                        const char *     hash,
4002                        const char *     code,
4003                        const char *     reason,
4004                        pgp_signature_t &sig)
4005 {
4006     if (!hash) {
4007         hash = DEFAULT_HASH_ALG;
4008     }
4009     pgp_hash_alg_t halg = PGP_HASH_UNKNOWN;
4010     if (!str_to_hash_alg(hash, &halg)) {
4011         FFI_LOG(ffi, "Unknown hash algorithm: %s", hash);
4012         return RNP_ERROR_BAD_PARAMETERS;
4013     }
4014     pgp_revoke_t revinfo = {};
4015     if (code && !str_to_revocation_type(code, &revinfo.code)) {
4016         FFI_LOG(ffi, "Wrong revocation code: %s", code);
4017         return RNP_ERROR_BAD_PARAMETERS;
4018     }
4019     if (revinfo.code > PGP_REVOCATION_RETIRED) {
4020         FFI_LOG(ffi, "Wrong key revocation code: %d", (int) revinfo.code);
4021         return RNP_ERROR_BAD_PARAMETERS;
4022     }
4023     if (reason) {
4024         try {
4025             revinfo.reason = reason;
4026         } catch (const std::exception &e) {
4027             FFI_LOG(ffi, "%s", e.what());
4028             return RNP_ERROR_OUT_OF_MEMORY;
4029         }
4030     }
4031     /* unlock the secret key if needed */
4032     rnp::KeyLocker revlock(*revoker);
4033     if (revoker->is_locked() && !revoker->unlock(ffi->pass_provider)) {
4034         FFI_LOG(ffi, "Failed to unlock secret key");
4035         return RNP_ERROR_BAD_PASSWORD;
4036     }
4037     try {
4038         revoker->gen_revocation(revinfo, halg, key->pkt(), sig, ffi->context);
4039     } catch (const std::exception &e) {
4040         FFI_LOG(ffi, "Failed to generate revocation signature: %s", e.what());
4041         return RNP_ERROR_BAD_STATE;
4042     }
4043     return RNP_SUCCESS;
4044 }
4045 
4046 rnp_result_t
rnp_key_export_revocation(rnp_key_handle_t key,rnp_output_t output,uint32_t flags,const char * hash,const char * code,const char * reason)4047 rnp_key_export_revocation(rnp_key_handle_t key,
4048                           rnp_output_t     output,
4049                           uint32_t         flags,
4050                           const char *     hash,
4051                           const char *     code,
4052                           const char *     reason)
4053 try {
4054     if (!key || !key->ffi || !output) {
4055         return RNP_ERROR_NULL_POINTER;
4056     }
4057     if (flags) {
4058         return RNP_ERROR_BAD_PARAMETERS;
4059     }
4060 
4061     pgp_key_t *exkey = get_key_prefer_public(key);
4062     if (!exkey || !exkey->is_primary()) {
4063         return RNP_ERROR_BAD_PARAMETERS;
4064     }
4065     pgp_key_t *revoker = rnp_key_get_revoker(key);
4066     if (!revoker) {
4067         FFI_LOG(key->ffi, "Revoker secret key not found");
4068         return RNP_ERROR_BAD_PARAMETERS;
4069     }
4070 
4071     pgp_signature_t sig;
4072     rnp_result_t    ret =
4073       rnp_key_get_revocation(key->ffi, exkey, revoker, hash, code, reason, sig);
4074     if (ret) {
4075         return ret;
4076     }
4077 
4078     sig.write(output->dst);
4079     ret = output->dst.werr;
4080     dst_flush(&output->dst);
4081     output->keep = !ret;
4082     return ret;
4083 }
4084 FFI_GUARD
4085 
4086 rnp_result_t
rnp_key_revoke(rnp_key_handle_t key,uint32_t flags,const char * hash,const char * code,const char * reason)4087 rnp_key_revoke(
4088   rnp_key_handle_t key, uint32_t flags, const char *hash, const char *code, const char *reason)
4089 try {
4090     if (!key || !key->ffi) {
4091         return RNP_ERROR_NULL_POINTER;
4092     }
4093     if (flags) {
4094         return RNP_ERROR_BAD_PARAMETERS;
4095     }
4096 
4097     pgp_key_t *exkey = get_key_prefer_public(key);
4098     if (!exkey) {
4099         return RNP_ERROR_BAD_PARAMETERS;
4100     }
4101     pgp_key_t *revoker = rnp_key_get_revoker(key);
4102     if (!revoker) {
4103         FFI_LOG(key->ffi, "Revoker secret key not found");
4104         return RNP_ERROR_BAD_PARAMETERS;
4105     }
4106 
4107     pgp_signature_t sig;
4108     rnp_result_t    ret =
4109       rnp_key_get_revocation(key->ffi, exkey, revoker, hash, code, reason, sig);
4110     if (ret) {
4111         return ret;
4112     }
4113     pgp_sig_import_status_t pub_status = PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY;
4114     pgp_sig_import_status_t sec_status = PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY;
4115     if (key->pub) {
4116         pub_status = rnp_key_store_import_key_signature(key->ffi->pubring, key->pub, &sig);
4117     }
4118     if (key->sec) {
4119         sec_status = rnp_key_store_import_key_signature(key->ffi->secring, key->sec, &sig);
4120     }
4121 
4122     if ((pub_status == PGP_SIG_IMPORT_STATUS_UNKNOWN) ||
4123         (sec_status == PGP_SIG_IMPORT_STATUS_UNKNOWN)) {
4124         return RNP_ERROR_GENERIC;
4125     }
4126     return RNP_SUCCESS;
4127 }
4128 FFI_GUARD
4129 
4130 rnp_result_t
rnp_key_25519_bits_tweaked(rnp_key_handle_t key,bool * result)4131 rnp_key_25519_bits_tweaked(rnp_key_handle_t key, bool *result)
4132 try {
4133     if (!key || !result) {
4134         return RNP_ERROR_NULL_POINTER;
4135     }
4136     pgp_key_t *seckey = get_key_require_secret(key);
4137     if (!seckey || seckey->is_locked() || (seckey->alg() != PGP_PKA_ECDH) ||
4138         (seckey->curve() != PGP_CURVE_25519)) {
4139         return RNP_ERROR_BAD_PARAMETERS;
4140     }
4141     *result = x25519_bits_tweaked(seckey->material().ec);
4142     return RNP_SUCCESS;
4143 }
4144 FFI_GUARD
4145 
4146 rnp_result_t
rnp_key_25519_bits_tweak(rnp_key_handle_t key)4147 rnp_key_25519_bits_tweak(rnp_key_handle_t key)
4148 try {
4149     if (!key) {
4150         return RNP_ERROR_NULL_POINTER;
4151     }
4152     pgp_key_t *seckey = get_key_require_secret(key);
4153     if (!seckey || seckey->is_protected() || (seckey->alg() != PGP_PKA_ECDH) ||
4154         (seckey->curve() != PGP_CURVE_25519)) {
4155         return RNP_ERROR_BAD_PARAMETERS;
4156     }
4157     if (!x25519_tweak_bits(seckey->pkt().material.ec)) {
4158         FFI_LOG(key->ffi, "Failed to tweak 25519 key bits.");
4159         return RNP_ERROR_BAD_STATE;
4160     }
4161     if (!seckey->write_sec_rawpkt(seckey->pkt(), "", key->ffi->rng())) {
4162         FFI_LOG(key->ffi, "Failed to update rawpkt.");
4163         return RNP_ERROR_BAD_STATE;
4164     }
4165     return RNP_SUCCESS;
4166 }
4167 FFI_GUARD
4168 
4169 rnp_result_t
rnp_key_remove(rnp_key_handle_t key,uint32_t flags)4170 rnp_key_remove(rnp_key_handle_t key, uint32_t flags)
4171 try {
4172     if (!key || !key->ffi) {
4173         return RNP_ERROR_NULL_POINTER;
4174     }
4175     bool pub = false;
4176     if (flags & RNP_KEY_REMOVE_PUBLIC) {
4177         pub = true;
4178         flags &= ~RNP_KEY_REMOVE_PUBLIC;
4179     }
4180     bool sec = false;
4181     if (flags & RNP_KEY_REMOVE_SECRET) {
4182         sec = true;
4183         flags &= ~RNP_KEY_REMOVE_SECRET;
4184     }
4185     bool sub = false;
4186     if (flags & RNP_KEY_REMOVE_SUBKEYS) {
4187         sub = true;
4188         flags &= ~RNP_KEY_REMOVE_SUBKEYS;
4189     }
4190     if (flags) {
4191         FFI_LOG(key->ffi, "Unknown flags: %" PRIu32, flags);
4192         return RNP_ERROR_BAD_PARAMETERS;
4193     }
4194     if (!pub && !sec) {
4195         return RNP_ERROR_BAD_PARAMETERS;
4196     }
4197     if (sub && get_key_prefer_public(key)->is_subkey()) {
4198         return RNP_ERROR_BAD_PARAMETERS;
4199     }
4200 
4201     if (pub) {
4202         if (!key->ffi->pubring || !key->pub) {
4203             return RNP_ERROR_BAD_PARAMETERS;
4204         }
4205         if (!rnp_key_store_remove_key(key->ffi->pubring, key->pub, sub)) {
4206             return RNP_ERROR_KEY_NOT_FOUND;
4207         }
4208         key->pub = NULL;
4209     }
4210     if (sec) {
4211         if (!key->ffi->secring || !key->sec) {
4212             return RNP_ERROR_BAD_PARAMETERS;
4213         }
4214         if (!rnp_key_store_remove_key(key->ffi->secring, key->sec, sub)) {
4215             return RNP_ERROR_KEY_NOT_FOUND;
4216         }
4217         key->sec = NULL;
4218     }
4219     return RNP_SUCCESS;
4220 }
4221 FFI_GUARD
4222 
4223 static void
report_signature_removal(rnp_ffi_t ffi,const pgp_key_t & key,rnp_key_signatures_cb sigcb,void * app_ctx,pgp_subsig_t & keysig,bool & remove)4224 report_signature_removal(rnp_ffi_t             ffi,
4225                          const pgp_key_t &     key,
4226                          rnp_key_signatures_cb sigcb,
4227                          void *                app_ctx,
4228                          pgp_subsig_t &        keysig,
4229                          bool &                remove)
4230 {
4231     if (!sigcb) {
4232         return;
4233     }
4234     rnp_signature_handle_t sig = (rnp_signature_handle_t) calloc(1, sizeof(*sig));
4235     if (!sig) {
4236         FFI_LOG(ffi, "Signature handle allocation failed.");
4237         return;
4238     }
4239     sig->ffi = ffi;
4240     sig->key = &key;
4241     sig->sig = &keysig;
4242     sig->own_sig = false;
4243     uint32_t action = remove ? RNP_KEY_SIGNATURE_REMOVE : RNP_KEY_SIGNATURE_KEEP;
4244     sigcb(ffi, app_ctx, sig, &action);
4245     switch (action) {
4246     case RNP_KEY_SIGNATURE_REMOVE:
4247         remove = true;
4248         break;
4249     case RNP_KEY_SIGNATURE_KEEP:
4250         remove = false;
4251         break;
4252     default:
4253         FFI_LOG(ffi, "Invalid signature removal action: %" PRIu32, action);
4254         break;
4255     }
4256     rnp_signature_handle_destroy(sig);
4257 }
4258 
4259 static bool
signature_needs_removal(rnp_ffi_t ffi,const pgp_key_t & key,pgp_subsig_t & sig,uint32_t flags)4260 signature_needs_removal(rnp_ffi_t ffi, const pgp_key_t &key, pgp_subsig_t &sig, uint32_t flags)
4261 {
4262     /* quick check for non-self signatures */
4263     bool nonself = flags & RNP_KEY_SIGNATURE_NON_SELF_SIG;
4264     if (nonself && key.is_primary() && !key.is_signer(sig)) {
4265         return true;
4266     }
4267     if (nonself && key.is_subkey()) {
4268         pgp_key_t *primary = rnp_key_store_get_primary_key(ffi->pubring, &key);
4269         if (primary && !primary->is_signer(sig)) {
4270             return true;
4271         }
4272     }
4273     /* unknown signer */
4274     pgp_key_t *signer = pgp_sig_get_signer(sig, ffi->pubring, &ffi->key_provider);
4275     if (!signer && (flags & RNP_KEY_SIGNATURE_UNKNOWN_KEY)) {
4276         return true;
4277     }
4278     /* validate signature if didn't */
4279     if (signer && !sig.validated()) {
4280         signer->validate_sig(key, sig, ffi->context);
4281     }
4282     /* we cannot check for invalid/expired if sig was not validated */
4283     if (!sig.validated()) {
4284         return false;
4285     }
4286     if ((flags & RNP_KEY_SIGNATURE_INVALID) && !sig.validity.valid) {
4287         return true;
4288     }
4289     return false;
4290 }
4291 
4292 static void
remove_key_signatures(rnp_ffi_t ffi,pgp_key_t & pub,pgp_key_t * sec,uint32_t flags,rnp_key_signatures_cb sigcb,void * app_ctx)4293 remove_key_signatures(rnp_ffi_t             ffi,
4294                       pgp_key_t &           pub,
4295                       pgp_key_t *           sec,
4296                       uint32_t              flags,
4297                       rnp_key_signatures_cb sigcb,
4298                       void *                app_ctx)
4299 {
4300     std::vector<pgp_sig_id_t> sigs;
4301 
4302     for (size_t idx = 0; idx < pub.sig_count(); idx++) {
4303         pgp_subsig_t &sig = pub.get_sig(idx);
4304         bool          remove = signature_needs_removal(ffi, pub, sig, flags);
4305         report_signature_removal(ffi, pub, sigcb, app_ctx, sig, remove);
4306         if (remove) {
4307             sigs.push_back(sig.sigid);
4308         }
4309     }
4310     size_t deleted = pub.del_sigs(sigs);
4311     if (deleted != sigs.size()) {
4312         FFI_LOG(ffi, "Invalid deleted sigs count: %zu instead of %zu.", deleted, sigs.size());
4313     }
4314     /* delete from the secret key if any */
4315     if (sec && (sec != &pub)) {
4316         sec->del_sigs(sigs);
4317     }
4318 }
4319 
4320 rnp_result_t
rnp_key_remove_signatures(rnp_key_handle_t handle,uint32_t flags,rnp_key_signatures_cb sigcb,void * app_ctx)4321 rnp_key_remove_signatures(rnp_key_handle_t      handle,
4322                           uint32_t              flags,
4323                           rnp_key_signatures_cb sigcb,
4324                           void *                app_ctx)
4325 try {
4326     if (!handle) {
4327         return RNP_ERROR_NULL_POINTER;
4328     }
4329     if (!flags && !sigcb) {
4330         return RNP_ERROR_BAD_PARAMETERS;
4331     }
4332     uint32_t origflags = flags;
4333     if (flags & RNP_KEY_SIGNATURE_INVALID) {
4334         flags &= ~RNP_KEY_SIGNATURE_INVALID;
4335     }
4336     if (flags & RNP_KEY_SIGNATURE_NON_SELF_SIG) {
4337         flags &= ~RNP_KEY_SIGNATURE_NON_SELF_SIG;
4338     }
4339     if (flags & RNP_KEY_SIGNATURE_UNKNOWN_KEY) {
4340         flags &= ~RNP_KEY_SIGNATURE_UNKNOWN_KEY;
4341     }
4342     if (flags) {
4343         FFI_LOG(handle->ffi, "Invalid flags: %" PRIu32, flags);
4344         return RNP_ERROR_BAD_PARAMETERS;
4345     }
4346     flags = origflags;
4347 
4348     pgp_key_t *key = get_key_prefer_public(handle);
4349     if (!key) {
4350         return RNP_ERROR_BAD_PARAMETERS;
4351     }
4352 
4353     /* process key itself */
4354     pgp_key_t *sec = get_key_require_secret(handle);
4355     remove_key_signatures(handle->ffi, *key, sec, flags, sigcb, app_ctx);
4356 
4357     /* process subkeys */
4358     for (size_t idx = 0; key->is_primary() && (idx < key->subkey_count()); idx++) {
4359         pgp_key_t *sub = pgp_key_get_subkey(key, handle->ffi->pubring, idx);
4360         if (!sub) {
4361             FFI_LOG(handle->ffi, "Failed to get subkey at idx %zu.", idx);
4362             continue;
4363         }
4364         pgp_key_t *subsec = rnp_key_store_get_key_by_fpr(handle->ffi->secring, sub->fp());
4365         remove_key_signatures(handle->ffi, *sub, subsec, flags, sigcb, app_ctx);
4366     }
4367     /* revalidate key/subkey */
4368     key->revalidate(*handle->ffi->pubring);
4369     if (sec) {
4370         sec->revalidate(*handle->ffi->secring);
4371     }
4372     return RNP_SUCCESS;
4373 }
4374 FFI_GUARD
4375 
4376 static bool
pk_alg_allows_custom_curve(pgp_pubkey_alg_t pkalg)4377 pk_alg_allows_custom_curve(pgp_pubkey_alg_t pkalg)
4378 {
4379     switch (pkalg) {
4380     case PGP_PKA_ECDH:
4381     case PGP_PKA_ECDSA:
4382     case PGP_PKA_SM2:
4383         return true;
4384     default:
4385         return false;
4386     }
4387 }
4388 
4389 static bool
parse_preferences(json_object * jso,pgp_user_prefs_t & prefs)4390 parse_preferences(json_object *jso, pgp_user_prefs_t &prefs)
4391 {
4392     static const struct {
4393         const char *   key;
4394         enum json_type type;
4395     } properties[] = {{"hashes", json_type_array},
4396                       {"ciphers", json_type_array},
4397                       {"compression", json_type_array},
4398                       {"key server", json_type_string}};
4399 
4400     for (size_t iprop = 0; iprop < ARRAY_SIZE(properties); iprop++) {
4401         json_object *value = NULL;
4402         const char * key = properties[iprop].key;
4403 
4404         if (!json_object_object_get_ex(jso, key, &value)) {
4405             continue;
4406         }
4407 
4408         if (!json_object_is_type(value, properties[iprop].type)) {
4409             return false;
4410         }
4411         try {
4412             if (rnp::str_case_eq(key, "hashes")) {
4413                 int length = json_object_array_length(value);
4414                 for (int i = 0; i < length; i++) {
4415                     json_object *item = json_object_array_get_idx(value, i);
4416                     if (!json_object_is_type(item, json_type_string)) {
4417                         return false;
4418                     }
4419                     pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN;
4420                     if (!str_to_hash_alg(json_object_get_string(item), &hash_alg)) {
4421                         return false;
4422                     }
4423                     prefs.add_hash_alg(hash_alg);
4424                 }
4425             } else if (rnp::str_case_eq(key, "ciphers")) {
4426                 int length = json_object_array_length(value);
4427                 for (int i = 0; i < length; i++) {
4428                     json_object *item = json_object_array_get_idx(value, i);
4429                     if (!json_object_is_type(item, json_type_string)) {
4430                         return false;
4431                     }
4432                     pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN;
4433                     if (!str_to_cipher(json_object_get_string(item), &symm_alg)) {
4434                         return false;
4435                     }
4436                     prefs.add_symm_alg(symm_alg);
4437                 }
4438             } else if (rnp::str_case_eq(key, "compression")) {
4439                 int length = json_object_array_length(value);
4440                 for (int i = 0; i < length; i++) {
4441                     json_object *item = json_object_array_get_idx(value, i);
4442                     if (!json_object_is_type(item, json_type_string)) {
4443                         return false;
4444                     }
4445                     pgp_compression_type_t z_alg = PGP_C_UNKNOWN;
4446                     if (!str_to_compression_alg(json_object_get_string(item), &z_alg)) {
4447                         return false;
4448                     }
4449                     prefs.add_z_alg(z_alg);
4450                 }
4451             } else if (rnp::str_case_eq(key, "key server")) {
4452                 prefs.key_server = json_object_get_string(value);
4453             }
4454         } catch (const std::exception &e) {
4455             RNP_LOG("%s", e.what());
4456             return false;
4457         }
4458         // delete this field since it has been handled
4459         json_object_object_del(jso, key);
4460     }
4461     return true;
4462 }
4463 
4464 static bool
parse_keygen_crypto(json_object * jso,rnp_keygen_crypto_params_t * crypto)4465 parse_keygen_crypto(json_object *jso, rnp_keygen_crypto_params_t *crypto)
4466 {
4467     static const struct {
4468         const char *   key;
4469         enum json_type type;
4470     } properties[] = {{"type", json_type_string},
4471                       {"curve", json_type_string},
4472                       {"length", json_type_int},
4473                       {"hash", json_type_string}};
4474 
4475     for (size_t i = 0; i < ARRAY_SIZE(properties); i++) {
4476         json_object *value = NULL;
4477         const char * key = properties[i].key;
4478 
4479         if (!json_object_object_get_ex(jso, key, &value)) {
4480             continue;
4481         }
4482 
4483         if (!json_object_is_type(value, properties[i].type)) {
4484             return false;
4485         }
4486         // TODO: make sure there are no duplicate keys in the JSON
4487         if (rnp::str_case_eq(key, "type")) {
4488             if (!str_to_pubkey_alg(json_object_get_string(value), &crypto->key_alg)) {
4489                 return false;
4490             }
4491         } else if (rnp::str_case_eq(key, "length")) {
4492             int length = json_object_get_int(value);
4493             switch (crypto->key_alg) {
4494             case PGP_PKA_RSA:
4495                 crypto->rsa.modulus_bit_len = length;
4496                 break;
4497             case PGP_PKA_DSA:
4498                 crypto->dsa.p_bitlen = length;
4499                 break;
4500             case PGP_PKA_ELGAMAL:
4501                 crypto->elgamal.key_bitlen = length;
4502                 break;
4503             default:
4504                 return false;
4505             }
4506         } else if (rnp::str_case_eq(key, "curve")) {
4507             if (!pk_alg_allows_custom_curve(crypto->key_alg)) {
4508                 return false;
4509             }
4510             if (!curve_str_to_type(json_object_get_string(value), &crypto->ecc.curve)) {
4511                 return false;
4512             }
4513         } else if (rnp::str_case_eq(key, "hash")) {
4514             if (!str_to_hash_alg(json_object_get_string(value), &crypto->hash_alg)) {
4515                 return false;
4516             }
4517         } else {
4518             // shouldn't happen
4519             return false;
4520         }
4521         // delete this field since it has been handled
4522         json_object_object_del(jso, key);
4523     }
4524     return true;
4525 }
4526 
4527 static bool
parse_protection(json_object * jso,rnp_key_protection_params_t * protection)4528 parse_protection(json_object *jso, rnp_key_protection_params_t *protection)
4529 {
4530     static const struct {
4531         const char *   key;
4532         enum json_type type;
4533     } properties[] = {{"cipher", json_type_string},
4534                       {"mode", json_type_string},
4535                       {"iterations", json_type_int},
4536                       {"hash", json_type_string}};
4537 
4538     for (size_t i = 0; i < ARRAY_SIZE(properties); i++) {
4539         json_object *value = NULL;
4540         const char * key = properties[i].key;
4541 
4542         if (!json_object_object_get_ex(jso, key, &value)) {
4543             continue;
4544         }
4545 
4546         if (!json_object_is_type(value, properties[i].type)) {
4547             return false;
4548         }
4549         // TODO: make sure there are no duplicate keys in the JSON
4550         if (rnp::str_case_eq(key, "cipher")) {
4551             if (!str_to_cipher(json_object_get_string(value), &protection->symm_alg)) {
4552                 return false;
4553             }
4554         } else if (rnp::str_case_eq(key, "mode")) {
4555             if (!str_to_cipher_mode(json_object_get_string(value), &protection->cipher_mode)) {
4556                 return false;
4557             }
4558         } else if (rnp::str_case_eq(key, "iterations")) {
4559             protection->iterations = json_object_get_int(value);
4560         } else if (rnp::str_case_eq(key, "hash")) {
4561             if (!str_to_hash_alg(json_object_get_string(value), &protection->hash_alg)) {
4562                 return false;
4563             }
4564         } else {
4565             // shouldn't happen
4566             return false;
4567         }
4568         // delete this field since it has been handled
4569         json_object_object_del(jso, key);
4570     }
4571     return true;
4572 }
4573 
4574 static bool
parse_keygen_primary(json_object * jso,rnp_action_keygen_t * desc)4575 parse_keygen_primary(json_object *jso, rnp_action_keygen_t *desc)
4576 {
4577     static const char *properties[] = {
4578       "userid", "usage", "expiration", "preferences", "protection"};
4579     rnp_selfsig_cert_info_t *cert = &desc->primary.keygen.cert;
4580 
4581     if (!parse_keygen_crypto(jso, &desc->primary.keygen.crypto)) {
4582         return false;
4583     }
4584     for (size_t i = 0; i < ARRAY_SIZE(properties); i++) {
4585         json_object *value = NULL;
4586         const char * key = properties[i];
4587 
4588         if (!json_object_object_get_ex(jso, key, &value)) {
4589             continue;
4590         }
4591         if (rnp::str_case_eq(key, "userid")) {
4592             if (!json_object_is_type(value, json_type_string)) {
4593                 return false;
4594             }
4595             const char *userid = json_object_get_string(value);
4596             size_t      userid_len = strlen(userid);
4597             if (userid_len >= sizeof(cert->userid)) {
4598                 return false;
4599             }
4600             memcpy(cert->userid, userid, userid_len + 1);
4601         } else if (rnp::str_case_eq(key, "usage")) {
4602             switch (json_object_get_type(value)) {
4603             case json_type_array: {
4604                 int length = json_object_array_length(value);
4605                 for (int j = 0; j < length; j++) {
4606                     json_object *item = json_object_array_get_idx(value, j);
4607                     if (!json_object_is_type(item, json_type_string)) {
4608                         return false;
4609                     }
4610                     uint8_t flag = 0;
4611                     if (!str_to_key_flag(json_object_get_string(item), &flag)) {
4612                         return false;
4613                     }
4614                     // check for duplicate
4615                     if (cert->key_flags & flag) {
4616                         return false;
4617                     }
4618                     cert->key_flags |= flag;
4619                 }
4620             } break;
4621             case json_type_string: {
4622                 if (!str_to_key_flag(json_object_get_string(value), &cert->key_flags)) {
4623                     return false;
4624                 }
4625             } break;
4626             default:
4627                 return false;
4628             }
4629         } else if (rnp::str_case_eq(key, "expiration")) {
4630             if (!json_object_is_type(value, json_type_int)) {
4631                 return false;
4632             }
4633             cert->key_expiration = json_object_get_int(value);
4634         } else if (rnp::str_case_eq(key, "preferences")) {
4635             if (!json_object_is_type(value, json_type_object)) {
4636                 return false;
4637             }
4638             if (!parse_preferences(value, cert->prefs)) {
4639                 return false;
4640             }
4641             if (json_object_object_length(value) != 0) {
4642                 return false;
4643             }
4644         } else if (rnp::str_case_eq(key, "protection")) {
4645             if (!json_object_is_type(value, json_type_object)) {
4646                 return false;
4647             }
4648             if (!parse_protection(value, &desc->primary.protection)) {
4649                 return false;
4650             }
4651             if (json_object_object_length(value) != 0) {
4652                 return false;
4653             }
4654         }
4655         // delete this field since it has been handled
4656         json_object_object_del(jso, key);
4657     }
4658     return json_object_object_length(jso) == 0;
4659 }
4660 
4661 static bool
parse_keygen_sub(json_object * jso,rnp_action_keygen_t * desc)4662 parse_keygen_sub(json_object *jso, rnp_action_keygen_t *desc)
4663 {
4664     static const char *         properties[] = {"usage", "expiration", "protection"};
4665     rnp_selfsig_binding_info_t *binding = &desc->subkey.keygen.binding;
4666 
4667     if (!parse_keygen_crypto(jso, &desc->subkey.keygen.crypto)) {
4668         return false;
4669     }
4670     for (size_t i = 0; i < ARRAY_SIZE(properties); i++) {
4671         json_object *value = NULL;
4672         const char * key = properties[i];
4673 
4674         if (!json_object_object_get_ex(jso, key, &value)) {
4675             continue;
4676         }
4677         if (rnp::str_case_eq(key, "usage")) {
4678             switch (json_object_get_type(value)) {
4679             case json_type_array: {
4680                 int length = json_object_array_length(value);
4681                 for (int j = 0; j < length; j++) {
4682                     json_object *item = json_object_array_get_idx(value, j);
4683                     if (!json_object_is_type(item, json_type_string)) {
4684                         return false;
4685                     }
4686                     uint8_t flag = 0;
4687                     if (!str_to_key_flag(json_object_get_string(item), &flag)) {
4688                         return false;
4689                     }
4690                     if (binding->key_flags & flag) {
4691                         return false;
4692                     }
4693                     binding->key_flags |= flag;
4694                 }
4695             } break;
4696             case json_type_string: {
4697                 if (!str_to_key_flag(json_object_get_string(value), &binding->key_flags)) {
4698                     return false;
4699                 }
4700             } break;
4701             default:
4702                 return false;
4703             }
4704         } else if (rnp::str_case_eq(key, "expiration")) {
4705             if (!json_object_is_type(value, json_type_int)) {
4706                 return false;
4707             }
4708             binding->key_expiration = json_object_get_int(value);
4709         } else if (rnp::str_case_eq(key, "protection")) {
4710             if (!json_object_is_type(value, json_type_object)) {
4711                 return false;
4712             }
4713             if (!parse_protection(value, &desc->subkey.protection)) {
4714                 return false;
4715             }
4716             if (json_object_object_length(value) != 0) {
4717                 return false;
4718             }
4719         }
4720         // delete this field since it has been handled
4721         json_object_object_del(jso, key);
4722     }
4723     return json_object_object_length(jso) == 0;
4724 }
4725 
4726 static bool
gen_json_grips(char ** result,const pgp_key_t * primary,const pgp_key_t * sub)4727 gen_json_grips(char **result, const pgp_key_t *primary, const pgp_key_t *sub)
4728 {
4729     bool         ret = false;
4730     json_object *jso = NULL;
4731     char         grip[PGP_KEY_GRIP_SIZE * 2 + 1];
4732 
4733     if (!result) {
4734         return false;
4735     }
4736 
4737     jso = json_object_new_object();
4738     if (!jso) {
4739         return false;
4740     }
4741 
4742     if (primary) {
4743         json_object *jsoprimary = json_object_new_object();
4744         if (!jsoprimary) {
4745             goto done;
4746         }
4747         json_object_object_add(jso, "primary", jsoprimary);
4748         if (!rnp::hex_encode(
4749               primary->grip().data(), primary->grip().size(), grip, sizeof(grip))) {
4750             goto done;
4751         }
4752         json_object *jsogrip = json_object_new_string(grip);
4753         if (!jsogrip) {
4754             goto done;
4755         }
4756         json_object_object_add(jsoprimary, "grip", jsogrip);
4757     }
4758     if (sub) {
4759         json_object *jsosub = json_object_new_object();
4760         if (!jsosub) {
4761             goto done;
4762         }
4763         json_object_object_add(jso, "sub", jsosub);
4764         if (!rnp::hex_encode(sub->grip().data(), sub->grip().size(), grip, sizeof(grip))) {
4765             goto done;
4766         }
4767         json_object *jsogrip = json_object_new_string(grip);
4768         if (!jsogrip) {
4769             goto done;
4770         }
4771         json_object_object_add(jsosub, "grip", jsogrip);
4772     }
4773     *result = strdup(json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY));
4774 
4775     ret = true;
4776 done:
4777     json_object_put(jso);
4778     return ret;
4779 }
4780 
4781 rnp_result_t
rnp_generate_key_json(rnp_ffi_t ffi,const char * json,char ** results)4782 rnp_generate_key_json(rnp_ffi_t ffi, const char *json, char **results)
4783 try {
4784     rnp_result_t        ret = RNP_ERROR_GENERIC;
4785     json_object *       jso = NULL;
4786     rnp_action_keygen_t keygen_desc = {};
4787     char *              identifier_type = NULL;
4788     char *              identifier = NULL;
4789     pgp_key_t           primary_pub;
4790     pgp_key_t           primary_sec;
4791     pgp_key_t           sub_pub;
4792     pgp_key_t           sub_sec;
4793     json_object *       jsoprimary = NULL;
4794     json_object *       jsosub = NULL;
4795     json_tokener_error  error;
4796 
4797     // checks
4798     if (!ffi || !ffi->secring || !json) {
4799         return RNP_ERROR_NULL_POINTER;
4800     }
4801 
4802     // parse the JSON
4803     jso = json_tokener_parse_verbose(json, &error);
4804     if (!jso) {
4805         // syntax error or some other issue
4806         FFI_LOG(ffi, "Invalid JSON: %s", json_tokener_error_desc(error));
4807         ret = RNP_ERROR_BAD_FORMAT;
4808         goto done;
4809     }
4810 
4811     // locate the appropriate sections
4812     {
4813         json_object_object_foreach(jso, key, value)
4814         {
4815             json_object **dest = NULL;
4816 
4817             if (rnp::str_case_eq(key, "primary")) {
4818                 dest = &jsoprimary;
4819             } else if (rnp::str_case_eq(key, "sub")) {
4820                 dest = &jsosub;
4821             } else {
4822                 // unrecognized key in the object
4823                 FFI_LOG(ffi, "Unexpected key in JSON: %s", key);
4824                 ret = RNP_ERROR_BAD_PARAMETERS;
4825                 goto done;
4826             }
4827 
4828             // duplicate "primary"/"sub"
4829             if (*dest) {
4830                 ret = RNP_ERROR_BAD_PARAMETERS;
4831                 goto done;
4832             }
4833             *dest = value;
4834         }
4835     }
4836 
4837     if (jsoprimary && jsosub) { // generating primary+sub
4838         if (!parse_keygen_primary(jsoprimary, &keygen_desc) ||
4839             !parse_keygen_sub(jsosub, &keygen_desc)) {
4840             ret = RNP_ERROR_BAD_PARAMETERS;
4841             goto done;
4842         }
4843         keygen_desc.primary.keygen.crypto.ctx = &ffi->context;
4844         keygen_desc.subkey.keygen.crypto.ctx = &ffi->context;
4845         if (!pgp_generate_keypair(keygen_desc.primary.keygen,
4846                                   keygen_desc.subkey.keygen,
4847                                   true,
4848                                   primary_sec,
4849                                   primary_pub,
4850                                   sub_sec,
4851                                   sub_pub,
4852                                   ffi->secring->format)) {
4853             goto done;
4854         }
4855         if (results && !gen_json_grips(results, &primary_pub, &sub_pub)) {
4856             ret = RNP_ERROR_OUT_OF_MEMORY;
4857             goto done;
4858         }
4859         if (ffi->pubring) {
4860             if (!rnp_key_store_add_key(ffi->pubring, &primary_pub)) {
4861                 ret = RNP_ERROR_OUT_OF_MEMORY;
4862                 goto done;
4863             }
4864             if (!rnp_key_store_add_key(ffi->pubring, &sub_pub)) {
4865                 ret = RNP_ERROR_OUT_OF_MEMORY;
4866                 goto done;
4867             }
4868         }
4869         /* add key/subkey protection */
4870         if (keygen_desc.primary.protection.symm_alg &&
4871             !primary_sec.protect(
4872               keygen_desc.primary.protection, ffi->pass_provider, ffi->rng())) {
4873             ret = RNP_ERROR_BAD_PARAMETERS;
4874             goto done;
4875         }
4876 
4877         if (keygen_desc.subkey.protection.symm_alg &&
4878             !sub_sec.protect(keygen_desc.subkey.protection, ffi->pass_provider, ffi->rng())) {
4879             ret = RNP_ERROR_BAD_PARAMETERS;
4880             goto done;
4881         }
4882 
4883         if (!rnp_key_store_add_key(ffi->secring, &primary_sec)) {
4884             ret = RNP_ERROR_OUT_OF_MEMORY;
4885             goto done;
4886         }
4887         if (!rnp_key_store_add_key(ffi->secring, &sub_sec)) {
4888             ret = RNP_ERROR_OUT_OF_MEMORY;
4889             goto done;
4890         }
4891     } else if (jsoprimary && !jsosub) { // generating primary only
4892         keygen_desc.primary.keygen.crypto.ctx = &ffi->context;
4893         if (!parse_keygen_primary(jsoprimary, &keygen_desc)) {
4894             ret = RNP_ERROR_BAD_PARAMETERS;
4895             goto done;
4896         }
4897         if (!pgp_generate_primary_key(keygen_desc.primary.keygen,
4898                                       true,
4899                                       primary_sec,
4900                                       primary_pub,
4901                                       ffi->secring->format)) {
4902             goto done;
4903         }
4904         if (results && !gen_json_grips(results, &primary_pub, NULL)) {
4905             ret = RNP_ERROR_OUT_OF_MEMORY;
4906             goto done;
4907         }
4908         if (ffi->pubring) {
4909             if (!rnp_key_store_add_key(ffi->pubring, &primary_pub)) {
4910                 ret = RNP_ERROR_OUT_OF_MEMORY;
4911                 goto done;
4912             }
4913         }
4914         /* encrypt secret key if specified */
4915         if (keygen_desc.primary.protection.symm_alg &&
4916             !primary_sec.protect(
4917               keygen_desc.primary.protection, ffi->pass_provider, ffi->rng())) {
4918             ret = RNP_ERROR_BAD_PARAMETERS;
4919             goto done;
4920         }
4921 
4922         if (!rnp_key_store_add_key(ffi->secring, &primary_sec)) {
4923             ret = RNP_ERROR_OUT_OF_MEMORY;
4924             goto done;
4925         }
4926     } else if (jsosub) { // generating subkey only
4927         if (!ffi->pubring) {
4928             ret = RNP_ERROR_NULL_POINTER;
4929             goto done;
4930         }
4931         json_object *jsoparent = NULL;
4932         if (!json_object_object_get_ex(jsosub, "primary", &jsoparent) ||
4933             json_object_object_length(jsoparent) != 1) {
4934             ret = RNP_ERROR_BAD_PARAMETERS;
4935             goto done;
4936         }
4937         json_object_object_foreach(jsoparent, key, value)
4938         {
4939             if (!json_object_is_type(value, json_type_string)) {
4940                 ret = RNP_ERROR_BAD_PARAMETERS;
4941                 goto done;
4942             }
4943             identifier_type = strdup(key);
4944             identifier = strdup(json_object_get_string(value));
4945         }
4946         if (!identifier_type || !identifier) {
4947             ret = RNP_ERROR_OUT_OF_MEMORY;
4948             goto done;
4949         }
4950         json_object_object_del(jsosub, "primary");
4951 
4952         pgp_key_search_t locator = {(pgp_key_search_type_t) 0};
4953         rnp_result_t     tmpret = str_to_locator(ffi, &locator, identifier_type, identifier);
4954         if (tmpret) {
4955             ret = tmpret;
4956             goto done;
4957         }
4958 
4959         pgp_key_t *primary_pub = rnp_key_store_search(ffi->pubring, &locator, NULL);
4960         pgp_key_t *primary_sec = rnp_key_store_search(ffi->secring, &locator, NULL);
4961         if (!primary_sec || !primary_pub) {
4962             ret = RNP_ERROR_KEY_NOT_FOUND;
4963             goto done;
4964         }
4965         if (!parse_keygen_sub(jsosub, &keygen_desc)) {
4966             ret = RNP_ERROR_BAD_PARAMETERS;
4967             goto done;
4968         }
4969         keygen_desc.subkey.keygen.crypto.ctx = &ffi->context;
4970         if (!pgp_generate_subkey(keygen_desc.subkey.keygen,
4971                                  true,
4972                                  *primary_sec,
4973                                  *primary_pub,
4974                                  sub_sec,
4975                                  sub_pub,
4976                                  ffi->pass_provider,
4977                                  ffi->secring->format)) {
4978             goto done;
4979         }
4980         if (results && !gen_json_grips(results, NULL, &sub_pub)) {
4981             ret = RNP_ERROR_OUT_OF_MEMORY;
4982             goto done;
4983         }
4984         if (ffi->pubring) {
4985             if (!rnp_key_store_add_key(ffi->pubring, &sub_pub)) {
4986                 ret = RNP_ERROR_OUT_OF_MEMORY;
4987                 goto done;
4988             }
4989         }
4990         /* encrypt subkey if specified */
4991         if (keygen_desc.subkey.protection.symm_alg &&
4992             !sub_sec.protect(keygen_desc.subkey.protection, ffi->pass_provider, ffi->rng())) {
4993             ret = RNP_ERROR_BAD_PARAMETERS;
4994             goto done;
4995         }
4996 
4997         if (!rnp_key_store_add_key(ffi->secring, &sub_sec)) {
4998             ret = RNP_ERROR_OUT_OF_MEMORY;
4999             goto done;
5000         }
5001     } else {
5002         // nothing to generate...
5003         ret = RNP_ERROR_BAD_PARAMETERS;
5004         goto done;
5005     }
5006 
5007     ret = RNP_SUCCESS;
5008 done:
5009     json_object_put(jso);
5010     free(identifier_type);
5011     free(identifier);
5012     return ret;
5013 }
5014 FFI_GUARD
5015 
5016 rnp_result_t
rnp_generate_key_ex(rnp_ffi_t ffi,const char * key_alg,const char * sub_alg,uint32_t key_bits,uint32_t sub_bits,const char * key_curve,const char * sub_curve,const char * userid,const char * password,rnp_key_handle_t * key)5017 rnp_generate_key_ex(rnp_ffi_t         ffi,
5018                     const char *      key_alg,
5019                     const char *      sub_alg,
5020                     uint32_t          key_bits,
5021                     uint32_t          sub_bits,
5022                     const char *      key_curve,
5023                     const char *      sub_curve,
5024                     const char *      userid,
5025                     const char *      password,
5026                     rnp_key_handle_t *key)
5027 try {
5028     rnp_op_generate_t op = NULL;
5029     rnp_op_generate_t subop = NULL;
5030     rnp_key_handle_t  primary = NULL;
5031     rnp_key_handle_t  subkey = NULL;
5032     rnp_result_t      ret = RNP_ERROR_KEY_GENERATION;
5033 
5034     /* generate primary key */
5035     if ((ret = rnp_op_generate_create(&op, ffi, key_alg))) {
5036         return ret;
5037     }
5038     if (key_bits && (ret = rnp_op_generate_set_bits(op, key_bits))) {
5039         goto done;
5040     }
5041     if (key_curve && (ret = rnp_op_generate_set_curve(op, key_curve))) {
5042         goto done;
5043     }
5044     if ((ret = rnp_op_generate_set_userid(op, userid))) {
5045         goto done;
5046     }
5047     if ((ret = rnp_op_generate_add_usage(op, "sign"))) {
5048         goto done;
5049     }
5050     if ((ret = rnp_op_generate_add_usage(op, "certify"))) {
5051         goto done;
5052     }
5053     if ((ret = rnp_op_generate_execute(op))) {
5054         goto done;
5055     }
5056     if ((ret = rnp_op_generate_get_key(op, &primary))) {
5057         goto done;
5058     }
5059     /* generate subkey if requested */
5060     if (!sub_alg) {
5061         goto done;
5062     }
5063     if ((ret = rnp_op_generate_subkey_create(&subop, ffi, primary, sub_alg))) {
5064         goto done;
5065     }
5066     if (sub_bits && (ret = rnp_op_generate_set_bits(subop, sub_bits))) {
5067         goto done;
5068     }
5069     if (sub_curve && (ret = rnp_op_generate_set_curve(subop, sub_curve))) {
5070         goto done;
5071     }
5072     if (password && (ret = rnp_op_generate_set_protection_password(subop, password))) {
5073         goto done;
5074     }
5075     if ((ret = rnp_op_generate_add_usage(subop, "encrypt"))) {
5076         goto done;
5077     }
5078     if ((ret = rnp_op_generate_execute(subop))) {
5079         goto done;
5080     }
5081     if ((ret = rnp_op_generate_get_key(subop, &subkey))) {
5082         goto done;
5083     }
5084 done:
5085     /* only now will protect the primary key - to not spend time on unlocking to sign
5086      * subkey */
5087     if (!ret && password) {
5088         ret = rnp_key_protect(primary, password, NULL, NULL, NULL, 0);
5089     }
5090     if (ret && primary) {
5091         rnp_key_remove(primary, RNP_KEY_REMOVE_PUBLIC | RNP_KEY_REMOVE_SECRET);
5092     }
5093     if (ret && subkey) {
5094         rnp_key_remove(subkey, RNP_KEY_REMOVE_PUBLIC | RNP_KEY_REMOVE_SECRET);
5095     }
5096     if (!ret && key) {
5097         *key = primary;
5098     } else {
5099         rnp_key_handle_destroy(primary);
5100     }
5101     rnp_key_handle_destroy(subkey);
5102     rnp_op_generate_destroy(op);
5103     rnp_op_generate_destroy(subop);
5104     return ret;
5105 }
5106 FFI_GUARD
5107 
5108 rnp_result_t
rnp_generate_key_rsa(rnp_ffi_t ffi,uint32_t bits,uint32_t subbits,const char * userid,const char * password,rnp_key_handle_t * key)5109 rnp_generate_key_rsa(rnp_ffi_t         ffi,
5110                      uint32_t          bits,
5111                      uint32_t          subbits,
5112                      const char *      userid,
5113                      const char *      password,
5114                      rnp_key_handle_t *key)
5115 try {
5116     return rnp_generate_key_ex(ffi,
5117                                RNP_ALGNAME_RSA,
5118                                subbits ? RNP_ALGNAME_RSA : NULL,
5119                                bits,
5120                                subbits,
5121                                NULL,
5122                                NULL,
5123                                userid,
5124                                password,
5125                                key);
5126 }
5127 FFI_GUARD
5128 
5129 rnp_result_t
rnp_generate_key_dsa_eg(rnp_ffi_t ffi,uint32_t bits,uint32_t subbits,const char * userid,const char * password,rnp_key_handle_t * key)5130 rnp_generate_key_dsa_eg(rnp_ffi_t         ffi,
5131                         uint32_t          bits,
5132                         uint32_t          subbits,
5133                         const char *      userid,
5134                         const char *      password,
5135                         rnp_key_handle_t *key)
5136 try {
5137     return rnp_generate_key_ex(ffi,
5138                                RNP_ALGNAME_DSA,
5139                                subbits ? RNP_ALGNAME_ELGAMAL : NULL,
5140                                bits,
5141                                subbits,
5142                                NULL,
5143                                NULL,
5144                                userid,
5145                                password,
5146                                key);
5147 }
5148 FFI_GUARD
5149 
5150 rnp_result_t
rnp_generate_key_ec(rnp_ffi_t ffi,const char * curve,const char * userid,const char * password,rnp_key_handle_t * key)5151 rnp_generate_key_ec(rnp_ffi_t         ffi,
5152                     const char *      curve,
5153                     const char *      userid,
5154                     const char *      password,
5155                     rnp_key_handle_t *key)
5156 try {
5157     return rnp_generate_key_ex(
5158       ffi, RNP_ALGNAME_ECDSA, RNP_ALGNAME_ECDH, 0, 0, curve, curve, userid, password, key);
5159 }
5160 FFI_GUARD
5161 
5162 rnp_result_t
rnp_generate_key_25519(rnp_ffi_t ffi,const char * userid,const char * password,rnp_key_handle_t * key)5163 rnp_generate_key_25519(rnp_ffi_t         ffi,
5164                        const char *      userid,
5165                        const char *      password,
5166                        rnp_key_handle_t *key)
5167 try {
5168     return rnp_generate_key_ex(ffi,
5169                                RNP_ALGNAME_EDDSA,
5170                                RNP_ALGNAME_ECDH,
5171                                0,
5172                                0,
5173                                NULL,
5174                                "Curve25519",
5175                                userid,
5176                                password,
5177                                key);
5178 }
5179 FFI_GUARD
5180 
5181 rnp_result_t
rnp_generate_key_sm2(rnp_ffi_t ffi,const char * userid,const char * password,rnp_key_handle_t * key)5182 rnp_generate_key_sm2(rnp_ffi_t         ffi,
5183                      const char *      userid,
5184                      const char *      password,
5185                      rnp_key_handle_t *key)
5186 try {
5187     return rnp_generate_key_ex(
5188       ffi, RNP_ALGNAME_SM2, RNP_ALGNAME_SM2, 0, 0, NULL, NULL, userid, password, key);
5189 }
5190 FFI_GUARD
5191 
5192 static pgp_key_flags_t
default_key_flags(pgp_pubkey_alg_t alg,bool subkey)5193 default_key_flags(pgp_pubkey_alg_t alg, bool subkey)
5194 {
5195     switch (alg) {
5196     case PGP_PKA_RSA:
5197         return subkey ? PGP_KF_ENCRYPT : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY);
5198     case PGP_PKA_DSA:
5199     case PGP_PKA_ECDSA:
5200     case PGP_PKA_EDDSA:
5201         return subkey ? PGP_KF_SIGN : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY);
5202     case PGP_PKA_SM2:
5203         return subkey ? PGP_KF_ENCRYPT : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY);
5204     case PGP_PKA_ECDH:
5205     case PGP_PKA_ELGAMAL:
5206         return PGP_KF_ENCRYPT;
5207     default:
5208         return PGP_KF_NONE;
5209     }
5210 }
5211 
5212 rnp_result_t
rnp_op_generate_create(rnp_op_generate_t * op,rnp_ffi_t ffi,const char * alg)5213 rnp_op_generate_create(rnp_op_generate_t *op, rnp_ffi_t ffi, const char *alg)
5214 try {
5215     pgp_pubkey_alg_t key_alg = PGP_PKA_NOTHING;
5216 
5217     if (!op || !ffi || !alg) {
5218         return RNP_ERROR_NULL_POINTER;
5219     }
5220 
5221     if (!ffi->pubring || !ffi->secring) {
5222         return RNP_ERROR_BAD_PARAMETERS;
5223     }
5224 
5225     if (!str_to_pubkey_alg(alg, &key_alg)) {
5226         return RNP_ERROR_BAD_PARAMETERS;
5227     }
5228 
5229     if (!(pgp_pk_alg_capabilities(key_alg) & PGP_KF_SIGN)) {
5230         return RNP_ERROR_BAD_PARAMETERS;
5231     }
5232 
5233     *op = new rnp_op_generate_st();
5234     (*op)->ffi = ffi;
5235     (*op)->primary = true;
5236     (*op)->crypto.key_alg = key_alg;
5237     (*op)->crypto.ctx = &ffi->context;
5238     (*op)->cert.key_flags = default_key_flags(key_alg, false);
5239 
5240     return RNP_SUCCESS;
5241 }
5242 FFI_GUARD
5243 
5244 rnp_result_t
rnp_op_generate_subkey_create(rnp_op_generate_t * op,rnp_ffi_t ffi,rnp_key_handle_t primary,const char * alg)5245 rnp_op_generate_subkey_create(rnp_op_generate_t *op,
5246                               rnp_ffi_t          ffi,
5247                               rnp_key_handle_t   primary,
5248                               const char *       alg)
5249 try {
5250     if (!op || !ffi || !alg || !primary) {
5251         return RNP_ERROR_NULL_POINTER;
5252     }
5253 
5254     if (!ffi->pubring || !ffi->secring) {
5255         return RNP_ERROR_BAD_PARAMETERS;
5256     }
5257 
5258     /* TODO: should we do these checks here or may leave it up till generate call? */
5259     bool flag = false;
5260     if (rnp_key_have_secret(primary, &flag) || !flag) {
5261         return RNP_ERROR_BAD_PARAMETERS;
5262     }
5263 
5264     if (rnp_key_is_primary(primary, &flag) || !flag) {
5265         return RNP_ERROR_BAD_PARAMETERS;
5266     }
5267 
5268     if (!primary->sec->can_sign()) {
5269         return RNP_ERROR_BAD_PARAMETERS;
5270     }
5271 
5272     pgp_pubkey_alg_t key_alg = PGP_PKA_NOTHING;
5273     if (!str_to_pubkey_alg(alg, &key_alg)) {
5274         return RNP_ERROR_BAD_PARAMETERS;
5275     }
5276 
5277     *op = new rnp_op_generate_st();
5278     (*op)->ffi = ffi;
5279     (*op)->primary = false;
5280     (*op)->crypto.key_alg = key_alg;
5281     (*op)->crypto.ctx = &ffi->context;
5282     (*op)->binding.key_flags = default_key_flags(key_alg, true);
5283     (*op)->primary_sec = primary->sec;
5284     (*op)->primary_pub = primary->pub;
5285 
5286     return RNP_SUCCESS;
5287 }
5288 FFI_GUARD
5289 
5290 rnp_result_t
rnp_op_generate_set_bits(rnp_op_generate_t op,uint32_t bits)5291 rnp_op_generate_set_bits(rnp_op_generate_t op, uint32_t bits)
5292 try {
5293     if (!op) {
5294         return RNP_ERROR_NULL_POINTER;
5295     }
5296 
5297     switch (op->crypto.key_alg) {
5298     case PGP_PKA_RSA:
5299     case PGP_PKA_RSA_ENCRYPT_ONLY:
5300     case PGP_PKA_RSA_SIGN_ONLY:
5301         op->crypto.rsa.modulus_bit_len = bits;
5302         break;
5303     case PGP_PKA_ELGAMAL:
5304         op->crypto.elgamal.key_bitlen = bits;
5305         break;
5306     case PGP_PKA_DSA:
5307         op->crypto.dsa.p_bitlen = bits;
5308         break;
5309     default:
5310         return RNP_ERROR_BAD_PARAMETERS;
5311     }
5312 
5313     return RNP_SUCCESS;
5314 }
5315 FFI_GUARD
5316 
5317 rnp_result_t
rnp_op_generate_set_hash(rnp_op_generate_t op,const char * hash)5318 rnp_op_generate_set_hash(rnp_op_generate_t op, const char *hash)
5319 try {
5320     if (!op || !hash) {
5321         return RNP_ERROR_NULL_POINTER;
5322     }
5323     if (!str_to_hash_alg(hash, &op->crypto.hash_alg)) {
5324         FFI_LOG(op->ffi, "Invalid hash: %s", hash);
5325         return RNP_ERROR_BAD_PARAMETERS;
5326     }
5327     return RNP_SUCCESS;
5328 }
5329 FFI_GUARD
5330 
5331 rnp_result_t
rnp_op_generate_set_dsa_qbits(rnp_op_generate_t op,uint32_t qbits)5332 rnp_op_generate_set_dsa_qbits(rnp_op_generate_t op, uint32_t qbits)
5333 try {
5334     if (!op) {
5335         return RNP_ERROR_NULL_POINTER;
5336     }
5337     if (op->crypto.key_alg != PGP_PKA_DSA) {
5338         return RNP_ERROR_BAD_PARAMETERS;
5339     }
5340     op->crypto.dsa.q_bitlen = qbits;
5341     return RNP_SUCCESS;
5342 }
5343 FFI_GUARD
5344 
5345 rnp_result_t
rnp_op_generate_set_curve(rnp_op_generate_t op,const char * curve)5346 rnp_op_generate_set_curve(rnp_op_generate_t op, const char *curve)
5347 try {
5348     if (!op || !curve) {
5349         return RNP_ERROR_NULL_POINTER;
5350     }
5351     if (!pk_alg_allows_custom_curve(op->crypto.key_alg)) {
5352         return RNP_ERROR_BAD_PARAMETERS;
5353     }
5354     if (!curve_str_to_type(curve, &op->crypto.ecc.curve)) {
5355         return RNP_ERROR_BAD_PARAMETERS;
5356     }
5357     return RNP_SUCCESS;
5358 }
5359 FFI_GUARD
5360 
5361 rnp_result_t
rnp_op_generate_set_protection_password(rnp_op_generate_t op,const char * password)5362 rnp_op_generate_set_protection_password(rnp_op_generate_t op, const char *password)
5363 try {
5364     if (!op || !password) {
5365         return RNP_ERROR_NULL_POINTER;
5366     }
5367     op->password.assign(password, password + strlen(password) + 1);
5368     return RNP_SUCCESS;
5369 }
5370 FFI_GUARD
5371 
5372 rnp_result_t
rnp_op_generate_set_request_password(rnp_op_generate_t op,bool request)5373 rnp_op_generate_set_request_password(rnp_op_generate_t op, bool request)
5374 try {
5375     if (!op || !request) {
5376         return RNP_ERROR_NULL_POINTER;
5377     }
5378     op->request_password = request;
5379     return RNP_SUCCESS;
5380 }
5381 FFI_GUARD
5382 
5383 rnp_result_t
rnp_op_generate_set_protection_cipher(rnp_op_generate_t op,const char * cipher)5384 rnp_op_generate_set_protection_cipher(rnp_op_generate_t op, const char *cipher)
5385 try {
5386     if (!op || !cipher) {
5387         return RNP_ERROR_NULL_POINTER;
5388     }
5389     if (!str_to_cipher(cipher, &op->protection.symm_alg)) {
5390         return RNP_ERROR_BAD_PARAMETERS;
5391     }
5392     return RNP_SUCCESS;
5393 }
5394 FFI_GUARD
5395 
5396 rnp_result_t
rnp_op_generate_set_protection_hash(rnp_op_generate_t op,const char * hash)5397 rnp_op_generate_set_protection_hash(rnp_op_generate_t op, const char *hash)
5398 try {
5399     if (!op || !hash) {
5400         return RNP_ERROR_NULL_POINTER;
5401     }
5402     if (!str_to_hash_alg(hash, &op->protection.hash_alg)) {
5403         return RNP_ERROR_BAD_PARAMETERS;
5404     }
5405     return RNP_SUCCESS;
5406 }
5407 FFI_GUARD
5408 
5409 rnp_result_t
rnp_op_generate_set_protection_mode(rnp_op_generate_t op,const char * mode)5410 rnp_op_generate_set_protection_mode(rnp_op_generate_t op, const char *mode)
5411 try {
5412     if (!op || !mode) {
5413         return RNP_ERROR_NULL_POINTER;
5414     }
5415     if (!str_to_cipher_mode(mode, &op->protection.cipher_mode)) {
5416         return RNP_ERROR_BAD_PARAMETERS;
5417     }
5418     return RNP_SUCCESS;
5419 }
5420 FFI_GUARD
5421 
5422 rnp_result_t
rnp_op_generate_set_protection_iterations(rnp_op_generate_t op,uint32_t iterations)5423 rnp_op_generate_set_protection_iterations(rnp_op_generate_t op, uint32_t iterations)
5424 try {
5425     if (!op) {
5426         return RNP_ERROR_NULL_POINTER;
5427     }
5428     op->protection.iterations = iterations;
5429     return RNP_SUCCESS;
5430 }
5431 FFI_GUARD
5432 
5433 rnp_result_t
rnp_op_generate_add_usage(rnp_op_generate_t op,const char * usage)5434 rnp_op_generate_add_usage(rnp_op_generate_t op, const char *usage)
5435 try {
5436     if (!op || !usage) {
5437         return RNP_ERROR_NULL_POINTER;
5438     }
5439     uint8_t flag = 0;
5440     if (!str_to_key_flag(usage, &flag)) {
5441         return RNP_ERROR_BAD_PARAMETERS;
5442     }
5443     if (!(pgp_pk_alg_capabilities(op->crypto.key_alg) & flag)) {
5444         return RNP_ERROR_NOT_SUPPORTED;
5445     }
5446     if (op->primary) {
5447         op->cert.key_flags |= flag;
5448     } else {
5449         op->binding.key_flags |= flag;
5450     }
5451     return RNP_SUCCESS;
5452 }
5453 FFI_GUARD
5454 
5455 rnp_result_t
rnp_op_generate_clear_usage(rnp_op_generate_t op)5456 rnp_op_generate_clear_usage(rnp_op_generate_t op)
5457 try {
5458     if (!op) {
5459         return RNP_ERROR_NULL_POINTER;
5460     }
5461     if (op->primary) {
5462         op->cert.key_flags = 0;
5463     } else {
5464         op->binding.key_flags = 0;
5465     }
5466     return RNP_SUCCESS;
5467 }
5468 FFI_GUARD
5469 
5470 rnp_result_t
rnp_op_generate_set_userid(rnp_op_generate_t op,const char * userid)5471 rnp_op_generate_set_userid(rnp_op_generate_t op, const char *userid)
5472 try {
5473     if (!op || !userid) {
5474         return RNP_ERROR_NULL_POINTER;
5475     }
5476     if (!op->primary) {
5477         return RNP_ERROR_BAD_PARAMETERS;
5478     }
5479     size_t userid_len = strlen(userid);
5480     if (userid_len >= sizeof(op->cert.userid)) {
5481         return RNP_ERROR_BAD_PARAMETERS;
5482     }
5483     memcpy(op->cert.userid, userid, userid_len + 1);
5484     return RNP_SUCCESS;
5485 }
5486 FFI_GUARD
5487 
5488 rnp_result_t
rnp_op_generate_set_expiration(rnp_op_generate_t op,uint32_t expiration)5489 rnp_op_generate_set_expiration(rnp_op_generate_t op, uint32_t expiration)
5490 try {
5491     if (!op) {
5492         return RNP_ERROR_NULL_POINTER;
5493     }
5494     if (op->primary) {
5495         op->cert.key_expiration = expiration;
5496     } else {
5497         op->binding.key_expiration = expiration;
5498     }
5499     return RNP_SUCCESS;
5500 }
5501 FFI_GUARD
5502 
5503 rnp_result_t
rnp_op_generate_clear_pref_hashes(rnp_op_generate_t op)5504 rnp_op_generate_clear_pref_hashes(rnp_op_generate_t op)
5505 try {
5506     if (!op) {
5507         return RNP_ERROR_NULL_POINTER;
5508     }
5509     if (!op->primary) {
5510         return RNP_ERROR_BAD_PARAMETERS;
5511     }
5512     op->cert.prefs.set_hash_algs({});
5513     return RNP_SUCCESS;
5514 }
5515 FFI_GUARD
5516 
5517 rnp_result_t
rnp_op_generate_add_pref_hash(rnp_op_generate_t op,const char * hash)5518 rnp_op_generate_add_pref_hash(rnp_op_generate_t op, const char *hash)
5519 try {
5520     if (!op || !hash) {
5521         return RNP_ERROR_NULL_POINTER;
5522     }
5523     if (!op->primary) {
5524         return RNP_ERROR_BAD_PARAMETERS;
5525     }
5526     pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN;
5527     if (!str_to_hash_alg(hash, &hash_alg)) {
5528         return RNP_ERROR_BAD_PARAMETERS;
5529     }
5530     op->cert.prefs.add_hash_alg(hash_alg);
5531     return RNP_SUCCESS;
5532 }
5533 FFI_GUARD
5534 
5535 rnp_result_t
rnp_op_generate_clear_pref_compression(rnp_op_generate_t op)5536 rnp_op_generate_clear_pref_compression(rnp_op_generate_t op)
5537 try {
5538     if (!op) {
5539         return RNP_ERROR_NULL_POINTER;
5540     }
5541     if (!op->primary) {
5542         return RNP_ERROR_BAD_PARAMETERS;
5543     }
5544     op->cert.prefs.set_z_algs({});
5545     return RNP_SUCCESS;
5546 }
5547 FFI_GUARD
5548 
5549 rnp_result_t
rnp_op_generate_add_pref_compression(rnp_op_generate_t op,const char * compression)5550 rnp_op_generate_add_pref_compression(rnp_op_generate_t op, const char *compression)
5551 try {
5552     if (!op || !compression) {
5553         return RNP_ERROR_NULL_POINTER;
5554     }
5555     if (!op->primary) {
5556         return RNP_ERROR_BAD_PARAMETERS;
5557     }
5558     pgp_compression_type_t z_alg = PGP_C_UNKNOWN;
5559     if (!str_to_compression_alg(compression, &z_alg)) {
5560         return RNP_ERROR_BAD_PARAMETERS;
5561     }
5562     op->cert.prefs.add_z_alg(z_alg);
5563     return RNP_SUCCESS;
5564 }
5565 FFI_GUARD
5566 
5567 rnp_result_t
rnp_op_generate_clear_pref_ciphers(rnp_op_generate_t op)5568 rnp_op_generate_clear_pref_ciphers(rnp_op_generate_t op)
5569 try {
5570     if (!op) {
5571         return RNP_ERROR_NULL_POINTER;
5572     }
5573     if (!op->primary) {
5574         return RNP_ERROR_BAD_PARAMETERS;
5575     }
5576     op->cert.prefs.set_symm_algs({});
5577     return RNP_SUCCESS;
5578 }
5579 FFI_GUARD
5580 
5581 rnp_result_t
rnp_op_generate_add_pref_cipher(rnp_op_generate_t op,const char * cipher)5582 rnp_op_generate_add_pref_cipher(rnp_op_generate_t op, const char *cipher)
5583 try {
5584     if (!op || !cipher) {
5585         return RNP_ERROR_NULL_POINTER;
5586     }
5587     if (!op->primary) {
5588         return RNP_ERROR_BAD_PARAMETERS;
5589     }
5590     pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN;
5591     if (!str_to_cipher(cipher, &symm_alg)) {
5592         return RNP_ERROR_BAD_PARAMETERS;
5593     }
5594     op->cert.prefs.add_symm_alg(symm_alg);
5595     return RNP_SUCCESS;
5596 }
5597 FFI_GUARD
5598 
5599 rnp_result_t
rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op,const char * keyserver)5600 rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op, const char *keyserver)
5601 try {
5602     if (!op) {
5603         return RNP_ERROR_NULL_POINTER;
5604     }
5605     if (!op->primary) {
5606         return RNP_ERROR_BAD_PARAMETERS;
5607     }
5608     op->cert.prefs.key_server = keyserver ? keyserver : "";
5609     return RNP_SUCCESS;
5610 }
5611 FFI_GUARD
5612 
5613 rnp_result_t
rnp_op_generate_execute(rnp_op_generate_t op)5614 rnp_op_generate_execute(rnp_op_generate_t op)
5615 try {
5616     if (!op || !op->ffi) {
5617         return RNP_ERROR_NULL_POINTER;
5618     }
5619 
5620     rnp_result_t            ret = RNP_ERROR_GENERIC;
5621     pgp_key_t               pub;
5622     pgp_key_t               sec;
5623     pgp_password_provider_t prov = {.callback = NULL};
5624 
5625     if (op->primary) {
5626         rnp_keygen_primary_desc_t keygen = {};
5627         keygen.crypto = op->crypto;
5628         keygen.cert = op->cert;
5629         op->cert.prefs = {}; /* generate call will free prefs */
5630 
5631         if (!pgp_generate_primary_key(keygen, true, sec, pub, op->ffi->secring->format)) {
5632             return RNP_ERROR_KEY_GENERATION;
5633         }
5634     } else {
5635         /* subkey generation */
5636         rnp_keygen_subkey_desc_t keygen = {};
5637         keygen.crypto = op->crypto;
5638         keygen.binding = op->binding;
5639         if (!pgp_generate_subkey(keygen,
5640                                  true,
5641                                  *op->primary_sec,
5642                                  *op->primary_pub,
5643                                  sec,
5644                                  pub,
5645                                  op->ffi->pass_provider,
5646                                  op->ffi->secring->format)) {
5647             return RNP_ERROR_KEY_GENERATION;
5648         }
5649     }
5650 
5651     /* add public key part to the keyring */
5652     if (!(op->gen_pub = rnp_key_store_add_key(op->ffi->pubring, &pub))) {
5653         ret = RNP_ERROR_OUT_OF_MEMORY;
5654         goto done;
5655     }
5656 
5657     /* encrypt secret key if requested */
5658     if (!op->password.empty()) {
5659         prov = {.callback = rnp_password_provider_string,
5660                 .userdata = (void *) op->password.data()};
5661     } else if (op->request_password) {
5662         prov = {.callback = rnp_password_cb_bounce, .userdata = op->ffi};
5663     }
5664     if (prov.callback && !sec.protect(op->protection, prov, op->ffi->rng())) {
5665         FFI_LOG(op->ffi, "failed to encrypt the key");
5666         ret = RNP_ERROR_BAD_PARAMETERS;
5667         goto done;
5668     }
5669 
5670     /* add secret key to the keyring */
5671     if (!(op->gen_sec = rnp_key_store_add_key(op->ffi->secring, &sec))) {
5672         ret = RNP_ERROR_OUT_OF_MEMORY;
5673         goto done;
5674     }
5675     ret = RNP_SUCCESS;
5676 done:
5677     op->password.clear();
5678     if (ret && op->gen_pub) {
5679         rnp_key_store_remove_key(op->ffi->pubring, op->gen_pub, false);
5680         op->gen_pub = NULL;
5681     }
5682     if (ret && op->gen_sec) {
5683         rnp_key_store_remove_key(op->ffi->secring, op->gen_sec, false);
5684         op->gen_sec = NULL;
5685     }
5686     return ret;
5687 }
5688 FFI_GUARD
5689 
5690 rnp_result_t
rnp_op_generate_get_key(rnp_op_generate_t op,rnp_key_handle_t * handle)5691 rnp_op_generate_get_key(rnp_op_generate_t op, rnp_key_handle_t *handle)
5692 try {
5693     if (!op || !handle) {
5694         return RNP_ERROR_NULL_POINTER;
5695     }
5696     if (!op->gen_sec || !op->gen_pub) {
5697         return RNP_ERROR_BAD_PARAMETERS;
5698     }
5699 
5700     *handle = (rnp_key_handle_t) malloc(sizeof(**handle));
5701     if (!*handle) {
5702         return RNP_ERROR_OUT_OF_MEMORY;
5703     }
5704     (*handle)->ffi = op->ffi;
5705     (*handle)->pub = op->gen_pub;
5706     (*handle)->sec = op->gen_sec;
5707     return RNP_SUCCESS;
5708 }
5709 FFI_GUARD
5710 
5711 rnp_result_t
rnp_op_generate_destroy(rnp_op_generate_t op)5712 rnp_op_generate_destroy(rnp_op_generate_t op)
5713 try {
5714     delete op;
5715     return RNP_SUCCESS;
5716 }
5717 FFI_GUARD
5718 
5719 rnp_result_t
rnp_key_handle_destroy(rnp_key_handle_t key)5720 rnp_key_handle_destroy(rnp_key_handle_t key)
5721 try {
5722     // This does not free key->key which is owned by the keyring
5723     free(key);
5724     return RNP_SUCCESS;
5725 }
5726 FFI_GUARD
5727 
5728 void
rnp_buffer_destroy(void * ptr)5729 rnp_buffer_destroy(void *ptr)
5730 {
5731     free(ptr);
5732 }
5733 
5734 void
rnp_buffer_clear(void * ptr,size_t size)5735 rnp_buffer_clear(void *ptr, size_t size)
5736 {
5737     if (ptr) {
5738         secure_clear(ptr, size);
5739     }
5740 }
5741 
5742 static pgp_key_t *
get_key_require_public(rnp_key_handle_t handle)5743 get_key_require_public(rnp_key_handle_t handle)
5744 {
5745     if (!handle->pub) {
5746         pgp_key_request_ctx_t request;
5747         request.secret = false;
5748 
5749         // try fingerprint
5750         request.search.type = PGP_KEY_SEARCH_FINGERPRINT;
5751         request.search.by.fingerprint = handle->sec->fp();
5752         handle->pub = pgp_request_key(&handle->ffi->key_provider, &request);
5753         if (handle->pub) {
5754             return handle->pub;
5755         }
5756 
5757         // try keyid
5758         request.search.type = PGP_KEY_SEARCH_KEYID;
5759         request.search.by.keyid = handle->sec->keyid();
5760         handle->pub = pgp_request_key(&handle->ffi->key_provider, &request);
5761     }
5762     return handle->pub;
5763 }
5764 
5765 static pgp_key_t *
get_key_prefer_public(rnp_key_handle_t handle)5766 get_key_prefer_public(rnp_key_handle_t handle)
5767 {
5768     pgp_key_t *pub = get_key_require_public(handle);
5769     return pub ? pub : get_key_require_secret(handle);
5770 }
5771 
5772 static pgp_key_t *
get_key_require_secret(rnp_key_handle_t handle)5773 get_key_require_secret(rnp_key_handle_t handle)
5774 {
5775     if (!handle->sec) {
5776         pgp_key_request_ctx_t request;
5777         request.secret = true;
5778 
5779         // try fingerprint
5780         request.search.type = PGP_KEY_SEARCH_FINGERPRINT;
5781         request.search.by.fingerprint = handle->pub->fp();
5782         handle->sec = pgp_request_key(&handle->ffi->key_provider, &request);
5783         if (handle->sec) {
5784             return handle->sec;
5785         }
5786 
5787         // try keyid
5788         request.search.type = PGP_KEY_SEARCH_KEYID;
5789         request.search.by.keyid = handle->pub->keyid();
5790         handle->sec = pgp_request_key(&handle->ffi->key_provider, &request);
5791     }
5792     return handle->sec;
5793 }
5794 
5795 static rnp_result_t
key_get_uid_at(pgp_key_t * key,size_t idx,char ** uid)5796 key_get_uid_at(pgp_key_t *key, size_t idx, char **uid)
5797 {
5798     if (!key || !uid) {
5799         return RNP_ERROR_NULL_POINTER;
5800     }
5801     if (idx >= key->uid_count()) {
5802         return RNP_ERROR_BAD_PARAMETERS;
5803     }
5804     *uid = strdup(key->get_uid(idx).str.c_str());
5805     if (!*uid) {
5806         return RNP_ERROR_OUT_OF_MEMORY;
5807     }
5808     return RNP_SUCCESS;
5809 }
5810 
5811 rnp_result_t
rnp_key_add_uid(rnp_key_handle_t handle,const char * uid,const char * hash,uint32_t expiration,uint8_t key_flags,bool primary)5812 rnp_key_add_uid(rnp_key_handle_t handle,
5813                 const char *     uid,
5814                 const char *     hash,
5815                 uint32_t         expiration,
5816                 uint8_t          key_flags,
5817                 bool             primary)
5818 try {
5819     if (!handle || !uid) {
5820         return RNP_ERROR_NULL_POINTER;
5821     }
5822     /* setup parameters */
5823     if (!hash) {
5824         hash = DEFAULT_HASH_ALG;
5825     }
5826     pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN;
5827     if (!str_to_hash_alg(hash, &hash_alg)) {
5828         FFI_LOG(handle->ffi, "Invalid hash: %s", hash);
5829         return RNP_ERROR_BAD_PARAMETERS;
5830     }
5831 
5832     rnp_selfsig_cert_info_t info = {};
5833     size_t                  uid_len = strlen(uid);
5834     if (uid_len >= sizeof(info.userid)) {
5835         FFI_LOG(handle->ffi, "UserID too long");
5836         return RNP_ERROR_BAD_PARAMETERS;
5837     }
5838     memcpy(info.userid, uid, uid_len + 1);
5839     info.key_flags = key_flags;
5840     info.key_expiration = expiration;
5841     info.primary = primary;
5842 
5843     /* obtain and unlok secret key */
5844     pgp_key_t *secret_key = get_key_require_secret(handle);
5845     if (!secret_key) {
5846         return RNP_ERROR_NO_SUITABLE_KEY;
5847     }
5848     pgp_key_t *public_key = get_key_prefer_public(handle);
5849     if (!public_key && secret_key->format == PGP_KEY_STORE_G10) {
5850         return RNP_ERROR_NO_SUITABLE_KEY;
5851     }
5852     rnp::KeyLocker seclock(*secret_key);
5853     if (secret_key->is_locked() &&
5854         !secret_key->unlock(handle->ffi->pass_provider, PGP_OP_ADD_USERID)) {
5855         return RNP_ERROR_BAD_PASSWORD;
5856     }
5857     /* add and certify userid */
5858     secret_key->add_uid_cert(info, hash_alg, handle->ffi->context, public_key);
5859     return RNP_SUCCESS;
5860 }
5861 FFI_GUARD
5862 
5863 rnp_result_t
rnp_key_get_primary_uid(rnp_key_handle_t handle,char ** uid)5864 rnp_key_get_primary_uid(rnp_key_handle_t handle, char **uid)
5865 try {
5866     if (!handle || !uid) {
5867         return RNP_ERROR_NULL_POINTER;
5868     }
5869 
5870     pgp_key_t *key = get_key_prefer_public(handle);
5871     if (key->has_primary_uid()) {
5872         return key_get_uid_at(key, key->get_primary_uid(), uid);
5873     }
5874     for (size_t i = 0; i < key->uid_count(); i++) {
5875         if (!key->get_uid(i).valid) {
5876             continue;
5877         }
5878         return key_get_uid_at(key, i, uid);
5879     }
5880     return RNP_ERROR_BAD_PARAMETERS;
5881 }
5882 FFI_GUARD
5883 
5884 rnp_result_t
rnp_key_get_uid_count(rnp_key_handle_t handle,size_t * count)5885 rnp_key_get_uid_count(rnp_key_handle_t handle, size_t *count)
5886 try {
5887     if (!handle || !count) {
5888         return RNP_ERROR_NULL_POINTER;
5889     }
5890 
5891     *count = get_key_prefer_public(handle)->uid_count();
5892     return RNP_SUCCESS;
5893 }
5894 FFI_GUARD
5895 
5896 rnp_result_t
rnp_key_get_uid_at(rnp_key_handle_t handle,size_t idx,char ** uid)5897 rnp_key_get_uid_at(rnp_key_handle_t handle, size_t idx, char **uid)
5898 try {
5899     if (handle == NULL || uid == NULL)
5900         return RNP_ERROR_NULL_POINTER;
5901 
5902     pgp_key_t *key = get_key_prefer_public(handle);
5903     return key_get_uid_at(key, idx, uid);
5904 }
5905 FFI_GUARD
5906 
5907 rnp_result_t
rnp_key_get_uid_handle_at(rnp_key_handle_t key,size_t idx,rnp_uid_handle_t * uid)5908 rnp_key_get_uid_handle_at(rnp_key_handle_t key, size_t idx, rnp_uid_handle_t *uid)
5909 try {
5910     if (!key || !uid) {
5911         return RNP_ERROR_NULL_POINTER;
5912     }
5913 
5914     pgp_key_t *akey = get_key_prefer_public(key);
5915     if (!akey) {
5916         return RNP_ERROR_BAD_PARAMETERS;
5917     }
5918 
5919     if (idx >= akey->uid_count()) {
5920         return RNP_ERROR_BAD_PARAMETERS;
5921     }
5922 
5923     *uid = (rnp_uid_handle_t) malloc(sizeof(**uid));
5924     if (!*uid) {
5925         return RNP_ERROR_OUT_OF_MEMORY;
5926     }
5927 
5928     (*uid)->ffi = key->ffi;
5929     (*uid)->key = akey;
5930     (*uid)->idx = idx;
5931     return RNP_SUCCESS;
5932 }
5933 FFI_GUARD
5934 
5935 static pgp_userid_t *
rnp_uid_handle_get_uid(rnp_uid_handle_t uid)5936 rnp_uid_handle_get_uid(rnp_uid_handle_t uid)
5937 {
5938     if (!uid || !uid->key) {
5939         return NULL;
5940     }
5941     return &uid->key->get_uid(uid->idx);
5942 }
5943 
5944 rnp_result_t
rnp_uid_get_type(rnp_uid_handle_t uid,uint32_t * type)5945 rnp_uid_get_type(rnp_uid_handle_t uid, uint32_t *type)
5946 try {
5947     if (!type) {
5948         return RNP_ERROR_NULL_POINTER;
5949     }
5950     pgp_userid_t *id = rnp_uid_handle_get_uid(uid);
5951     if (!id) {
5952         return RNP_ERROR_NULL_POINTER;
5953     }
5954     switch (id->pkt.tag) {
5955     case PGP_PKT_USER_ID:
5956         *type = RNP_USER_ID;
5957         return RNP_SUCCESS;
5958     case PGP_PKT_USER_ATTR:
5959         *type = RNP_USER_ATTR;
5960         return RNP_SUCCESS;
5961     default:
5962         return RNP_ERROR_BAD_STATE;
5963     }
5964 }
5965 FFI_GUARD
5966 
5967 rnp_result_t
rnp_uid_get_data(rnp_uid_handle_t uid,void ** data,size_t * size)5968 rnp_uid_get_data(rnp_uid_handle_t uid, void **data, size_t *size)
5969 try {
5970     if (!data || !size) {
5971         return RNP_ERROR_NULL_POINTER;
5972     }
5973     pgp_userid_t *id = rnp_uid_handle_get_uid(uid);
5974     if (!id) {
5975         return RNP_ERROR_NULL_POINTER;
5976     }
5977     *data = malloc(id->pkt.uid_len);
5978     if (id->pkt.uid_len && !*data) {
5979         return RNP_ERROR_OUT_OF_MEMORY;
5980     }
5981     memcpy(*data, id->pkt.uid, id->pkt.uid_len);
5982     *size = id->pkt.uid_len;
5983     return RNP_SUCCESS;
5984 }
5985 FFI_GUARD
5986 
5987 rnp_result_t
rnp_uid_is_primary(rnp_uid_handle_t uid,bool * primary)5988 rnp_uid_is_primary(rnp_uid_handle_t uid, bool *primary)
5989 try {
5990     if (!primary) {
5991         return RNP_ERROR_NULL_POINTER;
5992     }
5993     pgp_userid_t *id = rnp_uid_handle_get_uid(uid);
5994     if (!id) {
5995         return RNP_ERROR_NULL_POINTER;
5996     }
5997     *primary = uid->key->has_primary_uid() && (uid->key->get_primary_uid() == uid->idx);
5998     return RNP_SUCCESS;
5999 }
6000 FFI_GUARD
6001 
6002 rnp_result_t
rnp_uid_is_valid(rnp_uid_handle_t uid,bool * valid)6003 rnp_uid_is_valid(rnp_uid_handle_t uid, bool *valid)
6004 try {
6005     if (!valid) {
6006         return RNP_ERROR_NULL_POINTER;
6007     }
6008     pgp_userid_t *id = rnp_uid_handle_get_uid(uid);
6009     if (!id) {
6010         return RNP_ERROR_NULL_POINTER;
6011     }
6012     *valid = id->valid;
6013     return RNP_SUCCESS;
6014 }
6015 FFI_GUARD
6016 
6017 static rnp_result_t
rnp_key_return_signature(rnp_ffi_t ffi,pgp_key_t * key,pgp_subsig_t * subsig,rnp_signature_handle_t * sig)6018 rnp_key_return_signature(rnp_ffi_t               ffi,
6019                          pgp_key_t *             key,
6020                          pgp_subsig_t *          subsig,
6021                          rnp_signature_handle_t *sig)
6022 {
6023     *sig = (rnp_signature_handle_t) calloc(1, sizeof(**sig));
6024     if (!*sig) {
6025         return RNP_ERROR_OUT_OF_MEMORY;
6026     }
6027     (*sig)->ffi = ffi;
6028     (*sig)->key = key;
6029     (*sig)->sig = subsig;
6030     return RNP_SUCCESS;
6031 }
6032 
6033 rnp_result_t
rnp_key_get_signature_count(rnp_key_handle_t handle,size_t * count)6034 rnp_key_get_signature_count(rnp_key_handle_t handle, size_t *count)
6035 try {
6036     if (!handle || !count) {
6037         return RNP_ERROR_NULL_POINTER;
6038     }
6039     pgp_key_t *key = get_key_prefer_public(handle);
6040     if (!key) {
6041         return RNP_ERROR_BAD_PARAMETERS;
6042     }
6043     *count = key->keysig_count();
6044     return RNP_SUCCESS;
6045 }
6046 FFI_GUARD
6047 
6048 rnp_result_t
rnp_key_get_signature_at(rnp_key_handle_t handle,size_t idx,rnp_signature_handle_t * sig)6049 rnp_key_get_signature_at(rnp_key_handle_t handle, size_t idx, rnp_signature_handle_t *sig)
6050 try {
6051     if (!handle || !sig) {
6052         return RNP_ERROR_NULL_POINTER;
6053     }
6054 
6055     pgp_key_t *key = get_key_prefer_public(handle);
6056     if (!key || (idx >= key->keysig_count())) {
6057         return RNP_ERROR_BAD_PARAMETERS;
6058     }
6059     return rnp_key_return_signature(handle->ffi, key, &key->get_keysig(idx), sig);
6060 }
6061 FFI_GUARD
6062 
6063 rnp_result_t
rnp_key_get_revocation_signature(rnp_key_handle_t handle,rnp_signature_handle_t * sig)6064 rnp_key_get_revocation_signature(rnp_key_handle_t handle, rnp_signature_handle_t *sig)
6065 try {
6066     if (!handle || !sig) {
6067         return RNP_ERROR_NULL_POINTER;
6068     }
6069     pgp_key_t *key = get_key_prefer_public(handle);
6070     if (!key) {
6071         return RNP_ERROR_BAD_PARAMETERS;
6072     }
6073     if (!key->revoked()) {
6074         *sig = NULL;
6075         return RNP_SUCCESS;
6076     }
6077     if (!key->has_sig(key->revocation().sigid)) {
6078         return RNP_ERROR_BAD_STATE;
6079     }
6080     return rnp_key_return_signature(
6081       handle->ffi, key, &key->get_sig(key->revocation().sigid), sig);
6082 }
6083 FFI_GUARD
6084 
6085 rnp_result_t
rnp_uid_get_signature_count(rnp_uid_handle_t handle,size_t * count)6086 rnp_uid_get_signature_count(rnp_uid_handle_t handle, size_t *count)
6087 try {
6088     if (!handle || !count) {
6089         return RNP_ERROR_NULL_POINTER;
6090     }
6091     if (!handle->key) {
6092         return RNP_ERROR_BAD_PARAMETERS;
6093     }
6094     *count = handle->key->get_uid(handle->idx).sig_count();
6095     return RNP_SUCCESS;
6096 }
6097 FFI_GUARD
6098 
6099 rnp_result_t
rnp_uid_get_signature_at(rnp_uid_handle_t handle,size_t idx,rnp_signature_handle_t * sig)6100 rnp_uid_get_signature_at(rnp_uid_handle_t handle, size_t idx, rnp_signature_handle_t *sig)
6101 try {
6102     if (!handle || !sig) {
6103         return RNP_ERROR_NULL_POINTER;
6104     }
6105     if (!handle->key) {
6106         return RNP_ERROR_BAD_PARAMETERS;
6107     }
6108     pgp_userid_t &uid = handle->key->get_uid(handle->idx);
6109     if (idx >= uid.sig_count()) {
6110         return RNP_ERROR_BAD_PARAMETERS;
6111     }
6112     const pgp_sig_id_t &sigid = uid.get_sig(idx);
6113     if (!handle->key->has_sig(sigid)) {
6114         return RNP_ERROR_BAD_STATE;
6115     }
6116     return rnp_key_return_signature(
6117       handle->ffi, handle->key, &handle->key->get_sig(sigid), sig);
6118 }
6119 FFI_GUARD
6120 
6121 rnp_result_t
rnp_signature_get_type(rnp_signature_handle_t handle,char ** type)6122 rnp_signature_get_type(rnp_signature_handle_t handle, char **type)
6123 try {
6124     if (!handle || !type) {
6125         return RNP_ERROR_NULL_POINTER;
6126     }
6127     if (!handle->sig) {
6128         return RNP_ERROR_BAD_PARAMETERS;
6129     }
6130     auto sigtype = id_str_pair::lookup(sig_type_map, handle->sig->sig.type());
6131     return ret_str_value(sigtype, type);
6132 }
6133 FFI_GUARD
6134 
6135 rnp_result_t
rnp_signature_get_alg(rnp_signature_handle_t handle,char ** alg)6136 rnp_signature_get_alg(rnp_signature_handle_t handle, char **alg)
6137 try {
6138     if (!handle || !alg) {
6139         return RNP_ERROR_NULL_POINTER;
6140     }
6141     if (!handle->sig) {
6142         return RNP_ERROR_BAD_PARAMETERS;
6143     }
6144     return get_map_value(pubkey_alg_map, handle->sig->sig.palg, alg);
6145 }
6146 FFI_GUARD
6147 
6148 rnp_result_t
rnp_signature_get_hash_alg(rnp_signature_handle_t handle,char ** alg)6149 rnp_signature_get_hash_alg(rnp_signature_handle_t handle, char **alg)
6150 try {
6151     if (!handle || !alg) {
6152         return RNP_ERROR_NULL_POINTER;
6153     }
6154     if (!handle->sig) {
6155         return RNP_ERROR_BAD_PARAMETERS;
6156     }
6157     return get_map_value(hash_alg_map, handle->sig->sig.halg, alg);
6158 }
6159 FFI_GUARD
6160 
6161 rnp_result_t
rnp_signature_get_creation(rnp_signature_handle_t handle,uint32_t * create)6162 rnp_signature_get_creation(rnp_signature_handle_t handle, uint32_t *create)
6163 try {
6164     if (!handle || !create) {
6165         return RNP_ERROR_NULL_POINTER;
6166     }
6167     if (!handle->sig) {
6168         return RNP_ERROR_BAD_PARAMETERS;
6169     }
6170     *create = handle->sig->sig.creation();
6171     return RNP_SUCCESS;
6172 }
6173 FFI_GUARD
6174 
6175 rnp_result_t
rnp_signature_get_expiration(rnp_signature_handle_t handle,uint32_t * expires)6176 rnp_signature_get_expiration(rnp_signature_handle_t handle, uint32_t *expires)
6177 try {
6178     if (!handle || !expires) {
6179         return RNP_ERROR_NULL_POINTER;
6180     }
6181     if (!handle->sig) {
6182         return RNP_ERROR_BAD_PARAMETERS;
6183     }
6184     *expires = handle->sig->sig.expiration();
6185     return RNP_SUCCESS;
6186 }
6187 FFI_GUARD
6188 
6189 rnp_result_t
rnp_signature_get_keyid(rnp_signature_handle_t handle,char ** result)6190 rnp_signature_get_keyid(rnp_signature_handle_t handle, char **result)
6191 try {
6192     if (!handle || !result) {
6193         return RNP_ERROR_NULL_POINTER;
6194     }
6195     if (!handle->sig) {
6196         return RNP_ERROR_BAD_PARAMETERS;
6197     }
6198     if (!handle->sig->sig.has_keyid()) {
6199         *result = NULL;
6200         return RNP_SUCCESS;
6201     }
6202     pgp_key_id_t keyid = handle->sig->sig.keyid();
6203     return hex_encode_value(keyid.data(), keyid.size(), result);
6204 }
6205 FFI_GUARD
6206 
6207 rnp_result_t
rnp_signature_get_signer(rnp_signature_handle_t sig,rnp_key_handle_t * key)6208 rnp_signature_get_signer(rnp_signature_handle_t sig, rnp_key_handle_t *key)
6209 try {
6210     if (!sig || !sig->sig) {
6211         return RNP_ERROR_BAD_PARAMETERS;
6212     }
6213     if (!sig->sig->sig.has_keyid()) {
6214         *key = NULL;
6215         return RNP_SUCCESS;
6216     }
6217     pgp_key_search_t locator = {};
6218     locator.type = PGP_KEY_SEARCH_KEYID;
6219     locator.by.keyid = sig->sig->sig.keyid();
6220     return rnp_locate_key_int(sig->ffi, locator, key);
6221 }
6222 FFI_GUARD
6223 
6224 rnp_result_t
rnp_signature_is_valid(rnp_signature_handle_t sig,uint32_t flags)6225 rnp_signature_is_valid(rnp_signature_handle_t sig, uint32_t flags)
6226 try {
6227     if (!sig) {
6228         return RNP_ERROR_NULL_POINTER;
6229     }
6230     if (!sig->sig || sig->own_sig || flags) {
6231         return RNP_ERROR_BAD_PARAMETERS;
6232     }
6233 
6234     if (!sig->sig->validity.validated) {
6235         pgp_key_t *signer =
6236           pgp_sig_get_signer(*sig->sig, sig->ffi->pubring, &sig->ffi->key_provider);
6237         if (!signer) {
6238             return RNP_ERROR_KEY_NOT_FOUND;
6239         }
6240         signer->validate_sig(*sig->key, *sig->sig, sig->ffi->context);
6241     }
6242 
6243     if (!sig->sig->validity.validated) {
6244         return RNP_ERROR_VERIFICATION_FAILED;
6245     }
6246     if (sig->sig->validity.expired) {
6247         return RNP_ERROR_SIGNATURE_EXPIRED;
6248     }
6249     return sig->sig->valid() ? RNP_SUCCESS : RNP_ERROR_SIGNATURE_INVALID;
6250 }
6251 FFI_GUARD
6252 
6253 rnp_result_t
rnp_signature_packet_to_json(rnp_signature_handle_t sig,uint32_t flags,char ** json)6254 rnp_signature_packet_to_json(rnp_signature_handle_t sig, uint32_t flags, char **json)
6255 try {
6256     if (!sig || !json) {
6257         return RNP_ERROR_NULL_POINTER;
6258     }
6259 
6260     pgp_dest_t memdst = {};
6261     if (init_mem_dest(&memdst, NULL, 0)) {
6262         return RNP_ERROR_OUT_OF_MEMORY;
6263     }
6264     try {
6265         sig->sig->sig.write(memdst);
6266     } catch (const std::exception &e) {
6267         FFI_LOG(sig->ffi, "%s", e.what());
6268         dst_close(&memdst, true);
6269         return RNP_ERROR_BAD_PARAMETERS;
6270     }
6271 
6272     pgp_source_t memsrc = {};
6273     rnp_result_t ret = RNP_ERROR_BAD_STATE;
6274     if (init_mem_src(&memsrc, mem_dest_get_memory(&memdst), memdst.writeb, false)) {
6275         goto done;
6276     }
6277 
6278     ret = rnp_dump_src_to_json(&memsrc, flags, json);
6279 done:
6280     dst_close(&memdst, true);
6281     src_close(&memsrc);
6282     return ret;
6283 }
6284 FFI_GUARD
6285 
6286 rnp_result_t
rnp_signature_remove(rnp_key_handle_t key,rnp_signature_handle_t sig)6287 rnp_signature_remove(rnp_key_handle_t key, rnp_signature_handle_t sig)
6288 try {
6289     if (!key || !sig) {
6290         return RNP_ERROR_NULL_POINTER;
6291     }
6292     if (sig->own_sig || !sig->sig) {
6293         return RNP_ERROR_BAD_PARAMETERS;
6294     }
6295     pgp_key_t *pkey = get_key_require_public(key);
6296     pgp_key_t *skey = get_key_require_secret(key);
6297     if (!pkey && !skey) {
6298         return RNP_ERROR_BAD_PARAMETERS;
6299     }
6300     const pgp_sig_id_t sigid = sig->sig->sigid;
6301     bool               ok = false;
6302     if (pkey) {
6303         ok = pkey->del_sig(sigid);
6304         pkey->revalidate(*key->ffi->pubring);
6305     }
6306     if (skey) {
6307         /* secret key may not have signature, but we still need to delete it at least once to
6308          * succeed */
6309         ok = skey->del_sig(sigid) || ok;
6310         skey->revalidate(*key->ffi->secring);
6311     }
6312     return ok ? RNP_SUCCESS : RNP_ERROR_NO_SIGNATURES_FOUND;
6313 }
6314 FFI_GUARD
6315 
6316 rnp_result_t
rnp_signature_handle_destroy(rnp_signature_handle_t sig)6317 rnp_signature_handle_destroy(rnp_signature_handle_t sig)
6318 try {
6319     if (sig && sig->own_sig) {
6320         delete sig->sig;
6321     }
6322     free(sig);
6323     return RNP_SUCCESS;
6324 }
6325 FFI_GUARD
6326 
6327 rnp_result_t
rnp_uid_is_revoked(rnp_uid_handle_t uid,bool * result)6328 rnp_uid_is_revoked(rnp_uid_handle_t uid, bool *result)
6329 try {
6330     if (!uid || !result) {
6331         return RNP_ERROR_NULL_POINTER;
6332     }
6333 
6334     if (!uid->key) {
6335         return RNP_ERROR_BAD_PARAMETERS;
6336     }
6337 
6338     *result = uid->key->get_uid(uid->idx).revoked;
6339     return RNP_SUCCESS;
6340 }
6341 FFI_GUARD
6342 
6343 rnp_result_t
rnp_uid_get_revocation_signature(rnp_uid_handle_t uid,rnp_signature_handle_t * sig)6344 rnp_uid_get_revocation_signature(rnp_uid_handle_t uid, rnp_signature_handle_t *sig)
6345 try {
6346     if (!uid || !sig) {
6347         return RNP_ERROR_NULL_POINTER;
6348     }
6349     if (!uid->key) {
6350         return RNP_ERROR_BAD_PARAMETERS;
6351     }
6352     if (uid->idx >= uid->key->uid_count()) {
6353         return RNP_ERROR_BAD_STATE;
6354     }
6355     const pgp_userid_t &userid = uid->key->get_uid(uid->idx);
6356     if (!userid.revoked) {
6357         *sig = NULL;
6358         return RNP_SUCCESS;
6359     }
6360     if (!uid->key->has_sig(userid.revocation.sigid)) {
6361         return RNP_ERROR_BAD_STATE;
6362     }
6363     return rnp_key_return_signature(
6364       uid->ffi, uid->key, &uid->key->get_sig(userid.revocation.sigid), sig);
6365 }
6366 FFI_GUARD
6367 
6368 rnp_result_t
rnp_uid_remove(rnp_key_handle_t key,rnp_uid_handle_t uid)6369 rnp_uid_remove(rnp_key_handle_t key, rnp_uid_handle_t uid)
6370 try {
6371     if (!key || !uid) {
6372         return RNP_ERROR_NULL_POINTER;
6373     }
6374     pgp_key_t *pkey = get_key_require_public(key);
6375     pgp_key_t *skey = get_key_require_secret(key);
6376     if (!pkey && !skey) {
6377         return RNP_ERROR_BAD_PARAMETERS;
6378     }
6379     if ((uid->key != pkey) && (uid->key != skey)) {
6380         return RNP_ERROR_BAD_PARAMETERS;
6381     }
6382 
6383     bool ok = false;
6384     if (pkey && (pkey->uid_count() > uid->idx)) {
6385         pkey->del_uid(uid->idx);
6386         pkey->revalidate(*key->ffi->pubring);
6387         ok = true;
6388     }
6389     if (skey && (skey->uid_count() > uid->idx)) {
6390         skey->del_uid(uid->idx);
6391         skey->revalidate(*key->ffi->secring);
6392         ok = true;
6393     }
6394     return ok ? RNP_SUCCESS : RNP_ERROR_BAD_PARAMETERS;
6395 }
6396 FFI_GUARD
6397 
6398 rnp_result_t
rnp_uid_handle_destroy(rnp_uid_handle_t uid)6399 rnp_uid_handle_destroy(rnp_uid_handle_t uid)
6400 try {
6401     free(uid);
6402     return RNP_SUCCESS;
6403 }
6404 FFI_GUARD
6405 
6406 rnp_result_t
rnp_key_get_subkey_count(rnp_key_handle_t handle,size_t * count)6407 rnp_key_get_subkey_count(rnp_key_handle_t handle, size_t *count)
6408 try {
6409     if (!handle || !count) {
6410         return RNP_ERROR_NULL_POINTER;
6411     }
6412     pgp_key_t *key = get_key_prefer_public(handle);
6413     *count = key->subkey_count();
6414     return RNP_SUCCESS;
6415 }
6416 FFI_GUARD
6417 
6418 rnp_result_t
rnp_key_get_subkey_at(rnp_key_handle_t handle,size_t idx,rnp_key_handle_t * subkey)6419 rnp_key_get_subkey_at(rnp_key_handle_t handle, size_t idx, rnp_key_handle_t *subkey)
6420 try {
6421     if (!handle || !subkey) {
6422         return RNP_ERROR_NULL_POINTER;
6423     }
6424     pgp_key_t *key = get_key_prefer_public(handle);
6425     if (idx >= key->subkey_count()) {
6426         return RNP_ERROR_BAD_PARAMETERS;
6427     }
6428     pgp_key_search_t locator = {};
6429     locator.type = PGP_KEY_SEARCH_FINGERPRINT;
6430     locator.by.fingerprint = key->get_subkey_fp(idx);
6431     return rnp_locate_key_int(handle->ffi, locator, subkey);
6432 }
6433 FFI_GUARD
6434 
6435 rnp_result_t
rnp_key_get_default_key(rnp_key_handle_t primary_key,const char * usage,uint32_t flags,rnp_key_handle_t * default_key)6436 rnp_key_get_default_key(rnp_key_handle_t  primary_key,
6437                         const char *      usage,
6438                         uint32_t          flags,
6439                         rnp_key_handle_t *default_key)
6440 try {
6441     if (!primary_key || !usage || !default_key) {
6442         return RNP_ERROR_NULL_POINTER;
6443     }
6444     uint8_t keyflag = 0;
6445     bool    no_primary = false;
6446     if (!str_to_key_flag(usage, &keyflag)) {
6447         return RNP_ERROR_BAD_PARAMETERS;
6448     }
6449     if (flags & RNP_KEY_SUBKEYS_ONLY) {
6450         no_primary = true;
6451         flags &= ~RNP_KEY_SUBKEYS_ONLY;
6452     }
6453     if (flags) {
6454         FFI_LOG(primary_key->ffi, "Invalid flags: %" PRIu32, flags);
6455         return RNP_ERROR_BAD_PARAMETERS;
6456     }
6457     pgp_key_t *key = get_key_prefer_public(primary_key);
6458     if (!key) {
6459         return RNP_ERROR_BAD_PARAMETERS;
6460     }
6461     pgp_key_t *defkey = find_suitable_key(
6462       PGP_OP_UNKNOWN, key, &primary_key->ffi->key_provider, keyflag, no_primary);
6463     if (!defkey) {
6464         *default_key = NULL;
6465         return RNP_ERROR_NO_SUITABLE_KEY;
6466     }
6467 
6468     pgp_key_search_t search = {(pgp_key_search_type_t) 0};
6469     search.type = PGP_KEY_SEARCH_FINGERPRINT;
6470     search.by.fingerprint = defkey->fp();
6471 
6472     bool         require_secret = keyflag != PGP_KF_ENCRYPT;
6473     rnp_result_t ret =
6474       rnp_locate_key_int(primary_key->ffi, search, default_key, require_secret);
6475 
6476     if (!*default_key && !ret) {
6477         return RNP_ERROR_NO_SUITABLE_KEY;
6478     }
6479 
6480     return ret;
6481 }
6482 FFI_GUARD
6483 
6484 rnp_result_t
rnp_key_get_alg(rnp_key_handle_t handle,char ** alg)6485 rnp_key_get_alg(rnp_key_handle_t handle, char **alg)
6486 try {
6487     if (!handle || !alg) {
6488         return RNP_ERROR_NULL_POINTER;
6489     }
6490     pgp_key_t *key = get_key_prefer_public(handle);
6491     return get_map_value(pubkey_alg_map, key->alg(), alg);
6492 }
6493 FFI_GUARD
6494 
6495 rnp_result_t
rnp_key_get_bits(rnp_key_handle_t handle,uint32_t * bits)6496 rnp_key_get_bits(rnp_key_handle_t handle, uint32_t *bits)
6497 try {
6498     if (!handle || !bits) {
6499         return RNP_ERROR_NULL_POINTER;
6500     }
6501     pgp_key_t *key = get_key_prefer_public(handle);
6502     size_t     _bits = key->material().bits();
6503     if (!_bits) {
6504         return RNP_ERROR_BAD_PARAMETERS;
6505     }
6506     *bits = _bits;
6507     return RNP_SUCCESS;
6508 }
6509 FFI_GUARD
6510 
6511 rnp_result_t
rnp_key_get_dsa_qbits(rnp_key_handle_t handle,uint32_t * qbits)6512 rnp_key_get_dsa_qbits(rnp_key_handle_t handle, uint32_t *qbits)
6513 try {
6514     if (!handle || !qbits) {
6515         return RNP_ERROR_NULL_POINTER;
6516     }
6517     pgp_key_t *key = get_key_prefer_public(handle);
6518     size_t     _qbits = key->material().qbits();
6519     if (!_qbits) {
6520         return RNP_ERROR_BAD_PARAMETERS;
6521     }
6522     *qbits = _qbits;
6523     return RNP_SUCCESS;
6524 }
6525 FFI_GUARD
6526 
6527 rnp_result_t
rnp_key_get_curve(rnp_key_handle_t handle,char ** curve)6528 rnp_key_get_curve(rnp_key_handle_t handle, char **curve)
6529 try {
6530     if (!handle || !curve) {
6531         return RNP_ERROR_NULL_POINTER;
6532     }
6533     pgp_key_t * key = get_key_prefer_public(handle);
6534     pgp_curve_t _curve = key->curve();
6535     if (_curve == PGP_CURVE_UNKNOWN) {
6536         return RNP_ERROR_BAD_PARAMETERS;
6537     }
6538     const char *curvename = NULL;
6539     if (!curve_type_to_str(_curve, &curvename)) {
6540         return RNP_ERROR_BAD_PARAMETERS;
6541     }
6542     char *curvenamecp = strdup(curvename);
6543     if (!curvenamecp) {
6544         return RNP_ERROR_OUT_OF_MEMORY;
6545     }
6546     *curve = curvenamecp;
6547     return RNP_SUCCESS;
6548 }
6549 FFI_GUARD
6550 
6551 rnp_result_t
rnp_key_get_fprint(rnp_key_handle_t handle,char ** fprint)6552 rnp_key_get_fprint(rnp_key_handle_t handle, char **fprint)
6553 try {
6554     if (!handle || !fprint) {
6555         return RNP_ERROR_NULL_POINTER;
6556     }
6557 
6558     const pgp_fingerprint_t &fp = get_key_prefer_public(handle)->fp();
6559     return hex_encode_value(fp.fingerprint, fp.length, fprint);
6560 }
6561 FFI_GUARD
6562 
6563 rnp_result_t
rnp_key_get_keyid(rnp_key_handle_t handle,char ** keyid)6564 rnp_key_get_keyid(rnp_key_handle_t handle, char **keyid)
6565 try {
6566     if (!handle || !keyid) {
6567         return RNP_ERROR_NULL_POINTER;
6568     }
6569 
6570     pgp_key_t *key = get_key_prefer_public(handle);
6571     return hex_encode_value(key->keyid().data(), key->keyid().size(), keyid);
6572 }
6573 FFI_GUARD
6574 
6575 rnp_result_t
rnp_key_get_grip(rnp_key_handle_t handle,char ** grip)6576 rnp_key_get_grip(rnp_key_handle_t handle, char **grip)
6577 try {
6578     if (!handle || !grip) {
6579         return RNP_ERROR_NULL_POINTER;
6580     }
6581 
6582     const pgp_key_grip_t &kgrip = get_key_prefer_public(handle)->grip();
6583     return hex_encode_value(kgrip.data(), kgrip.size(), grip);
6584 }
6585 FFI_GUARD
6586 
6587 static const pgp_key_grip_t *
rnp_get_grip_by_fp(rnp_ffi_t ffi,const pgp_fingerprint_t & fp)6588 rnp_get_grip_by_fp(rnp_ffi_t ffi, const pgp_fingerprint_t &fp)
6589 {
6590     pgp_key_t *key = NULL;
6591     if (ffi->pubring) {
6592         key = rnp_key_store_get_key_by_fpr(ffi->pubring, fp);
6593     }
6594     if (!key && ffi->secring) {
6595         key = rnp_key_store_get_key_by_fpr(ffi->secring, fp);
6596     }
6597     return key ? &key->grip() : NULL;
6598 }
6599 
6600 rnp_result_t
rnp_key_get_primary_grip(rnp_key_handle_t handle,char ** grip)6601 rnp_key_get_primary_grip(rnp_key_handle_t handle, char **grip)
6602 try {
6603     if (!handle || !grip) {
6604         return RNP_ERROR_NULL_POINTER;
6605     }
6606 
6607     pgp_key_t *key = get_key_prefer_public(handle);
6608     if (!key->is_subkey()) {
6609         return RNP_ERROR_BAD_PARAMETERS;
6610     }
6611     if (!key->has_primary_fp()) {
6612         *grip = NULL;
6613         return RNP_SUCCESS;
6614     }
6615     const pgp_key_grip_t *pgrip = rnp_get_grip_by_fp(handle->ffi, key->primary_fp());
6616     if (!pgrip) {
6617         *grip = NULL;
6618         return RNP_SUCCESS;
6619     }
6620     return hex_encode_value(pgrip->data(), pgrip->size(), grip);
6621 }
6622 FFI_GUARD
6623 
6624 rnp_result_t
rnp_key_get_primary_fprint(rnp_key_handle_t handle,char ** fprint)6625 rnp_key_get_primary_fprint(rnp_key_handle_t handle, char **fprint)
6626 try {
6627     if (!handle || !fprint) {
6628         return RNP_ERROR_NULL_POINTER;
6629     }
6630 
6631     pgp_key_t *key = get_key_prefer_public(handle);
6632     if (!key->is_subkey()) {
6633         return RNP_ERROR_BAD_PARAMETERS;
6634     }
6635     if (!key->has_primary_fp()) {
6636         *fprint = NULL;
6637         return RNP_SUCCESS;
6638     }
6639     const pgp_fingerprint_t &fp = key->primary_fp();
6640     return hex_encode_value(fp.fingerprint, fp.length, fprint);
6641 }
6642 FFI_GUARD
6643 
6644 rnp_result_t
rnp_key_allows_usage(rnp_key_handle_t handle,const char * usage,bool * result)6645 rnp_key_allows_usage(rnp_key_handle_t handle, const char *usage, bool *result)
6646 try {
6647     if (!handle || !usage || !result) {
6648         return RNP_ERROR_NULL_POINTER;
6649     }
6650     uint8_t flag = 0;
6651     if (!str_to_key_flag(usage, &flag)) {
6652         return RNP_ERROR_BAD_PARAMETERS;
6653     }
6654     pgp_key_t *key = get_key_prefer_public(handle);
6655     if (!key) {
6656         return RNP_ERROR_BAD_PARAMETERS;
6657     }
6658     *result = key->flags() & flag;
6659     return RNP_SUCCESS;
6660 }
6661 FFI_GUARD
6662 
6663 rnp_result_t
rnp_key_get_creation(rnp_key_handle_t handle,uint32_t * result)6664 rnp_key_get_creation(rnp_key_handle_t handle, uint32_t *result)
6665 try {
6666     if (!handle || !result) {
6667         return RNP_ERROR_NULL_POINTER;
6668     }
6669     pgp_key_t *key = get_key_prefer_public(handle);
6670     if (!key) {
6671         return RNP_ERROR_BAD_PARAMETERS;
6672     }
6673     *result = key->creation();
6674     return RNP_SUCCESS;
6675 }
6676 FFI_GUARD
6677 
6678 rnp_result_t
rnp_key_is_revoked(rnp_key_handle_t handle,bool * result)6679 rnp_key_is_revoked(rnp_key_handle_t handle, bool *result)
6680 try {
6681     if (!handle || !result) {
6682         return RNP_ERROR_NULL_POINTER;
6683     }
6684     pgp_key_t *key = get_key_prefer_public(handle);
6685     if (!key) {
6686         return RNP_ERROR_BAD_PARAMETERS;
6687     }
6688     *result = key->revoked();
6689     return RNP_SUCCESS;
6690 }
6691 FFI_GUARD
6692 
6693 rnp_result_t
rnp_key_is_valid(rnp_key_handle_t handle,bool * result)6694 rnp_key_is_valid(rnp_key_handle_t handle, bool *result)
6695 try {
6696     if (!handle || !result) {
6697         return RNP_ERROR_NULL_POINTER;
6698     }
6699     pgp_key_t *key = get_key_require_public(handle);
6700     if (!key) {
6701         return RNP_ERROR_BAD_PARAMETERS;
6702     }
6703     if (!key->validated()) {
6704         key->validate(*handle->ffi->pubring);
6705     }
6706     if (!key->validated()) {
6707         return RNP_ERROR_VERIFICATION_FAILED;
6708     }
6709     *result = key->valid();
6710     return RNP_SUCCESS;
6711 }
6712 FFI_GUARD
6713 
6714 rnp_result_t
rnp_key_valid_till(rnp_key_handle_t handle,uint32_t * result)6715 rnp_key_valid_till(rnp_key_handle_t handle, uint32_t *result)
6716 try {
6717     if (!result) {
6718         return RNP_ERROR_NULL_POINTER;
6719     }
6720     uint64_t     res = 0;
6721     rnp_result_t ret = rnp_key_valid_till64(handle, &res);
6722     if (ret) {
6723         return ret;
6724     }
6725     if (res == UINT64_MAX) {
6726         *result = UINT32_MAX;
6727     } else if (res >= UINT32_MAX) {
6728         *result = UINT32_MAX - 1;
6729     } else {
6730         *result = (uint32_t) res;
6731     }
6732     return RNP_SUCCESS;
6733 }
6734 FFI_GUARD
6735 
6736 rnp_result_t
rnp_key_valid_till64(rnp_key_handle_t handle,uint64_t * result)6737 rnp_key_valid_till64(rnp_key_handle_t handle, uint64_t *result)
6738 try {
6739     if (!handle || !result) {
6740         return RNP_ERROR_NULL_POINTER;
6741     }
6742     pgp_key_t *key = get_key_require_public(handle);
6743     if (!key) {
6744         return RNP_ERROR_BAD_PARAMETERS;
6745     }
6746 
6747     if (!key->validated()) {
6748         key->validate(*handle->ffi->pubring);
6749     }
6750     if (!key->validated()) {
6751         return RNP_ERROR_VERIFICATION_FAILED;
6752     }
6753 
6754     if (key->is_subkey()) {
6755         /* check validity time of the primary key as well */
6756         pgp_key_t *primary = rnp_key_store_get_primary_key(handle->ffi->pubring, key);
6757         if (!primary) {
6758             /* no primary key - subkey considered as never valid */
6759             *result = 0;
6760             return RNP_SUCCESS;
6761         }
6762         if (!primary->validated()) {
6763             primary->validate(*handle->ffi->pubring);
6764         }
6765         if (!primary->validated()) {
6766             return RNP_ERROR_VERIFICATION_FAILED;
6767         }
6768         *result = key->valid_till();
6769     } else {
6770         *result = key->valid_till();
6771     }
6772     return RNP_SUCCESS;
6773 }
6774 FFI_GUARD
6775 
6776 rnp_result_t
rnp_key_get_expiration(rnp_key_handle_t handle,uint32_t * result)6777 rnp_key_get_expiration(rnp_key_handle_t handle, uint32_t *result)
6778 try {
6779     if (!handle || !result) {
6780         return RNP_ERROR_NULL_POINTER;
6781     }
6782     pgp_key_t *key = get_key_prefer_public(handle);
6783     if (!key) {
6784         return RNP_ERROR_BAD_PARAMETERS;
6785     }
6786     *result = key->expiration();
6787     return RNP_SUCCESS;
6788 }
6789 FFI_GUARD
6790 
6791 rnp_result_t
rnp_key_set_expiration(rnp_key_handle_t key,uint32_t expiry)6792 rnp_key_set_expiration(rnp_key_handle_t key, uint32_t expiry)
6793 try {
6794     if (!key) {
6795         return RNP_ERROR_NULL_POINTER;
6796     }
6797 
6798     pgp_key_t *pkey = get_key_prefer_public(key);
6799     if (!pkey) {
6800         return RNP_ERROR_BAD_PARAMETERS;
6801     }
6802     pgp_key_t *skey = get_key_require_secret(key);
6803     if (!skey) {
6804         FFI_LOG(key->ffi, "Secret key required.");
6805         return RNP_ERROR_BAD_PARAMETERS;
6806     }
6807 
6808     if (pkey->is_primary()) {
6809         if (!pgp_key_set_expiration(
6810               pkey, skey, expiry, key->ffi->pass_provider, key->ffi->context)) {
6811             return RNP_ERROR_GENERIC;
6812         }
6813         pkey->revalidate(*key->ffi->pubring);
6814         if (pkey != skey) {
6815             skey->revalidate(*key->ffi->secring);
6816         }
6817         return RNP_SUCCESS;
6818     }
6819 
6820     /* for subkey we need primary key */
6821     if (!pkey->has_primary_fp()) {
6822         FFI_LOG(key->ffi, "Primary key fp not available.");
6823         return RNP_ERROR_BAD_PARAMETERS;
6824     }
6825 
6826     pgp_key_search_t search = {};
6827     search.type = PGP_KEY_SEARCH_FINGERPRINT;
6828     search.by.fingerprint = pkey->primary_fp();
6829     pgp_key_t *prim_sec = find_key(key->ffi, &search, KEY_TYPE_SECRET, true);
6830     if (!prim_sec) {
6831         FFI_LOG(key->ffi, "Primary secret key not found.");
6832         return RNP_ERROR_KEY_NOT_FOUND;
6833     }
6834     if (!pgp_subkey_set_expiration(
6835           pkey, prim_sec, skey, expiry, key->ffi->pass_provider, key->ffi->context)) {
6836         return RNP_ERROR_GENERIC;
6837     }
6838     prim_sec->revalidate(*key->ffi->secring);
6839     pgp_key_t *prim_pub = find_key(key->ffi, &search, KEY_TYPE_PUBLIC, true);
6840     if (prim_pub) {
6841         prim_pub->revalidate(*key->ffi->pubring);
6842     }
6843     return RNP_SUCCESS;
6844 }
6845 FFI_GUARD
6846 
6847 rnp_result_t
rnp_key_get_revocation_reason(rnp_key_handle_t handle,char ** result)6848 rnp_key_get_revocation_reason(rnp_key_handle_t handle, char **result)
6849 try {
6850     if (!handle || !result) {
6851         return RNP_ERROR_NULL_POINTER;
6852     }
6853     pgp_key_t *key = get_key_prefer_public(handle);
6854     if (!key || !key->revoked()) {
6855         return RNP_ERROR_BAD_PARAMETERS;
6856     }
6857 
6858     *result = strdup(key->revocation().reason.c_str());
6859     if (!*result) {
6860         return RNP_ERROR_OUT_OF_MEMORY;
6861     }
6862     return RNP_SUCCESS;
6863 }
6864 FFI_GUARD
6865 
6866 static rnp_result_t
rnp_key_is_revoked_with_code(rnp_key_handle_t handle,bool * result,int code)6867 rnp_key_is_revoked_with_code(rnp_key_handle_t handle, bool *result, int code)
6868 {
6869     if (!handle || !result) {
6870         return RNP_ERROR_NULL_POINTER;
6871     }
6872     pgp_key_t *key = get_key_prefer_public(handle);
6873     if (!key || !key->revoked()) {
6874         return RNP_ERROR_BAD_PARAMETERS;
6875     }
6876 
6877     *result = key->revocation().code == code;
6878     return RNP_SUCCESS;
6879 }
6880 
6881 rnp_result_t
rnp_key_is_superseded(rnp_key_handle_t handle,bool * result)6882 rnp_key_is_superseded(rnp_key_handle_t handle, bool *result)
6883 try {
6884     return rnp_key_is_revoked_with_code(handle, result, PGP_REVOCATION_SUPERSEDED);
6885 }
6886 FFI_GUARD
6887 
6888 rnp_result_t
rnp_key_is_compromised(rnp_key_handle_t handle,bool * result)6889 rnp_key_is_compromised(rnp_key_handle_t handle, bool *result)
6890 try {
6891     return rnp_key_is_revoked_with_code(handle, result, PGP_REVOCATION_COMPROMISED);
6892 }
6893 FFI_GUARD
6894 
6895 rnp_result_t
rnp_key_is_retired(rnp_key_handle_t handle,bool * result)6896 rnp_key_is_retired(rnp_key_handle_t handle, bool *result)
6897 try {
6898     return rnp_key_is_revoked_with_code(handle, result, PGP_REVOCATION_RETIRED);
6899 }
6900 FFI_GUARD
6901 
6902 rnp_result_t
rnp_key_get_protection_type(rnp_key_handle_t key,char ** type)6903 rnp_key_get_protection_type(rnp_key_handle_t key, char **type)
6904 try {
6905     if (!key || !type) {
6906         return RNP_ERROR_NULL_POINTER;
6907     }
6908     if (!key->sec) {
6909         return RNP_ERROR_BAD_PARAMETERS;
6910     }
6911 
6912     const pgp_s2k_t &s2k = key->sec->pkt().sec_protection.s2k;
6913     const char *     res = "Unknown";
6914     if (s2k.usage == PGP_S2KU_NONE) {
6915         res = "None";
6916     }
6917     if ((s2k.usage == PGP_S2KU_ENCRYPTED) && (s2k.specifier != PGP_S2KS_EXPERIMENTAL)) {
6918         res = "Encrypted";
6919     }
6920     if ((s2k.usage == PGP_S2KU_ENCRYPTED_AND_HASHED) &&
6921         (s2k.specifier != PGP_S2KS_EXPERIMENTAL)) {
6922         res = "Encrypted-Hashed";
6923     }
6924     if ((s2k.specifier == PGP_S2KS_EXPERIMENTAL) &&
6925         (s2k.gpg_ext_num == PGP_S2K_GPG_NO_SECRET)) {
6926         res = "GPG-None";
6927     }
6928     if ((s2k.specifier == PGP_S2KS_EXPERIMENTAL) &&
6929         (s2k.gpg_ext_num == PGP_S2K_GPG_SMARTCARD)) {
6930         res = "GPG-Smartcard";
6931     }
6932 
6933     return ret_str_value(res, type);
6934 }
6935 FFI_GUARD
6936 
6937 rnp_result_t
rnp_key_get_protection_mode(rnp_key_handle_t key,char ** mode)6938 rnp_key_get_protection_mode(rnp_key_handle_t key, char **mode)
6939 try {
6940     if (!key || !mode) {
6941         return RNP_ERROR_NULL_POINTER;
6942     }
6943     if (!key->sec) {
6944         return RNP_ERROR_BAD_PARAMETERS;
6945     }
6946 
6947     if (key->sec->pkt().sec_protection.s2k.usage == PGP_S2KU_NONE) {
6948         return ret_str_value("None", mode);
6949     }
6950     if (key->sec->pkt().sec_protection.s2k.specifier == PGP_S2KS_EXPERIMENTAL) {
6951         return ret_str_value("Unknown", mode);
6952     }
6953 
6954     return get_map_value(cipher_mode_map, key->sec->pkt().sec_protection.cipher_mode, mode);
6955 }
6956 FFI_GUARD
6957 
6958 static bool
pgp_key_has_encryption_info(const pgp_key_t * key)6959 pgp_key_has_encryption_info(const pgp_key_t *key)
6960 {
6961     return (key->pkt().sec_protection.s2k.usage != PGP_S2KU_NONE) &&
6962            (key->pkt().sec_protection.s2k.specifier != PGP_S2KS_EXPERIMENTAL);
6963 }
6964 
6965 rnp_result_t
rnp_key_get_protection_cipher(rnp_key_handle_t key,char ** cipher)6966 rnp_key_get_protection_cipher(rnp_key_handle_t key, char **cipher)
6967 try {
6968     if (!key || !cipher) {
6969         return RNP_ERROR_NULL_POINTER;
6970     }
6971     if (!key->sec) {
6972         return RNP_ERROR_BAD_PARAMETERS;
6973     }
6974     if (!pgp_key_has_encryption_info(key->sec)) {
6975         return RNP_ERROR_BAD_PARAMETERS;
6976     }
6977 
6978     return get_map_value(symm_alg_map, key->sec->pkt().sec_protection.symm_alg, cipher);
6979 }
6980 FFI_GUARD
6981 
6982 rnp_result_t
rnp_key_get_protection_hash(rnp_key_handle_t key,char ** hash)6983 rnp_key_get_protection_hash(rnp_key_handle_t key, char **hash)
6984 try {
6985     if (!key || !hash) {
6986         return RNP_ERROR_NULL_POINTER;
6987     }
6988     if (!key->sec) {
6989         return RNP_ERROR_BAD_PARAMETERS;
6990     }
6991     if (!pgp_key_has_encryption_info(key->sec)) {
6992         return RNP_ERROR_BAD_PARAMETERS;
6993     }
6994 
6995     return get_map_value(hash_alg_map, key->sec->pkt().sec_protection.s2k.hash_alg, hash);
6996 }
6997 FFI_GUARD
6998 
6999 rnp_result_t
rnp_key_get_protection_iterations(rnp_key_handle_t key,size_t * iterations)7000 rnp_key_get_protection_iterations(rnp_key_handle_t key, size_t *iterations)
7001 try {
7002     if (!key || !iterations) {
7003         return RNP_ERROR_NULL_POINTER;
7004     }
7005     if (!key->sec) {
7006         return RNP_ERROR_BAD_PARAMETERS;
7007     }
7008     if (!pgp_key_has_encryption_info(key->sec)) {
7009         return RNP_ERROR_BAD_PARAMETERS;
7010     }
7011 
7012     if (key->sec->pkt().sec_protection.s2k.specifier == PGP_S2KS_ITERATED_AND_SALTED) {
7013         *iterations = pgp_s2k_decode_iterations(key->sec->pkt().sec_protection.s2k.iterations);
7014     } else {
7015         *iterations = 1;
7016     }
7017     return RNP_SUCCESS;
7018 }
7019 FFI_GUARD
7020 
7021 rnp_result_t
rnp_key_is_locked(rnp_key_handle_t handle,bool * result)7022 rnp_key_is_locked(rnp_key_handle_t handle, bool *result)
7023 try {
7024     if (handle == NULL || result == NULL)
7025         return RNP_ERROR_NULL_POINTER;
7026 
7027     pgp_key_t *key = get_key_require_secret(handle);
7028     if (!key) {
7029         return RNP_ERROR_NO_SUITABLE_KEY;
7030     }
7031     *result = key->is_locked();
7032     return RNP_SUCCESS;
7033 }
7034 FFI_GUARD
7035 
7036 rnp_result_t
rnp_key_lock(rnp_key_handle_t handle)7037 rnp_key_lock(rnp_key_handle_t handle)
7038 try {
7039     if (handle == NULL)
7040         return RNP_ERROR_NULL_POINTER;
7041 
7042     pgp_key_t *key = get_key_require_secret(handle);
7043     if (!key) {
7044         return RNP_ERROR_NO_SUITABLE_KEY;
7045     }
7046     if (!key->lock()) {
7047         return RNP_ERROR_GENERIC;
7048     }
7049     return RNP_SUCCESS;
7050 }
7051 FFI_GUARD
7052 
7053 rnp_result_t
rnp_key_unlock(rnp_key_handle_t handle,const char * password)7054 rnp_key_unlock(rnp_key_handle_t handle, const char *password)
7055 try {
7056     if (!handle) {
7057         return RNP_ERROR_NULL_POINTER;
7058     }
7059     pgp_key_t *key = get_key_require_secret(handle);
7060     if (!key) {
7061         return RNP_ERROR_NO_SUITABLE_KEY;
7062     }
7063     bool ok = false;
7064     if (password) {
7065         pgp_password_provider_t prov = {
7066           .callback = rnp_password_provider_string,
7067           .userdata = reinterpret_cast<void *>(const_cast<char *>(password))};
7068         ok = key->unlock(prov);
7069     } else {
7070         ok = key->unlock(handle->ffi->pass_provider);
7071     }
7072     if (!ok) {
7073         // likely a bad password
7074         return RNP_ERROR_BAD_PASSWORD;
7075     }
7076     return RNP_SUCCESS;
7077 }
7078 FFI_GUARD
7079 
7080 rnp_result_t
rnp_key_is_protected(rnp_key_handle_t handle,bool * result)7081 rnp_key_is_protected(rnp_key_handle_t handle, bool *result)
7082 try {
7083     if (handle == NULL || result == NULL)
7084         return RNP_ERROR_NULL_POINTER;
7085 
7086     pgp_key_t *key = get_key_require_secret(handle);
7087     if (!key) {
7088         return RNP_ERROR_NO_SUITABLE_KEY;
7089     }
7090     *result = key->is_protected();
7091     return RNP_SUCCESS;
7092 }
7093 FFI_GUARD
7094 
7095 rnp_result_t
rnp_key_protect(rnp_key_handle_t handle,const char * password,const char * cipher,const char * cipher_mode,const char * hash,size_t iterations)7096 rnp_key_protect(rnp_key_handle_t handle,
7097                 const char *     password,
7098                 const char *     cipher,
7099                 const char *     cipher_mode,
7100                 const char *     hash,
7101                 size_t           iterations)
7102 try {
7103     rnp_key_protection_params_t protection = {};
7104 
7105     // checks
7106     if (!handle || !password) {
7107         return RNP_ERROR_NULL_POINTER;
7108     }
7109 
7110     if (cipher && !str_to_cipher(cipher, &protection.symm_alg)) {
7111         FFI_LOG(handle->ffi, "Invalid cipher: %s", cipher);
7112         return RNP_ERROR_BAD_PARAMETERS;
7113     }
7114     if (cipher_mode && !str_to_cipher_mode(cipher_mode, &protection.cipher_mode)) {
7115         FFI_LOG(handle->ffi, "Invalid cipher mode: %s", cipher_mode);
7116         return RNP_ERROR_BAD_PARAMETERS;
7117     }
7118     if (hash && !str_to_hash_alg(hash, &protection.hash_alg)) {
7119         FFI_LOG(handle->ffi, "Invalid hash: %s", hash);
7120         return RNP_ERROR_BAD_PARAMETERS;
7121     }
7122     protection.iterations = iterations;
7123 
7124     // get the key
7125     pgp_key_t *key = get_key_require_secret(handle);
7126     if (!key) {
7127         return RNP_ERROR_NO_SUITABLE_KEY;
7128     }
7129     pgp_key_pkt_t *   decrypted_key = NULL;
7130     const std::string pass = password;
7131     if (key->encrypted()) {
7132         pgp_password_ctx_t ctx = {.op = PGP_OP_PROTECT, .key = key};
7133         decrypted_key = pgp_decrypt_seckey(*key, handle->ffi->pass_provider, ctx);
7134         if (!decrypted_key) {
7135             return RNP_ERROR_GENERIC;
7136         }
7137     }
7138     bool res = key->protect(
7139       decrypted_key ? *decrypted_key : key->pkt(), protection, pass, handle->ffi->rng());
7140     delete decrypted_key;
7141     return res ? RNP_SUCCESS : RNP_ERROR_GENERIC;
7142 }
7143 FFI_GUARD
7144 
7145 rnp_result_t
rnp_key_unprotect(rnp_key_handle_t handle,const char * password)7146 rnp_key_unprotect(rnp_key_handle_t handle, const char *password)
7147 try {
7148     // checks
7149     if (!handle) {
7150         return RNP_ERROR_NULL_POINTER;
7151     }
7152 
7153     // get the key
7154     pgp_key_t *key = get_key_require_secret(handle);
7155     if (!key) {
7156         return RNP_ERROR_NO_SUITABLE_KEY;
7157     }
7158     bool ok = false;
7159     if (password) {
7160         pgp_password_provider_t prov = {
7161           .callback = rnp_password_provider_string,
7162           .userdata = reinterpret_cast<void *>(const_cast<char *>(password))};
7163         ok = key->unprotect(prov, handle->ffi->rng());
7164     } else {
7165         ok = key->unprotect(handle->ffi->pass_provider, handle->ffi->rng());
7166     }
7167     if (!ok) {
7168         // likely a bad password
7169         return RNP_ERROR_BAD_PASSWORD;
7170     }
7171     return RNP_SUCCESS;
7172 }
7173 FFI_GUARD
7174 
7175 rnp_result_t
rnp_key_is_primary(rnp_key_handle_t handle,bool * result)7176 rnp_key_is_primary(rnp_key_handle_t handle, bool *result)
7177 try {
7178     if (handle == NULL || result == NULL)
7179         return RNP_ERROR_NULL_POINTER;
7180 
7181     pgp_key_t *key = get_key_prefer_public(handle);
7182     if (key->format == PGP_KEY_STORE_G10) {
7183         // we can't currently determine this for a G10 secret key
7184         return RNP_ERROR_NO_SUITABLE_KEY;
7185     }
7186     *result = key->is_primary();
7187     return RNP_SUCCESS;
7188 }
7189 FFI_GUARD
7190 
7191 rnp_result_t
rnp_key_is_sub(rnp_key_handle_t handle,bool * result)7192 rnp_key_is_sub(rnp_key_handle_t handle, bool *result)
7193 try {
7194     if (handle == NULL || result == NULL)
7195         return RNP_ERROR_NULL_POINTER;
7196 
7197     pgp_key_t *key = get_key_prefer_public(handle);
7198     if (key->format == PGP_KEY_STORE_G10) {
7199         // we can't currently determine this for a G10 secret key
7200         return RNP_ERROR_NO_SUITABLE_KEY;
7201     }
7202     *result = key->is_subkey();
7203     return RNP_SUCCESS;
7204 }
7205 FFI_GUARD
7206 
7207 rnp_result_t
rnp_key_have_secret(rnp_key_handle_t handle,bool * result)7208 rnp_key_have_secret(rnp_key_handle_t handle, bool *result)
7209 try {
7210     if (handle == NULL || result == NULL)
7211         return RNP_ERROR_NULL_POINTER;
7212 
7213     *result = handle->sec != NULL;
7214     return RNP_SUCCESS;
7215 }
7216 FFI_GUARD
7217 
7218 rnp_result_t
rnp_key_have_public(rnp_key_handle_t handle,bool * result)7219 rnp_key_have_public(rnp_key_handle_t handle, bool *result)
7220 try {
7221     if (handle == NULL || result == NULL)
7222         return RNP_ERROR_NULL_POINTER;
7223     *result = handle->pub != NULL;
7224     return RNP_SUCCESS;
7225 }
7226 FFI_GUARD
7227 
7228 static rnp_result_t
key_to_bytes(pgp_key_t * key,uint8_t ** buf,size_t * buf_len)7229 key_to_bytes(pgp_key_t *key, uint8_t **buf, size_t *buf_len)
7230 {
7231     pgp_dest_t memdst = {};
7232 
7233     if (init_mem_dest(&memdst, NULL, 0)) {
7234         return RNP_ERROR_OUT_OF_MEMORY;
7235     }
7236 
7237     key->write(memdst);
7238     if (memdst.werr) {
7239         dst_close(&memdst, true);
7240         return RNP_ERROR_OUT_OF_MEMORY;
7241     }
7242 
7243     *buf_len = memdst.writeb;
7244     *buf = (uint8_t *) mem_dest_own_memory(&memdst);
7245     dst_close(&memdst, true);
7246     if (*buf_len && !*buf) {
7247         return RNP_ERROR_OUT_OF_MEMORY;
7248     }
7249     return RNP_SUCCESS;
7250 }
7251 
7252 rnp_result_t
rnp_get_public_key_data(rnp_key_handle_t handle,uint8_t ** buf,size_t * buf_len)7253 rnp_get_public_key_data(rnp_key_handle_t handle, uint8_t **buf, size_t *buf_len)
7254 try {
7255     // checks
7256     if (!handle || !buf || !buf_len) {
7257         return RNP_ERROR_NULL_POINTER;
7258     }
7259 
7260     pgp_key_t *key = handle->pub;
7261     if (!key) {
7262         return RNP_ERROR_NO_SUITABLE_KEY;
7263     }
7264     return key_to_bytes(key, buf, buf_len);
7265 }
7266 FFI_GUARD
7267 
7268 rnp_result_t
rnp_get_secret_key_data(rnp_key_handle_t handle,uint8_t ** buf,size_t * buf_len)7269 rnp_get_secret_key_data(rnp_key_handle_t handle, uint8_t **buf, size_t *buf_len)
7270 try {
7271     // checks
7272     if (!handle || !buf || !buf_len) {
7273         return RNP_ERROR_NULL_POINTER;
7274     }
7275 
7276     pgp_key_t *key = handle->sec;
7277     if (!key) {
7278         return RNP_ERROR_NO_SUITABLE_KEY;
7279     }
7280     return key_to_bytes(key, buf, buf_len);
7281 }
7282 FFI_GUARD
7283 
7284 static bool
add_json_string_field(json_object * jso,const char * key,const char * value)7285 add_json_string_field(json_object *jso, const char *key, const char *value)
7286 {
7287     json_object *jsostr = json_object_new_string(value);
7288     if (!jsostr) {
7289         return false;
7290     }
7291     json_object_object_add(jso, key, jsostr);
7292     return true;
7293 }
7294 
7295 static bool
add_json_int_field(json_object * jso,const char * key,int32_t value)7296 add_json_int_field(json_object *jso, const char *key, int32_t value)
7297 {
7298     json_object *jsoval = json_object_new_int(value);
7299     if (!jsoval) {
7300         return false;
7301     }
7302     json_object_object_add(jso, key, jsoval);
7303     return true;
7304 }
7305 
7306 static bool
add_json_key_usage(json_object * jso,uint8_t key_flags)7307 add_json_key_usage(json_object *jso, uint8_t key_flags)
7308 {
7309     json_object *jsoarr = json_object_new_array();
7310     if (!jsoarr) {
7311         return false;
7312     }
7313     for (size_t i = 0; i < ARRAY_SIZE(key_usage_map); i++) {
7314         if (key_usage_map[i].id & key_flags) {
7315             json_object *jsostr = json_object_new_string(key_usage_map[i].str);
7316             if (!jsostr || json_object_array_add(jsoarr, jsostr)) {
7317                 json_object_put(jsoarr);
7318                 return false;
7319             }
7320         }
7321     }
7322     if (json_object_array_length(jsoarr)) {
7323         json_object_object_add(jso, "usage", jsoarr);
7324     } else {
7325         json_object_put(jsoarr);
7326     }
7327     return true;
7328 }
7329 
7330 static bool
add_json_key_flags(json_object * jso,uint8_t key_flags)7331 add_json_key_flags(json_object *jso, uint8_t key_flags)
7332 {
7333     json_object *jsoarr = json_object_new_array();
7334     if (!jsoarr) {
7335         return false;
7336     }
7337     for (size_t i = 0; i < ARRAY_SIZE(key_flags_map); i++) {
7338         if (key_flags_map[i].id & key_flags) {
7339             json_object *jsostr = json_object_new_string(key_flags_map[i].str);
7340             if (!jsostr || json_object_array_add(jsoarr, jsostr)) {
7341                 json_object_put(jsoarr);
7342                 return false;
7343             }
7344         }
7345     }
7346     if (json_object_array_length(jsoarr)) {
7347         json_object_object_add(jso, "flags", jsoarr);
7348     } else {
7349         json_object_put(jsoarr);
7350     }
7351     return true;
7352 }
7353 
7354 static rnp_result_t
add_json_mpis(json_object * jso,...)7355 add_json_mpis(json_object *jso, ...)
7356 {
7357     va_list      ap;
7358     const char * name;
7359     rnp_result_t ret = RNP_ERROR_GENERIC;
7360 
7361     va_start(ap, jso);
7362     while ((name = va_arg(ap, const char *))) {
7363         pgp_mpi_t *val = va_arg(ap, pgp_mpi_t *);
7364         if (!val) {
7365             ret = RNP_ERROR_BAD_PARAMETERS;
7366             goto done;
7367         }
7368         char *hex = mpi2hex(val);
7369         if (!hex) {
7370             // this could probably be other things
7371             ret = RNP_ERROR_OUT_OF_MEMORY;
7372             goto done;
7373         }
7374         json_object *jsostr = json_object_new_string(hex);
7375         free(hex);
7376         if (!jsostr) {
7377             ret = RNP_ERROR_OUT_OF_MEMORY;
7378             goto done;
7379         }
7380         json_object_object_add(jso, name, jsostr);
7381     }
7382     ret = RNP_SUCCESS;
7383 
7384 done:
7385     va_end(ap);
7386     return ret;
7387 }
7388 
7389 static rnp_result_t
add_json_public_mpis(json_object * jso,pgp_key_t * key)7390 add_json_public_mpis(json_object *jso, pgp_key_t *key)
7391 {
7392     const pgp_key_material_t &km = key->material();
7393     switch (km.alg) {
7394     case PGP_PKA_RSA:
7395     case PGP_PKA_RSA_ENCRYPT_ONLY:
7396     case PGP_PKA_RSA_SIGN_ONLY:
7397         return add_json_mpis(jso, "n", &km.rsa.n, "e", &km.rsa.e, NULL);
7398     case PGP_PKA_ELGAMAL:
7399     case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
7400         return add_json_mpis(jso, "p", &km.eg.p, "g", &km.eg.g, "y", &km.eg.y, NULL);
7401     case PGP_PKA_DSA:
7402         return add_json_mpis(
7403           jso, "p", &km.dsa.p, "q", &km.dsa.q, "g", &km.dsa.g, "y", &km.dsa.y, NULL);
7404     case PGP_PKA_ECDH:
7405     case PGP_PKA_ECDSA:
7406     case PGP_PKA_EDDSA:
7407     case PGP_PKA_SM2:
7408         return add_json_mpis(jso, "point", &km.ec.p, NULL);
7409     default:
7410         return RNP_ERROR_NOT_SUPPORTED;
7411     }
7412     return RNP_SUCCESS;
7413 }
7414 
7415 static rnp_result_t
add_json_secret_mpis(json_object * jso,pgp_key_t * key)7416 add_json_secret_mpis(json_object *jso, pgp_key_t *key)
7417 {
7418     const pgp_key_material_t &km = key->material();
7419     switch (key->alg()) {
7420     case PGP_PKA_RSA:
7421     case PGP_PKA_RSA_ENCRYPT_ONLY:
7422     case PGP_PKA_RSA_SIGN_ONLY:
7423         return add_json_mpis(
7424           jso, "d", &km.rsa.d, "p", &km.rsa.p, "q", &km.rsa.q, "u", &km.rsa.u, NULL);
7425     case PGP_PKA_ELGAMAL:
7426     case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
7427         return add_json_mpis(jso, "x", &km.eg.x, NULL);
7428     case PGP_PKA_DSA:
7429         return add_json_mpis(jso, "x", &km.dsa.x, NULL);
7430     case PGP_PKA_ECDH:
7431     case PGP_PKA_ECDSA:
7432     case PGP_PKA_EDDSA:
7433     case PGP_PKA_SM2:
7434         return add_json_mpis(jso, "x", &km.ec.x, NULL);
7435     default:
7436         return RNP_ERROR_NOT_SUPPORTED;
7437     }
7438     return RNP_SUCCESS;
7439 }
7440 
7441 static rnp_result_t
add_json_sig_mpis(json_object * jso,const pgp_signature_t * sig)7442 add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig)
7443 {
7444     pgp_signature_material_t material = {};
7445     try {
7446         if (!sig->parse_material(material)) {
7447             return RNP_ERROR_BAD_PARAMETERS;
7448         }
7449     } catch (const std::exception &e) {
7450         RNP_LOG("%s", e.what());
7451         return RNP_ERROR_OUT_OF_MEMORY;
7452     }
7453     switch (sig->palg) {
7454     case PGP_PKA_RSA:
7455     case PGP_PKA_RSA_ENCRYPT_ONLY:
7456     case PGP_PKA_RSA_SIGN_ONLY:
7457         return add_json_mpis(jso, "sig", &material.rsa.s, NULL);
7458     case PGP_PKA_ELGAMAL:
7459     case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
7460         return add_json_mpis(jso, "r", &material.eg.r, "s", &material.eg.s, NULL);
7461     case PGP_PKA_DSA:
7462         return add_json_mpis(jso, "r", &material.dsa.r, "s", &material.dsa.s, NULL);
7463     case PGP_PKA_ECDSA:
7464     case PGP_PKA_EDDSA:
7465     case PGP_PKA_SM2:
7466         return add_json_mpis(jso, "r", &material.ecc.r, "s", &material.ecc.s, NULL);
7467     default:
7468         // TODO: we could use info->unknown and add a hex string of raw data here
7469         return RNP_ERROR_NOT_SUPPORTED;
7470     }
7471     return RNP_SUCCESS;
7472 }
7473 
7474 static bool
add_json_user_prefs(json_object * jso,const pgp_user_prefs_t & prefs)7475 add_json_user_prefs(json_object *jso, const pgp_user_prefs_t &prefs)
7476 {
7477     // TODO: instead of using a string "Unknown" as a fallback for these,
7478     // we could add a string of hex/dec (or even an int)
7479     if (!prefs.symm_algs.empty()) {
7480         json_object *jsoarr = json_object_new_array();
7481         if (!jsoarr) {
7482             return false;
7483         }
7484         json_object_object_add(jso, "ciphers", jsoarr);
7485         for (auto alg : prefs.symm_algs) {
7486             const char * name = id_str_pair::lookup(symm_alg_map, alg, "Unknown");
7487             json_object *jsoname = json_object_new_string(name);
7488             if (!jsoname || json_object_array_add(jsoarr, jsoname)) {
7489                 return false;
7490             }
7491         }
7492     }
7493     if (!prefs.hash_algs.empty()) {
7494         json_object *jsoarr = json_object_new_array();
7495         if (!jsoarr) {
7496             return false;
7497         }
7498         json_object_object_add(jso, "hashes", jsoarr);
7499         for (auto alg : prefs.hash_algs) {
7500             const char * name = id_str_pair::lookup(hash_alg_map, alg, "Unknown");
7501             json_object *jsoname = json_object_new_string(name);
7502             if (!jsoname || json_object_array_add(jsoarr, jsoname)) {
7503                 return false;
7504             }
7505         }
7506     }
7507     if (!prefs.z_algs.empty()) {
7508         json_object *jsoarr = json_object_new_array();
7509         if (!jsoarr) {
7510             return false;
7511         }
7512         json_object_object_add(jso, "compression", jsoarr);
7513         for (auto alg : prefs.z_algs) {
7514             const char * name = id_str_pair::lookup(compress_alg_map, alg, "Unknown");
7515             json_object *jsoname = json_object_new_string(name);
7516             if (!jsoname || json_object_array_add(jsoarr, jsoname)) {
7517                 return false;
7518             }
7519         }
7520     }
7521     if (!prefs.ks_prefs.empty()) {
7522         json_object *jsoarr = json_object_new_array();
7523         if (!jsoarr) {
7524             return false;
7525         }
7526         json_object_object_add(jso, "key server preferences", jsoarr);
7527         for (auto flag : prefs.ks_prefs) {
7528             const char * name = id_str_pair::lookup(key_server_prefs_map, flag, "Unknown");
7529             json_object *jsoname = json_object_new_string(name);
7530             if (!jsoname || json_object_array_add(jsoarr, jsoname)) {
7531                 return false;
7532             }
7533         }
7534     }
7535     if (!prefs.key_server.empty()) {
7536         if (!add_json_string_field(jso, "key server", prefs.key_server.c_str())) {
7537             return false;
7538         }
7539     }
7540     return true;
7541 }
7542 
7543 static rnp_result_t
add_json_subsig(json_object * jso,bool is_sub,uint32_t flags,const pgp_subsig_t * subsig)7544 add_json_subsig(json_object *jso, bool is_sub, uint32_t flags, const pgp_subsig_t *subsig)
7545 {
7546     // userid (if applicable)
7547     if (!is_sub) {
7548         json_object *jsouid = json_object_new_int(subsig->uid);
7549         if (!jsouid) {
7550             return RNP_ERROR_OUT_OF_MEMORY;
7551         }
7552         json_object_object_add(jso, "userid", jsouid);
7553     }
7554     // trust
7555     json_object *jsotrust = json_object_new_object();
7556     if (!jsotrust) {
7557         return RNP_ERROR_OUT_OF_MEMORY;
7558     }
7559     json_object_object_add(jso, "trust", jsotrust);
7560     // trust (level)
7561     json_object *jsotrust_level = json_object_new_int(subsig->trustlevel);
7562     if (!jsotrust_level) {
7563         return RNP_ERROR_OUT_OF_MEMORY;
7564     }
7565     json_object_object_add(jsotrust, "level", jsotrust_level);
7566     // trust (amount)
7567     json_object *jsotrust_amount = json_object_new_int(subsig->trustamount);
7568     if (!jsotrust_amount) {
7569         return RNP_ERROR_OUT_OF_MEMORY;
7570     }
7571     json_object_object_add(jsotrust, "amount", jsotrust_amount);
7572     // key flags (usage)
7573     if (!add_json_key_usage(jso, subsig->key_flags)) {
7574         return RNP_ERROR_OUT_OF_MEMORY;
7575     }
7576     // key flags (other)
7577     if (!add_json_key_flags(jso, subsig->key_flags)) {
7578         return RNP_ERROR_OUT_OF_MEMORY;
7579     }
7580     // preferences
7581     const pgp_user_prefs_t &prefs = subsig->prefs;
7582     if (!prefs.symm_algs.empty() || !prefs.hash_algs.empty() || !prefs.z_algs.empty() ||
7583         !prefs.ks_prefs.empty() || !prefs.key_server.empty()) {
7584         json_object *jsoprefs = json_object_new_object();
7585         if (!jsoprefs) {
7586             return RNP_ERROR_OUT_OF_MEMORY;
7587         }
7588         json_object_object_add(jso, "preferences", jsoprefs);
7589         if (!add_json_user_prefs(jsoprefs, prefs)) {
7590             return RNP_ERROR_OUT_OF_MEMORY;
7591         }
7592     }
7593     const pgp_signature_t *sig = &subsig->sig;
7594     // version
7595     json_object *jsoversion = json_object_new_int(sig->version);
7596     if (!jsoversion) {
7597         return RNP_ERROR_OUT_OF_MEMORY;
7598     }
7599     json_object_object_add(jso, "version", jsoversion);
7600     // signature type
7601     auto type = id_str_pair::lookup(sig_type_map, sig->type());
7602     if (!add_json_string_field(jso, "type", type)) {
7603         return RNP_ERROR_OUT_OF_MEMORY;
7604     }
7605     // signer key type
7606     const char *key_type = id_str_pair::lookup(pubkey_alg_map, sig->palg);
7607     if (!add_json_string_field(jso, "key type", key_type)) {
7608         return RNP_ERROR_OUT_OF_MEMORY;
7609     }
7610     // hash
7611     const char *hash = id_str_pair::lookup(hash_alg_map, sig->halg);
7612     if (!add_json_string_field(jso, "hash", hash)) {
7613         return RNP_ERROR_OUT_OF_MEMORY;
7614     }
7615     // creation time
7616     json_object *jsocreation_time = json_object_new_int64(sig->creation());
7617     if (!jsocreation_time) {
7618         return RNP_ERROR_OUT_OF_MEMORY;
7619     }
7620     json_object_object_add(jso, "creation time", jsocreation_time);
7621     // expiration (seconds)
7622     json_object *jsoexpiration = json_object_new_int64(sig->expiration());
7623     if (!jsoexpiration) {
7624         return RNP_ERROR_OUT_OF_MEMORY;
7625     }
7626     json_object_object_add(jso, "expiration", jsoexpiration);
7627     // signer
7628     json_object *jsosigner = NULL;
7629     // TODO: add signer fingerprint as well (no support internally yet)
7630     if (sig->has_keyid()) {
7631         jsosigner = json_object_new_object();
7632         if (!jsosigner) {
7633             return RNP_ERROR_OUT_OF_MEMORY;
7634         }
7635         char         keyid[PGP_KEY_ID_SIZE * 2 + 1];
7636         pgp_key_id_t signer = sig->keyid();
7637         if (!rnp::hex_encode(signer.data(), signer.size(), keyid, sizeof(keyid))) {
7638             return RNP_ERROR_GENERIC;
7639         }
7640         if (!add_json_string_field(jsosigner, "keyid", keyid)) {
7641             json_object_put(jsosigner);
7642             return RNP_ERROR_OUT_OF_MEMORY;
7643         }
7644     }
7645     json_object_object_add(jso, "signer", jsosigner);
7646     // mpis
7647     json_object *jsompis = NULL;
7648     if (flags & RNP_JSON_SIGNATURE_MPIS) {
7649         jsompis = json_object_new_object();
7650         if (!jsompis) {
7651             return RNP_ERROR_OUT_OF_MEMORY;
7652         }
7653         rnp_result_t tmpret;
7654         if ((tmpret = add_json_sig_mpis(jsompis, sig))) {
7655             json_object_put(jsompis);
7656             return tmpret;
7657         }
7658     }
7659     json_object_object_add(jso, "mpis", jsompis);
7660     return RNP_SUCCESS;
7661 }
7662 
7663 static rnp_result_t
key_to_json(json_object * jso,rnp_key_handle_t handle,uint32_t flags)7664 key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags)
7665 {
7666     pgp_key_t *key = get_key_prefer_public(handle);
7667 
7668     // type
7669     const char *str = id_str_pair::lookup(pubkey_alg_map, key->alg(), NULL);
7670     if (!str) {
7671         return RNP_ERROR_BAD_PARAMETERS;
7672     }
7673     if (!add_json_string_field(jso, "type", str)) {
7674         return RNP_ERROR_OUT_OF_MEMORY;
7675     }
7676     // length
7677     if (!add_json_int_field(jso, "length", key->material().bits())) {
7678         return RNP_ERROR_OUT_OF_MEMORY;
7679     }
7680     // curve / alg-specific items
7681     switch (key->alg()) {
7682     case PGP_PKA_ECDH: {
7683         const char *hash_name =
7684           id_str_pair::lookup(hash_alg_map, key->material().ec.kdf_hash_alg, NULL);
7685         if (!hash_name) {
7686             return RNP_ERROR_BAD_PARAMETERS;
7687         }
7688         const char *cipher_name =
7689           id_str_pair::lookup(symm_alg_map, key->material().ec.key_wrap_alg, NULL);
7690         if (!cipher_name) {
7691             return RNP_ERROR_BAD_PARAMETERS;
7692         }
7693         json_object *jsohash = json_object_new_string(hash_name);
7694         if (!jsohash) {
7695             return RNP_ERROR_OUT_OF_MEMORY;
7696         }
7697         json_object_object_add(jso, "kdf hash", jsohash);
7698         json_object *jsocipher = json_object_new_string(cipher_name);
7699         if (!jsocipher) {
7700             return RNP_ERROR_OUT_OF_MEMORY;
7701         }
7702         json_object_object_add(jso, "key wrap cipher", jsocipher);
7703     }
7704         [[fallthrough]];
7705     case PGP_PKA_ECDSA:
7706     case PGP_PKA_EDDSA:
7707     case PGP_PKA_SM2: {
7708         const char *curve_name = NULL;
7709         if (!curve_type_to_str(key->material().ec.curve, &curve_name)) {
7710             return RNP_ERROR_BAD_PARAMETERS;
7711         }
7712         json_object *jsocurve = json_object_new_string(curve_name);
7713         if (!jsocurve) {
7714             return RNP_ERROR_OUT_OF_MEMORY;
7715         }
7716         json_object_object_add(jso, "curve", jsocurve);
7717     } break;
7718     default:
7719         break;
7720     }
7721 
7722     // keyid
7723     char keyid[PGP_KEY_ID_SIZE * 2 + 1];
7724     if (!rnp::hex_encode(key->keyid().data(), key->keyid().size(), keyid, sizeof(keyid))) {
7725         return RNP_ERROR_GENERIC;
7726     }
7727     if (!add_json_string_field(jso, "keyid", keyid)) {
7728         return RNP_ERROR_OUT_OF_MEMORY;
7729     }
7730     // fingerprint
7731     char fpr[PGP_FINGERPRINT_SIZE * 2 + 1];
7732     if (!rnp::hex_encode(key->fp().fingerprint, key->fp().length, fpr, sizeof(fpr))) {
7733         return RNP_ERROR_GENERIC;
7734     }
7735     if (!add_json_string_field(jso, "fingerprint", fpr)) {
7736         return RNP_ERROR_OUT_OF_MEMORY;
7737     }
7738     // grip
7739     char grip[PGP_KEY_GRIP_SIZE * 2 + 1];
7740     if (!rnp::hex_encode(key->grip().data(), key->grip().size(), grip, sizeof(grip))) {
7741         return RNP_ERROR_GENERIC;
7742     }
7743     if (!add_json_string_field(jso, "grip", grip)) {
7744         return RNP_ERROR_OUT_OF_MEMORY;
7745     }
7746     // revoked
7747     json_object *jsorevoked = json_object_new_boolean(key->revoked() ? true : false);
7748     if (!jsorevoked) {
7749         return RNP_ERROR_OUT_OF_MEMORY;
7750     }
7751     json_object_object_add(jso, "revoked", jsorevoked);
7752     // creation time
7753     json_object *jsocreation_time = json_object_new_int64(key->creation());
7754     if (!jsocreation_time) {
7755         return RNP_ERROR_OUT_OF_MEMORY;
7756     }
7757     json_object_object_add(jso, "creation time", jsocreation_time);
7758     // expiration
7759     json_object *jsoexpiration = json_object_new_int64(key->expiration());
7760     if (!jsoexpiration) {
7761         return RNP_ERROR_OUT_OF_MEMORY;
7762     }
7763     json_object_object_add(jso, "expiration", jsoexpiration);
7764     // key flags (usage)
7765     if (!add_json_key_usage(jso, key->flags())) {
7766         return RNP_ERROR_OUT_OF_MEMORY;
7767     }
7768     // key flags (other)
7769     if (!add_json_key_flags(jso, key->flags())) {
7770         return RNP_ERROR_OUT_OF_MEMORY;
7771     }
7772     // parent / subkeys
7773     if (key->is_primary()) {
7774         json_object *jsosubkeys_arr = json_object_new_array();
7775         if (!jsosubkeys_arr) {
7776             return RNP_ERROR_OUT_OF_MEMORY;
7777         }
7778         json_object_object_add(jso, "subkey grips", jsosubkeys_arr);
7779         for (auto &subfp : key->subkey_fps()) {
7780             const pgp_key_grip_t *subgrip = rnp_get_grip_by_fp(handle->ffi, subfp);
7781             if (!subgrip) {
7782                 continue;
7783             }
7784             if (!rnp::hex_encode(subgrip->data(), subgrip->size(), grip, sizeof(grip))) {
7785                 return RNP_ERROR_GENERIC;
7786             }
7787             json_object *jsostr = json_object_new_string(grip);
7788             if (!jsostr || json_object_array_add(jsosubkeys_arr, jsostr)) {
7789                 json_object_put(jsostr);
7790                 return RNP_ERROR_OUT_OF_MEMORY;
7791             }
7792         }
7793     } else if (key->has_primary_fp()) {
7794         auto pgrip = rnp_get_grip_by_fp(handle->ffi, key->primary_fp());
7795         if (pgrip) {
7796             if (!rnp::hex_encode(pgrip->data(), pgrip->size(), grip, sizeof(grip))) {
7797                 return RNP_ERROR_GENERIC;
7798             }
7799             if (!add_json_string_field(jso, "primary key grip", grip)) {
7800                 return RNP_ERROR_OUT_OF_MEMORY;
7801             }
7802         }
7803     }
7804     // public
7805     json_object *jsopublic = json_object_new_object();
7806     if (!jsopublic) {
7807         return RNP_ERROR_OUT_OF_MEMORY;
7808     }
7809     bool have_sec = handle->sec != NULL;
7810     bool have_pub = handle->pub != NULL;
7811     json_object_object_add(jso, "public key", jsopublic);
7812     json_object_object_add(
7813       jsopublic, "present", json_object_new_boolean(have_pub ? true : false));
7814     if (flags & RNP_JSON_PUBLIC_MPIS) {
7815         json_object *jsompis = json_object_new_object();
7816         if (!jsompis) {
7817             return RNP_ERROR_OUT_OF_MEMORY;
7818         }
7819         json_object_object_add(jsopublic, "mpis", jsompis);
7820         rnp_result_t tmpret;
7821         if ((tmpret = add_json_public_mpis(jsompis, key))) {
7822             return tmpret;
7823         }
7824     }
7825     // secret
7826     json_object *jsosecret = json_object_new_object();
7827     if (!jsosecret) {
7828         return RNP_ERROR_OUT_OF_MEMORY;
7829     }
7830     json_object_object_add(jso, "secret key", jsosecret);
7831     json_object_object_add(
7832       jsosecret, "present", json_object_new_boolean(have_sec ? true : false));
7833     if (have_sec) {
7834         bool locked = handle->sec->is_locked();
7835         if (flags & RNP_JSON_SECRET_MPIS) {
7836             if (locked) {
7837                 json_object_object_add(jsosecret, "mpis", NULL);
7838             } else {
7839                 json_object *jsompis = json_object_new_object();
7840                 if (!jsompis) {
7841                     return RNP_ERROR_OUT_OF_MEMORY;
7842                 }
7843                 json_object_object_add(jsosecret, "mpis", jsompis);
7844                 rnp_result_t tmpret;
7845                 if ((tmpret = add_json_secret_mpis(jsompis, handle->sec))) {
7846                     return tmpret;
7847                 }
7848             }
7849         }
7850         json_object *jsolocked = json_object_new_boolean(locked ? true : false);
7851         if (!jsolocked) {
7852             return RNP_ERROR_OUT_OF_MEMORY;
7853         }
7854         json_object_object_add(jsosecret, "locked", jsolocked);
7855         json_object *jsoprotected =
7856           json_object_new_boolean(handle->sec->is_protected() ? true : false);
7857         if (!jsoprotected) {
7858             return RNP_ERROR_OUT_OF_MEMORY;
7859         }
7860         json_object_object_add(jsosecret, "protected", jsoprotected);
7861     }
7862     // userids
7863     if (key->is_primary()) {
7864         json_object *jsouids_arr = json_object_new_array();
7865         if (!jsouids_arr) {
7866             return RNP_ERROR_OUT_OF_MEMORY;
7867         }
7868         json_object_object_add(jso, "userids", jsouids_arr);
7869         for (size_t i = 0; i < key->uid_count(); i++) {
7870             json_object *jsouid = json_object_new_string(key->get_uid(i).str.c_str());
7871             if (!jsouid || json_object_array_add(jsouids_arr, jsouid)) {
7872                 json_object_put(jsouid);
7873                 return RNP_ERROR_OUT_OF_MEMORY;
7874             }
7875         }
7876     }
7877     // signatures
7878     if (flags & RNP_JSON_SIGNATURES) {
7879         json_object *jsosigs_arr = json_object_new_array();
7880         if (!jsosigs_arr) {
7881             return RNP_ERROR_OUT_OF_MEMORY;
7882         }
7883         json_object_object_add(jso, "signatures", jsosigs_arr);
7884         for (size_t i = 0; i < key->sig_count(); i++) {
7885             json_object *jsosig = json_object_new_object();
7886             if (!jsosig || json_object_array_add(jsosigs_arr, jsosig)) {
7887                 json_object_put(jsosig);
7888                 return RNP_ERROR_OUT_OF_MEMORY;
7889             }
7890             rnp_result_t tmpret;
7891             if ((tmpret =
7892                    add_json_subsig(jsosig, key->is_subkey(), flags, &key->get_sig(i)))) {
7893                 return tmpret;
7894             }
7895         }
7896     }
7897     return RNP_SUCCESS;
7898 }
7899 
7900 rnp_result_t
rnp_key_to_json(rnp_key_handle_t handle,uint32_t flags,char ** result)7901 rnp_key_to_json(rnp_key_handle_t handle, uint32_t flags, char **result)
7902 try {
7903     rnp_result_t ret = RNP_ERROR_GENERIC;
7904     json_object *jso = NULL;
7905 
7906     // checks
7907     if (!handle || !result) {
7908         return RNP_ERROR_NULL_POINTER;
7909     }
7910     jso = json_object_new_object();
7911     if (!jso) {
7912         ret = RNP_ERROR_OUT_OF_MEMORY;
7913         goto done;
7914     }
7915     if ((ret = key_to_json(jso, handle, flags))) {
7916         goto done;
7917     }
7918     *result = (char *) json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY);
7919     if (!*result) {
7920         goto done;
7921     }
7922     *result = strdup(*result);
7923     if (!*result) {
7924         ret = RNP_ERROR_OUT_OF_MEMORY;
7925         goto done;
7926     }
7927 
7928     ret = RNP_SUCCESS;
7929 done:
7930     json_object_put(jso);
7931     return ret;
7932 }
7933 FFI_GUARD
7934 
7935 static rnp_result_t
rnp_dump_src_to_json(pgp_source_t * src,uint32_t flags,char ** result)7936 rnp_dump_src_to_json(pgp_source_t *src, uint32_t flags, char **result)
7937 {
7938     rnp_dump_ctx_t dumpctx = {};
7939     json_object *  jso = NULL;
7940     rnp_result_t   ret = RNP_ERROR_GENERIC;
7941 
7942     if (flags & RNP_JSON_DUMP_MPI) {
7943         dumpctx.dump_mpi = true;
7944         flags &= ~RNP_JSON_DUMP_MPI;
7945     }
7946     if (flags & RNP_JSON_DUMP_RAW) {
7947         dumpctx.dump_packets = true;
7948         flags &= ~RNP_JSON_DUMP_RAW;
7949     }
7950     if (flags & RNP_JSON_DUMP_GRIP) {
7951         dumpctx.dump_grips = true;
7952         flags &= ~RNP_JSON_DUMP_GRIP;
7953     }
7954     if (flags) {
7955         return RNP_ERROR_BAD_PARAMETERS;
7956     }
7957 
7958     ret = stream_dump_packets_json(&dumpctx, src, &jso);
7959     if (ret) {
7960         goto done;
7961     }
7962 
7963     *result = (char *) json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY);
7964     if (!*result) {
7965         goto done;
7966     }
7967     *result = strdup(*result);
7968     if (!*result) {
7969         ret = RNP_ERROR_OUT_OF_MEMORY;
7970         goto done;
7971     }
7972 
7973     ret = RNP_SUCCESS;
7974 done:
7975     json_object_put(jso);
7976     return ret;
7977 }
7978 
7979 rnp_result_t
rnp_key_packets_to_json(rnp_key_handle_t handle,bool secret,uint32_t flags,char ** result)7980 rnp_key_packets_to_json(rnp_key_handle_t handle, bool secret, uint32_t flags, char **result)
7981 try {
7982     pgp_key_t *  key = NULL;
7983     rnp_result_t ret = RNP_ERROR_GENERIC;
7984     pgp_dest_t   memdst = {};
7985     pgp_source_t memsrc = {};
7986 
7987     if (!handle || !result) {
7988         return RNP_ERROR_NULL_POINTER;
7989     }
7990 
7991     key = secret ? handle->sec : handle->pub;
7992     if (!key || (key->format == PGP_KEY_STORE_G10)) {
7993         return RNP_ERROR_BAD_PARAMETERS;
7994     }
7995 
7996     if (init_mem_dest(&memdst, NULL, 0)) {
7997         return RNP_ERROR_OUT_OF_MEMORY;
7998     }
7999 
8000     key->write(memdst);
8001     if (memdst.werr) {
8002         ret = RNP_ERROR_BAD_PARAMETERS;
8003         goto done;
8004     }
8005 
8006     if (init_mem_src(&memsrc, mem_dest_get_memory(&memdst), memdst.writeb, false)) {
8007         ret = RNP_ERROR_BAD_STATE;
8008         goto done;
8009     }
8010 
8011     ret = rnp_dump_src_to_json(&memsrc, flags, result);
8012 done:
8013     dst_close(&memdst, true);
8014     src_close(&memsrc);
8015     return ret;
8016 }
8017 FFI_GUARD
8018 
8019 rnp_result_t
rnp_dump_packets_to_json(rnp_input_t input,uint32_t flags,char ** result)8020 rnp_dump_packets_to_json(rnp_input_t input, uint32_t flags, char **result)
8021 try {
8022     if (!input || !result) {
8023         return RNP_ERROR_NULL_POINTER;
8024     }
8025 
8026     return rnp_dump_src_to_json(&input->src, flags, result);
8027 }
8028 FFI_GUARD
8029 
8030 rnp_result_t
rnp_dump_packets_to_output(rnp_input_t input,rnp_output_t output,uint32_t flags)8031 rnp_dump_packets_to_output(rnp_input_t input, rnp_output_t output, uint32_t flags)
8032 try {
8033     if (!input || !output) {
8034         return RNP_ERROR_NULL_POINTER;
8035     }
8036 
8037     rnp_dump_ctx_t dumpctx = {};
8038 
8039     if (flags & RNP_DUMP_MPI) {
8040         dumpctx.dump_mpi = true;
8041         flags &= ~RNP_DUMP_MPI;
8042     }
8043     if (flags & RNP_DUMP_RAW) {
8044         dumpctx.dump_packets = true;
8045         flags &= ~RNP_DUMP_RAW;
8046     }
8047     if (flags & RNP_DUMP_GRIP) {
8048         dumpctx.dump_grips = true;
8049         flags &= ~RNP_DUMP_GRIP;
8050     }
8051     if (flags) {
8052         return RNP_ERROR_BAD_PARAMETERS;
8053     }
8054 
8055     rnp_result_t ret = stream_dump_packets(&dumpctx, &input->src, &output->dst);
8056     output->keep = true;
8057     return ret;
8058 }
8059 FFI_GUARD
8060 
8061 // move to next key
8062 static bool
key_iter_next_key(rnp_identifier_iterator_t it)8063 key_iter_next_key(rnp_identifier_iterator_t it)
8064 {
8065     // check if we not reached the end of the ring
8066     *it->keyp = std::next(*it->keyp);
8067     if (*it->keyp != it->store->keys.end()) {
8068         it->uididx = 0;
8069         return true;
8070     }
8071     // if we are currently on pubring, switch to secring (if not empty)
8072     if (it->store == it->ffi->pubring && !it->ffi->secring->keys.empty()) {
8073         it->store = it->ffi->secring;
8074         *it->keyp = it->store->keys.begin();
8075         it->uididx = 0;
8076         return true;
8077     }
8078     // we've gone through both rings
8079     it->store = NULL;
8080     return false;
8081 }
8082 
8083 // move to next item (key or userid)
8084 static bool
key_iter_next_item(rnp_identifier_iterator_t it)8085 key_iter_next_item(rnp_identifier_iterator_t it)
8086 {
8087     switch (it->type) {
8088     case PGP_KEY_SEARCH_KEYID:
8089     case PGP_KEY_SEARCH_FINGERPRINT:
8090     case PGP_KEY_SEARCH_GRIP:
8091         return key_iter_next_key(it);
8092     case PGP_KEY_SEARCH_USERID:
8093         it->uididx++;
8094         while (it->uididx >= (*it->keyp)->uid_count()) {
8095             if (!key_iter_next_key(it)) {
8096                 return false;
8097             }
8098             it->uididx = 0;
8099         }
8100         break;
8101     default:
8102         assert(false);
8103         break;
8104     }
8105     return true;
8106 }
8107 
8108 static bool
key_iter_first_key(rnp_identifier_iterator_t it)8109 key_iter_first_key(rnp_identifier_iterator_t it)
8110 {
8111     if (rnp_key_store_get_key_count(it->ffi->pubring)) {
8112         it->store = it->ffi->pubring;
8113     } else if (rnp_key_store_get_key_count(it->ffi->secring)) {
8114         it->store = it->ffi->secring;
8115     } else {
8116         it->store = NULL;
8117         return false;
8118     }
8119     *it->keyp = it->store->keys.begin();
8120     it->uididx = 0;
8121     return true;
8122 }
8123 
8124 static bool
key_iter_first_item(rnp_identifier_iterator_t it)8125 key_iter_first_item(rnp_identifier_iterator_t it)
8126 {
8127     switch (it->type) {
8128     case PGP_KEY_SEARCH_KEYID:
8129     case PGP_KEY_SEARCH_FINGERPRINT:
8130     case PGP_KEY_SEARCH_GRIP:
8131         return key_iter_first_key(it);
8132     case PGP_KEY_SEARCH_USERID:
8133         if (!key_iter_first_key(it)) {
8134             return false;
8135         }
8136         it->uididx = 0;
8137         while (it->uididx >= (*it->keyp)->uid_count()) {
8138             if (!key_iter_next_key(it)) {
8139                 return false;
8140             }
8141         }
8142         break;
8143     default:
8144         assert(false);
8145         break;
8146     }
8147     return true;
8148 }
8149 
8150 static bool
key_iter_get_item(const rnp_identifier_iterator_t it,char * buf,size_t buf_len)8151 key_iter_get_item(const rnp_identifier_iterator_t it, char *buf, size_t buf_len)
8152 {
8153     const pgp_key_t *key = &**it->keyp;
8154     switch (it->type) {
8155     case PGP_KEY_SEARCH_KEYID: {
8156         if (!rnp::hex_encode(key->keyid().data(), key->keyid().size(), buf, buf_len)) {
8157             return false;
8158         }
8159         break;
8160     }
8161     case PGP_KEY_SEARCH_FINGERPRINT:
8162         if (!rnp::hex_encode(key->fp().fingerprint, key->fp().length, buf, buf_len)) {
8163             return false;
8164         }
8165         break;
8166     case PGP_KEY_SEARCH_GRIP:
8167         if (!rnp::hex_encode(key->grip().data(), key->grip().size(), buf, buf_len)) {
8168             return false;
8169         }
8170         break;
8171     case PGP_KEY_SEARCH_USERID: {
8172         if (it->uididx >= key->uid_count()) {
8173             return false;
8174         }
8175         const pgp_userid_t &uid = key->get_uid(it->uididx);
8176         if (uid.str.size() >= buf_len) {
8177             return false;
8178         }
8179         memcpy(buf, uid.str.c_str(), uid.str.size() + 1);
8180     } break;
8181     default:
8182         assert(false);
8183         break;
8184     }
8185     return true;
8186 }
8187 
8188 rnp_result_t
rnp_identifier_iterator_create(rnp_ffi_t ffi,rnp_identifier_iterator_t * it,const char * identifier_type)8189 rnp_identifier_iterator_create(rnp_ffi_t                  ffi,
8190                                rnp_identifier_iterator_t *it,
8191                                const char *               identifier_type)
8192 try {
8193     rnp_result_t                       ret = RNP_ERROR_GENERIC;
8194     struct rnp_identifier_iterator_st *obj = NULL;
8195 
8196     // checks
8197     if (!ffi || !it || !identifier_type) {
8198         return RNP_ERROR_NULL_POINTER;
8199     }
8200     // create iterator
8201     obj = (struct rnp_identifier_iterator_st *) calloc(1, sizeof(*obj));
8202     if (!obj) {
8203         return RNP_ERROR_OUT_OF_MEMORY;
8204     }
8205     obj->ffi = ffi;
8206     obj->keyp = new std::list<pgp_key_t>::iterator();
8207     obj->uididx = 0;
8208     // parse identifier type
8209     obj->type = static_cast<pgp_key_search_type_t>(
8210       id_str_pair::lookup(identifier_type_map, identifier_type, PGP_KEY_SEARCH_UNKNOWN));
8211     if (obj->type == PGP_KEY_SEARCH_UNKNOWN) {
8212         ret = RNP_ERROR_BAD_PARAMETERS;
8213         goto done;
8214     }
8215     obj->tbl = json_object_new_object();
8216     if (!obj->tbl) {
8217         ret = RNP_ERROR_OUT_OF_MEMORY;
8218         goto done;
8219     }
8220     // move to first item (if any)
8221     key_iter_first_item(obj);
8222     *it = obj;
8223 
8224     ret = RNP_SUCCESS;
8225 done:
8226     if (ret) {
8227         rnp_identifier_iterator_destroy(obj);
8228     }
8229     return ret;
8230 }
8231 FFI_GUARD
8232 
8233 rnp_result_t
rnp_identifier_iterator_next(rnp_identifier_iterator_t it,const char ** identifier)8234 rnp_identifier_iterator_next(rnp_identifier_iterator_t it, const char **identifier)
8235 try {
8236     rnp_result_t ret = RNP_ERROR_GENERIC;
8237 
8238     // checks
8239     if (!it || !identifier) {
8240         return RNP_ERROR_NULL_POINTER;
8241     }
8242     // initialize the result to NULL
8243     *identifier = NULL;
8244     // this means we reached the end of the rings
8245     if (!it->store) {
8246         return RNP_SUCCESS;
8247     }
8248     // get the item
8249     if (!key_iter_get_item(it, it->buf, sizeof(it->buf))) {
8250         return RNP_ERROR_GENERIC;
8251     }
8252     bool exists;
8253     bool iterator_valid = true;
8254     while ((exists = json_object_object_get_ex(it->tbl, it->buf, NULL))) {
8255         if (!((iterator_valid = key_iter_next_item(it)))) {
8256             break;
8257         }
8258         if (!key_iter_get_item(it, it->buf, sizeof(it->buf))) {
8259             return RNP_ERROR_GENERIC;
8260         }
8261     }
8262     // see if we actually found a new entry
8263     if (!exists) {
8264         // TODO: Newer json-c has a useful return value for json_object_object_add,
8265         // which doesn't require the json_object_object_get_ex check below.
8266         json_object_object_add(it->tbl, it->buf, NULL);
8267         if (!json_object_object_get_ex(it->tbl, it->buf, NULL)) {
8268             ret = RNP_ERROR_OUT_OF_MEMORY;
8269             goto done;
8270         }
8271         *identifier = it->buf;
8272     }
8273     // prepare for the next one
8274     if (iterator_valid) {
8275         key_iter_next_item(it);
8276     }
8277     ret = RNP_SUCCESS;
8278 
8279 done:
8280     if (ret) {
8281         *identifier = NULL;
8282     }
8283     return ret;
8284 }
8285 FFI_GUARD
8286 
8287 rnp_result_t
rnp_identifier_iterator_destroy(rnp_identifier_iterator_t it)8288 rnp_identifier_iterator_destroy(rnp_identifier_iterator_t it)
8289 try {
8290     if (it) {
8291         json_object_put(it->tbl);
8292         if (it->keyp) {
8293             delete it->keyp;
8294         }
8295         free(it);
8296     }
8297     return RNP_SUCCESS;
8298 }
8299 FFI_GUARD
8300 
8301 rnp_result_t
rnp_guess_contents(rnp_input_t input,char ** contents)8302 rnp_guess_contents(rnp_input_t input, char **contents)
8303 try {
8304     if (!input || !contents) {
8305         return RNP_ERROR_NULL_POINTER;
8306     }
8307 
8308     pgp_armored_msg_t msgtype = PGP_ARMORED_UNKNOWN;
8309     if (is_armored_source(&input->src)) {
8310         msgtype = rnp_armored_get_type(&input->src);
8311     } else {
8312         msgtype = rnp_armor_guess_type(&input->src);
8313     }
8314     const char *msg = id_str_pair::lookup(armor_type_map, msgtype);
8315     size_t      len = strlen(msg);
8316     *contents = (char *) calloc(1, len + 1);
8317     if (!*contents) {
8318         return RNP_ERROR_OUT_OF_MEMORY;
8319     }
8320     memcpy(*contents, msg, len);
8321     return RNP_SUCCESS;
8322 }
8323 FFI_GUARD
8324 
8325 rnp_result_t
rnp_enarmor(rnp_input_t input,rnp_output_t output,const char * type)8326 rnp_enarmor(rnp_input_t input, rnp_output_t output, const char *type)
8327 try {
8328     pgp_armored_msg_t msgtype = PGP_ARMORED_UNKNOWN;
8329     if (!input || !output) {
8330         return RNP_ERROR_NULL_POINTER;
8331     }
8332     if (type) {
8333         msgtype = static_cast<pgp_armored_msg_t>(
8334           id_str_pair::lookup(armor_type_map, type, PGP_ARMORED_UNKNOWN));
8335         if (msgtype == PGP_ARMORED_UNKNOWN) {
8336             RNP_LOG("Unsupported armor type: %s", type);
8337             return RNP_ERROR_BAD_PARAMETERS;
8338         }
8339     } else {
8340         msgtype = rnp_armor_guess_type(&input->src);
8341         if (!msgtype) {
8342             RNP_LOG("Unrecognized data to armor (try specifying a type)");
8343             return RNP_ERROR_BAD_PARAMETERS;
8344         }
8345     }
8346     rnp_result_t ret = rnp_armor_source(&input->src, &output->dst, msgtype);
8347     output->keep = !ret;
8348     return ret;
8349 }
8350 FFI_GUARD
8351 
8352 rnp_result_t
rnp_dearmor(rnp_input_t input,rnp_output_t output)8353 rnp_dearmor(rnp_input_t input, rnp_output_t output)
8354 try {
8355     if (!input || !output) {
8356         return RNP_ERROR_NULL_POINTER;
8357     }
8358     rnp_result_t ret = rnp_dearmor_source(&input->src, &output->dst);
8359     output->keep = !ret;
8360     return ret;
8361 }
8362 FFI_GUARD
8363 
8364 rnp_result_t
rnp_output_pipe(rnp_input_t input,rnp_output_t output)8365 rnp_output_pipe(rnp_input_t input, rnp_output_t output)
8366 try {
8367     if (!input || !output) {
8368         return RNP_ERROR_NULL_POINTER;
8369     }
8370     rnp_result_t ret = dst_write_src(&input->src, &output->dst);
8371     output->keep = !ret;
8372     return ret;
8373 }
8374 FFI_GUARD
8375 
8376 rnp_result_t
rnp_output_armor_set_line_length(rnp_output_t output,size_t llen)8377 rnp_output_armor_set_line_length(rnp_output_t output, size_t llen)
8378 try {
8379     if (!output || !llen) {
8380         return RNP_ERROR_BAD_PARAMETERS;
8381     }
8382     return armored_dst_set_line_length(&output->dst, llen);
8383 }
8384 FFI_GUARD
8385 
8386 const char *
rnp_backend_string()8387 rnp_backend_string()
8388 {
8389     return rnp::backend_string();
8390 }
8391 
8392 const char *
rnp_backend_version()8393 rnp_backend_version()
8394 {
8395     return rnp::backend_version();
8396 }
8397