aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/engine-assuan.c1
-rw-r--r--src/engine-backend.h3
-rw-r--r--src/engine-g13.c1
-rw-r--r--src/engine-gpg.c24
-rw-r--r--src/engine-gpgconf.c1
-rw-r--r--src/engine-gpgsm.c1
-rw-r--r--src/engine-spawn.c1
-rw-r--r--src/engine-uiserver.c1
-rw-r--r--src/engine.c20
-rw-r--r--src/engine.h4
-rw-r--r--src/genrandom.c149
-rw-r--r--src/gpgme.def2
-rw-r--r--src/gpgme.h.in12
-rw-r--r--src/libgpgme.vers2
15 files changed, 223 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 93de55b9..50f4bb4f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -85,7 +85,7 @@ main_sources = \
key.c keylist.c keysign.c tofupolicy.c \
revsig.c \
import.c export.c genkey.c delete.c edit.c getauditlog.c \
- setexpire.c setownertrust.c \
+ setexpire.c setownertrust.c genrandom.c \
opassuan.c passwd.c spawn.c assuan-support.c \
engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
engine-gpgsm.c engine-assuan.c engine-gpgconf.c \
diff --git a/src/engine-assuan.c b/src/engine-assuan.c
index ee28740d..e96313ff 100644
--- a/src/engine-assuan.c
+++ b/src/engine-assuan.c
@@ -841,6 +841,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
NULL, /* setexpire */
NULL, /* setownertrust */
llass_transact, /* opassuan_transact */
+ NULL, /* getdirect */
NULL, /* conf_load */
NULL, /* conf_save */
NULL, /* conf_dir */
diff --git a/src/engine-backend.h b/src/engine-backend.h
index d889d1a7..b0533f77 100644
--- a/src/engine-backend.h
+++ b/src/engine-backend.h
@@ -140,6 +140,9 @@ struct engine_ops
gpgme_assuan_status_cb_t status_cb,
void *status_cb_value);
+ gpgme_error_t (*getdirect) (void *engine, const char *argv[],
+ gpgme_data_t dataout, unsigned int flags);
+
gpgme_error_t (*conf_load) (void *engine, gpgme_conf_comp_t *conf_p);
gpgme_error_t (*conf_save) (void *engine, gpgme_conf_comp_t conf);
gpgme_error_t (*conf_dir) (void *engine, const char *what, char **result);
diff --git a/src/engine-g13.c b/src/engine-g13.c
index 9852be88..e30c1834 100644
--- a/src/engine-g13.c
+++ b/src/engine-g13.c
@@ -812,6 +812,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
NULL, /* setexpire */
NULL, /* setownertrust */
g13_transact,
+ NULL, /* getdirect */
NULL, /* conf_load */
NULL, /* conf_save */
NULL, /* conf_dir */
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index 0768ea74..66303263 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -4173,6 +4173,29 @@ gpg_setownertrust (void *engine, gpgme_key_t key, const char *value)
}
+static gpgme_error_t
+gpg_getdirect (void *engine, const char *argv[],
+ gpgme_data_t dataout, unsigned int flags)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+ int i;
+
+ if (!engine || !argv || !dataout || flags)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ for (i=0; !err && argv[i]; i++)
+ if ((err = add_arg (gpg, argv[i])))
+ return err;
+
+ err = add_data (gpg, dataout, 1, 1);
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
struct engine_ops _gpgme_engine_ops_gpg =
{
@@ -4214,6 +4237,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
gpg_setexpire,
gpg_setownertrust,
NULL, /* opassuan_transact */
+ gpg_getdirect,
NULL, /* conf_load */
NULL, /* conf_save */
NULL, /* conf_dir */
diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c
index 03999ddd..d1b977ad 100644
--- a/src/engine-gpgconf.c
+++ b/src/engine-gpgconf.c
@@ -1312,6 +1312,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
NULL, /* setexpire */
NULL, /* setownertrust */
NULL, /* opassuan_transact */
+ NULL, /* getdirect */
gpgconf_conf_load,
gpgconf_conf_save,
gpgconf_conf_dir,
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index dfc51128..e9d69d7a 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -2446,6 +2446,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
NULL, /* setexpire */
NULL, /* setownertrust */
NULL, /* opassuan_transact */
+ NULL, /* getdirect */
NULL, /* conf_load */
NULL, /* conf_save */
NULL, /* conf_dir */
diff --git a/src/engine-spawn.c b/src/engine-spawn.c
index a6280cde..7fdac9ca 100644
--- a/src/engine-spawn.c
+++ b/src/engine-spawn.c
@@ -472,6 +472,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
NULL, /* setexpire */
NULL, /* setownertrust */
NULL, /* opassuan_transact */
+ NULL, /* getdirect */
NULL, /* conf_load */
NULL, /* conf_save */
NULL, /* conf_dir */
diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c
index cdde41fd..6c89082e 100644
--- a/src/engine-uiserver.c
+++ b/src/engine-uiserver.c
@@ -1455,6 +1455,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
NULL, /* setexpire */
NULL, /* setownertrust */
NULL, /* opassuan_transact */
+ NULL, /* getdirect */
NULL, /* conf_load */
NULL, /* conf_save */
NULL, /* conf_dir */
diff --git a/src/engine.c b/src/engine.c
index 516bc3d1..d341488e 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -987,6 +987,26 @@ _gpgme_engine_op_assuan_transact (engine_t engine,
}
+/* Direct invocation of the engine's tool.
+ *
+ * For example with argv[0] = "--gen-random" and argv[1] = "30" the
+ * gpg engine puts 30 bytes zbase32 encoded random into DATAOUT.
+ * FLAGS must be passed as 0 for now.
+ */
+gpgme_error_t
+_gpgme_engine_op_getdirect (engine_t engine, const char *argv[],
+ gpgme_data_t dataout, unsigned int flags)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->getdirect)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->getdirect) (engine->engine, argv, dataout, flags);
+}
+
+
gpgme_error_t
_gpgme_engine_op_conf_load (engine_t engine, gpgme_conf_comp_t *conf_p)
{
diff --git a/src/engine.h b/src/engine.h
index 8c2d03ca..7befec90 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -185,6 +185,10 @@ gpgme_error_t _gpgme_engine_op_assuan_transact
gpgme_assuan_status_cb_t status_cb,
void *status_cb_value);
+gpgme_error_t _gpgme_engine_op_getdirect (engine_t engine, const char *argv[],
+ gpgme_data_t dataout,
+ unsigned int flags);
+
gpgme_error_t _gpgme_engine_op_conf_load (engine_t engine,
gpgme_conf_comp_t *conf_p);
gpgme_error_t _gpgme_engine_op_conf_save (engine_t engine,
diff --git a/src/genrandom.c b/src/genrandom.c
new file mode 100644
index 00000000..a4baa0b2
--- /dev/null
+++ b/src/genrandom.c
@@ -0,0 +1,149 @@
+/* genrandom.c - Wrapper around gpg --gen-random
+ * Copyright (C) 2025 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <https://gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <assert.h>
+
+#include "gpgme.h"
+#include "debug.h"
+#include "context.h"
+#include "ops.h"
+
+
+static gpgme_error_t
+do_genrandom (gpgme_ctx_t ctx, gpgme_data_t dataout, size_t length, int zbase)
+{
+ gpgme_error_t err;
+ const char *argv[4];
+ char countbuf[35];
+
+ if (ctx->protocol != GPGME_PROTOCOL_OPENPGP)
+ return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+
+ err = _gpgme_op_reset (ctx, 1/*synchronous*/);
+ if (err)
+ return err;
+
+ snprintf (countbuf, sizeof countbuf, "%zu", length);
+ argv[0] = "--gen-random";
+ argv[1] = zbase? "30" : "2";
+ argv[2] = countbuf;
+ argv[3] = NULL;
+
+ err = _gpgme_engine_op_getdirect (ctx->engine, argv, dataout, 0);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+
+ return err;
+}
+
+
+/* Fill BUFFER of size BUFSIZE with random bytes retrieved from gpg.
+ * If GPGME_RANDOM_MODE_ZBASE32 is used BUFSIZE needs to be at least
+ * 31 and will be filled with a string of 30 ascii characters followed
+ * by a Nul; the remainder of the buffer is not changed. In all other
+ * modes the entire buffer will be filled with binary data. The
+ * function has a limit of 1024 bytes to avoid accidental overuse of
+ * the random generator. */
+gpgme_error_t
+gpgme_op_random_bytes (gpgme_ctx_t ctx, gpgme_random_mode_t mode,
+ char *buffer, size_t bufsize)
+{
+ gpgme_error_t err = 0;
+ gpgme_data_t data = NULL;
+ char *datap = NULL;
+ size_t datalen;
+
+ TRACE_BEG (DEBUG_CTX, "gpgme_op_random_bytes", ctx, "mode=%d size=%zu",
+ mode, bufsize);
+
+ if (!ctx || !buffer || !bufsize)
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ else if (mode == GPGME_RANDOM_MODE_ZBASE32)
+ {
+ /* The output is expected to be 30 ascii characters followed by
+ * a trailing Nul. */
+ if (bufsize < 31)
+ err = gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
+ }
+ else if (mode)
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ else if (bufsize > 1024) /* More or an less arbitrary limit. */
+ err = gpg_error (GPG_ERR_TOO_LARGE);
+
+ if (err)
+ goto leave;
+
+ err = gpgme_data_new (&data);
+ if (err)
+ goto leave;
+
+ err = do_genrandom (ctx, data, bufsize, (mode == GPGME_RANDOM_MODE_ZBASE32));
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ if (err)
+ goto leave;
+
+ datap = gpgme_data_release_and_get_mem (data, &datalen);
+ data = NULL;
+ if (!datap)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ if (datalen > bufsize)
+ {
+ err = gpg_error (GPG_ERR_INTERNAL);
+ goto leave;
+ }
+ if (mode == GPGME_RANDOM_MODE_ZBASE32)
+ {
+ /* Strip trailing LF. */
+ while (datalen
+ && (datap[datalen-1] == '\n' || datap[datalen-1] == '\r'))
+ datalen--;
+
+ if (datalen != 30)
+ {
+ /* 30 is the holy count, not 29, not 31 and never 32. */
+ err = gpg_error (GPG_ERR_INTERNAL);
+ goto leave;
+ }
+ memcpy (buffer, datap, datalen);
+ buffer[datalen] = 0;
+ }
+ else
+ {
+ if (datalen != bufsize)
+ {
+ err = gpg_error (GPG_ERR_INTERNAL);
+ goto leave;
+ }
+ memcpy (buffer, datap, datalen);
+ }
+
+ leave:
+ free (datap);
+ gpgme_data_release (data);
+ return TRACE_ERR (err);
+}
diff --git a/src/gpgme.def b/src/gpgme.def
index 5a7f430a..d203901f 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -274,4 +274,6 @@ EXPORTS
gpgme_op_setownertrust @213
gpgme_op_setownertrust_start @214
+
+ gpgme_op_random_bytes @215
; END
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 52b15971..9c0c7977 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -2473,6 +2473,18 @@ gpgme_error_t gpgme_op_query_swdb (gpgme_ctx_t ctx,
gpgme_query_swdb_result_t gpgme_op_query_swdb_result (gpgme_ctx_t ctx);
+/* Mode values for gpgme_op_get_random_bytes. */
+typedef enum
+ {
+ GPGME_RANDOM_MODE_NORMAL = 0,
+ GPGME_RANDOM_MODE_ZBASE32 = 1
+ }
+gpgme_random_mode_t;
+
+/* Fill BUFFER with BUFSIZE random bytes from gpg. */
+gpgme_error_t gpgme_op_random_bytes (gpgme_ctx_t ctx, gpgme_random_mode_t mode,
+ char *buffer, size_t bufsize);
+
/*
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index 3b7849bb..83f8c87b 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -273,6 +273,8 @@ GPGME_1.0 {
gpgme_op_setownertrust;
gpgme_op_setownertrust_start;
+ gpgme_op_random_bytes;
+
local:
*;