summaryrefslogtreecommitdiff
path: root/guile/src/extra.c
diff options
context:
space:
mode:
Diffstat (limited to 'guile/src/extra.c')
-rw-r--r--guile/src/extra.c544
1 files changed, 544 insertions, 0 deletions
diff --git a/guile/src/extra.c b/guile/src/extra.c
new file mode 100644
index 0000000000..440e6c3099
--- /dev/null
+++ b/guile/src/extra.c
@@ -0,0 +1,544 @@
+/* GNUTLS-EXTRA --- Guile bindings for GNUTLS-EXTRA.
+ Copyright (C) 2007 Free Software Foundation
+
+ GNUTLS-EXTRA is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ GNUTLS-EXTRA 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUTLS-EXTRA; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Important note: As written above, this part of the code is ditributed
+ under the GPL, not the LGPL. */
+
+/* Written by Ludovic Courtès <ludo@chbouib.org>. */
+
+
+#include <stdio.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/extra.h>
+#include <gnutls/openpgp.h>
+#include <libguile.h>
+
+#include <alloca.h>
+
+#include "errors.h"
+#include "utils.h"
+#include "smobs.h"
+#include "enums.h"
+#include "extra-enums.h"
+#include "extra-smobs.h"
+
+
+
+/* SMOB and enums type definitions. */
+
+#include "extra-smob-types.i.c"
+#include "extra-enum-map.i.c"
+
+
+/* OpenPGP keys. */
+
+
+/* Maximum size we support for the name of OpenPGP keys. */
+#define GUILE_GNUTLS_MAX_OPENPGP_NAME_LENGTH 2048
+
+SCM_DEFINE (scm_gnutls_import_openpgp_public_key, "import-openpgp-public-key",
+ 2, 0, 0,
+ (SCM data, SCM format),
+ "Return a new OpenPGP public key object resulting from the "
+ "import of @var{data} (a uniform array) according to "
+ "@var{format}.")
+#define FUNC_NAME s_scm_gnutls_import_openpgp_public_key
+{
+ int err;
+ gnutls_openpgp_key_t c_key;
+ gnutls_openpgp_key_fmt c_format;
+ gnutls_datum_t c_data_d;
+ scm_t_array_handle c_data_handle;
+ const char *c_data;
+ size_t c_data_len;
+
+ SCM_VALIDATE_ARRAY (1, data);
+ c_format = scm_to_gnutls_openpgp_key_format (format, 2, FUNC_NAME);
+
+ c_data = scm_gnutls_get_array (data, &c_data_handle, &c_data_len,
+ FUNC_NAME);
+ c_data_d.data = (unsigned char *) c_data;
+ c_data_d.size = c_data_len;
+
+ err = gnutls_openpgp_key_init (&c_key);
+ if (EXPECT_FALSE (err))
+ {
+ scm_gnutls_release_array (&c_data_handle);
+ scm_gnutls_error (err, FUNC_NAME);
+ }
+
+ err = gnutls_openpgp_key_import (c_key, &c_data_d, c_format);
+ scm_gnutls_release_array (&c_data_handle);
+
+ if (EXPECT_FALSE (err))
+ {
+ gnutls_openpgp_key_deinit (c_key);
+ scm_gnutls_error (err, FUNC_NAME);
+ }
+
+ return (scm_from_gnutls_openpgp_public_key (c_key));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_import_openpgp_private_key, "import-openpgp-private-key",
+ 2, 1, 0,
+ (SCM data, SCM format, SCM pass),
+ "Return a new OpenPGP private key object resulting from the "
+ "import of @var{data} (a uniform array) according to "
+ "@var{format}. Optionally, a passphrase may be provided.")
+#define FUNC_NAME s_scm_gnutls_import_openpgp_private_key
+{
+ int err;
+ gnutls_openpgp_privkey_t c_key;
+ gnutls_openpgp_key_fmt c_format;
+ gnutls_datum_t c_data_d;
+ scm_t_array_handle c_data_handle;
+ const char *c_data;
+ char *c_pass;
+ size_t c_data_len, c_pass_len;
+
+ SCM_VALIDATE_ARRAY (1, data);
+ c_format = scm_to_gnutls_openpgp_key_format (format, 2, FUNC_NAME);
+ if ((pass == SCM_UNDEFINED) || (scm_is_false (pass)))
+ c_pass = NULL;
+ else
+ {
+ c_pass_len = scm_c_string_length (pass);
+ c_pass = (char *) alloca (c_pass_len + 1);
+ (void) scm_to_locale_stringbuf (pass, c_pass, c_pass_len + 1);
+ c_pass[c_pass_len] = '\0';
+ }
+
+ c_data = scm_gnutls_get_array (data, &c_data_handle, &c_data_len,
+ FUNC_NAME);
+ c_data_d.data = (unsigned char *) c_data;
+ c_data_d.size = c_data_len;
+
+ err = gnutls_openpgp_privkey_init (&c_key);
+ if (EXPECT_FALSE (err))
+ {
+ scm_gnutls_release_array (&c_data_handle);
+ scm_gnutls_error (err, FUNC_NAME);
+ }
+
+ err = gnutls_openpgp_privkey_import (c_key, &c_data_d, c_format, c_pass,
+ 0 /* currently unused */);
+ scm_gnutls_release_array (&c_data_handle);
+
+ if (EXPECT_FALSE (err))
+ {
+ gnutls_openpgp_privkey_deinit (c_key);
+ scm_gnutls_error (err, FUNC_NAME);
+ }
+
+ return (scm_from_gnutls_openpgp_private_key (c_key));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_public_key_id, "openpgp-public-key-id",
+ 1, 0, 0,
+ (SCM key),
+ "Return the ID (an 8-element u8vector) of public key "
+ "@var{key}.")
+#define FUNC_NAME s_scm_gnutls_openpgp_public_key_id
+{
+ int err;
+ unsigned char *c_id;
+ gnutls_openpgp_key_t c_key;
+
+ c_key = scm_to_gnutls_openpgp_public_key (key, 1, FUNC_NAME);
+
+ c_id = (unsigned char * ) malloc (8);
+ if (c_id == NULL)
+ scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
+
+ err = gnutls_openpgp_key_get_id (c_key, c_id);
+ if (EXPECT_FALSE (err))
+ scm_gnutls_error (err, FUNC_NAME);
+
+ return (scm_take_u8vector (c_id, 8));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_public_key_id_x, "openpgp-public-key-id!",
+ 2, 0, 0,
+ (SCM key, SCM id),
+ "Store the ID (an 8 byte sequence) of public key "
+ "@var{key} in @var{id} (a u8vector).")
+#define FUNC_NAME s_scm_gnutls_openpgp_public_key_id_x
+{
+ int err;
+ char *c_id;
+ scm_t_array_handle c_id_handle;
+ size_t c_id_size;
+ gnutls_openpgp_key_t c_key;
+
+ c_key = scm_to_gnutls_openpgp_public_key (key, 1, FUNC_NAME);
+ c_id = scm_gnutls_get_writable_array (id, &c_id_handle, &c_id_size,
+ FUNC_NAME);
+
+ if (EXPECT_FALSE (c_id_size < 8))
+ {
+ scm_gnutls_release_array (&c_id_handle);
+ scm_misc_error (FUNC_NAME, "ID vector too small: ~A",
+ scm_list_1 (id));
+ }
+
+ err = gnutls_openpgp_key_get_id (c_key, (unsigned char *) c_id);
+ scm_gnutls_release_array (&c_id_handle);
+
+ if (EXPECT_FALSE (err))
+ scm_gnutls_error (err, FUNC_NAME);
+
+ return SCM_UNSPECIFIED;
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_public_key_fingerpint_x,
+ "openpgp-public-key-fingerprint!",
+ 2, 0, 0,
+ (SCM key, SCM fpr),
+ "Store in @var{fpr} (a u8vector) the fingerprint of @var{key}. "
+ "Return the number of bytes stored in @var{fpr}.")
+#define FUNC_NAME s_scm_gnutls_openpgp_public_key_fingerpint_x
+{
+ int err;
+ gnutls_openpgp_key_t c_key;
+ char *c_fpr;
+ scm_t_array_handle c_fpr_handle;
+ size_t c_fpr_len, c_actual_len = 0;
+
+ c_key = scm_to_gnutls_openpgp_public_key (key, 1, FUNC_NAME);
+ SCM_VALIDATE_ARRAY (2, fpr);
+
+ c_fpr = scm_gnutls_get_writable_array (fpr, &c_fpr_handle, &c_fpr_len,
+ FUNC_NAME);
+
+ err = gnutls_openpgp_key_get_fingerprint (c_key, c_fpr, &c_actual_len);
+ scm_gnutls_release_array (&c_fpr_handle);
+
+ if (EXPECT_FALSE (err))
+ scm_gnutls_error (err, FUNC_NAME);
+
+ return (scm_from_size_t (c_actual_len));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_public_key_fingerprint,
+ "openpgp-public-key-fingerprint",
+ 1, 0, 0,
+ (SCM key),
+ "Return a new u8vector denoting the fingerprint of "
+ "@var{key}.")
+#define FUNC_NAME s_scm_gnutls_openpgp_public_key_fingerprint
+{
+ int err;
+ gnutls_openpgp_key_t c_key;
+ unsigned char *c_fpr;
+ size_t c_fpr_len, c_actual_len;
+
+ c_key = scm_to_gnutls_openpgp_public_key (key, 1, FUNC_NAME);
+
+ /* V4 fingerprints are 160-bit SHA-1 hashes (see RFC2440). */
+ c_fpr_len = 20;
+ c_fpr = (unsigned char *) malloc (c_fpr_len);
+ if (EXPECT_FALSE (c_fpr == NULL))
+ scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
+
+ do
+ {
+ c_actual_len = 0;
+ err = gnutls_openpgp_key_get_fingerprint (c_key, c_fpr,
+ &c_actual_len);
+ if (err == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ {
+ /* Grow C_FPR. */
+ unsigned char *c_new;
+
+ c_new = (unsigned char *) realloc (c_fpr, c_fpr_len * 2);
+ if (EXPECT_FALSE (c_new == NULL))
+ {
+ free (c_fpr);
+ scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
+ }
+ else
+ {
+ c_fpr_len *= 2;
+ c_fpr = c_new;
+ }
+ }
+ }
+ while (err == GNUTLS_E_SHORT_MEMORY_BUFFER);
+
+ if (EXPECT_FALSE (err))
+ {
+ free (c_fpr);
+ scm_gnutls_error (err, FUNC_NAME);
+ }
+
+ if (c_actual_len < c_fpr_len)
+ /* Shrink C_FPR. */
+ c_fpr = realloc (c_fpr, c_actual_len);
+
+ return (scm_take_u8vector (c_fpr, c_actual_len));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_public_key_name, "openpgp-public-key-name",
+ 2, 0, 0,
+ (SCM key, SCM index),
+ "Return the @var{index}th name of @var{key}.")
+#define FUNC_NAME s_scm_gnutls_openpgp_public_key_name
+{
+ int err;
+ gnutls_openpgp_key_t c_key;
+ int c_index;
+ char c_name[GUILE_GNUTLS_MAX_OPENPGP_NAME_LENGTH];
+ size_t c_name_len = sizeof (c_name);
+
+ c_key = scm_to_gnutls_openpgp_public_key (key, 1, FUNC_NAME);
+ c_index = scm_to_int (index);
+
+ err = gnutls_openpgp_key_get_name (c_key, c_index, c_name,
+ &c_name_len);
+ if (EXPECT_FALSE (err))
+ scm_gnutls_error (err, FUNC_NAME);
+
+ /* XXX: The name is really UTF-8. */
+ return (scm_from_locale_string (c_name));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_public_key_names, "openpgp-public-key-names",
+ 1, 0, 0,
+ (SCM key),
+ "Return the list of names for @var{key}.")
+#define FUNC_NAME s_scm_gnutls_openpgp_public_key_names
+{
+ int err;
+ SCM result = SCM_EOL;
+ gnutls_openpgp_key_t c_key;
+ int c_index = 0;
+ char c_name[GUILE_GNUTLS_MAX_OPENPGP_NAME_LENGTH];
+ size_t c_name_len = sizeof (c_name);
+
+ c_key = scm_to_gnutls_openpgp_public_key (key, 1, FUNC_NAME);
+
+ do
+ {
+ err = gnutls_openpgp_key_get_name (c_key, c_index, c_name,
+ &c_name_len);
+ if (!err)
+ {
+ result = scm_cons (scm_from_locale_string (c_name),
+ result);
+ c_index++;
+ }
+ }
+ while (!err);
+
+ if (EXPECT_FALSE (err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE))
+ scm_gnutls_error (err, FUNC_NAME);
+
+ return (scm_reverse_x (result, SCM_EOL));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_public_key_algorithm,
+ "openpgp-public-key-algorithm",
+ 1, 0, 0,
+ (SCM key),
+ "Return two values: the public key algorithm used by "
+ "@var{key} and the number of bits used.")
+#define FUNC_NAME s_scm_gnutls_openpgp_public_key_algorithm
+{
+ gnutls_openpgp_key_t c_key;
+ unsigned int c_bits;
+ gnutls_pk_algorithm_t c_algo;
+
+ c_key = scm_to_gnutls_openpgp_public_key (key, 1, FUNC_NAME);
+ c_algo = gnutls_openpgp_key_get_pk_algorithm (c_key, &c_bits);
+
+ return (scm_values (scm_list_2 (scm_from_gnutls_pk_algorithm (c_algo),
+ scm_from_uint (c_bits))));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_public_key_version,
+ "openpgp-public-key-version",
+ 1, 0, 0,
+ (SCM key),
+ "Return the version of the OpenPGP message format (RFC2440) "
+ "honored by @var{key}.")
+#define FUNC_NAME s_scm_gnutls_openpgp_public_key_version
+{
+ int c_version;
+ gnutls_openpgp_key_t c_key;
+
+ c_key = scm_to_gnutls_openpgp_public_key (key, 1, FUNC_NAME);
+ c_version = gnutls_openpgp_key_get_version (c_key);
+
+ return (scm_from_int (c_version));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_public_key_usage, "openpgp-public-key-usage",
+ 1, 0, 0,
+ (SCM key),
+ "Return a list of values denoting the key usage of @var{key}.")
+#define FUNC_NAME s_scm_gnutls_openpgp_public_key_usage
+{
+ int err;
+ unsigned int c_usage = 0;
+ gnutls_openpgp_key_t c_key;
+
+ c_key = scm_to_gnutls_openpgp_public_key (key, 1, FUNC_NAME);
+
+ err = gnutls_openpgp_key_get_key_usage (c_key, &c_usage);
+ if (EXPECT_FALSE (err))
+ scm_gnutls_error (err, FUNC_NAME);
+
+ return (scm_from_gnutls_key_usage_flags (c_usage));
+}
+#undef FUNC_NAME
+
+
+
+/* OpenPGP keyrings. */
+
+SCM_DEFINE (scm_gnutls_import_openpgp_keyring, "import-openpgp-keyring",
+ 2, 0, 0,
+ (SCM data, SCM format),
+ "Import @var{data} (a u8vector) according to @var{format} "
+ "and return the imported keyring.")
+#define FUNC_NAME s_scm_gnutls_import_openpgp_keyring
+{
+ int err;
+ gnutls_openpgp_keyring_t c_keyring;
+ gnutls_openpgp_key_fmt c_format;
+ gnutls_datum_t c_data_d;
+ scm_t_array_handle c_data_handle;
+ const char *c_data;
+ size_t c_data_len;
+
+ SCM_VALIDATE_ARRAY (1, data);
+ c_format = scm_to_gnutls_openpgp_key_format (format, 2, FUNC_NAME);
+
+ c_data = scm_gnutls_get_array (data, &c_data_handle, &c_data_len,
+ FUNC_NAME);
+
+ c_data_d.data = (unsigned char *) c_data;
+ c_data_d.size = c_data_len;
+
+ err = gnutls_openpgp_keyring_init (&c_keyring);
+ if (EXPECT_FALSE (err))
+ {
+ scm_gnutls_release_array (&c_data_handle);
+ scm_gnutls_error (err, FUNC_NAME);
+ }
+
+ err = gnutls_openpgp_keyring_import (c_keyring, &c_data_d, c_format);
+ scm_gnutls_release_array (&c_data_handle);
+
+ if (EXPECT_FALSE (err))
+ {
+ gnutls_openpgp_keyring_deinit (c_keyring);
+ scm_gnutls_error (err, FUNC_NAME);
+ }
+
+ return (scm_from_gnutls_openpgp_keyring (c_keyring));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_gnutls_openpgp_keyring_contains_key_id_p,
+ "openpgp-keyring-contains-key-id?",
+ 2, 0, 0,
+ (SCM keyring, SCM id),
+ "Return @code{#f} if key ID @var{id} is in @var{keyring}, "
+ "@code{#f} otherwise.")
+#define FUNC_NAME s_scm_gnutls_openpgp_keyring_contains_key_id_p
+{
+ int c_result;
+ gnutls_openpgp_keyring_t c_keyring;
+ scm_t_array_handle c_id_handle;
+ const char *c_id;
+ size_t c_id_len;
+
+ c_keyring = scm_to_gnutls_openpgp_keyring (keyring, 1, FUNC_NAME);
+ SCM_VALIDATE_ARRAY (1, id);
+
+ c_id = scm_gnutls_get_array (id, &c_id_handle, &c_id_len,
+ FUNC_NAME);
+ if (EXPECT_FALSE (c_id_len != 8))
+ {
+ scm_gnutls_release_array (&c_id_handle);
+ scm_wrong_type_arg (FUNC_NAME, 1, id);
+ }
+
+ c_result = gnutls_openpgp_keyring_check_id (c_keyring,
+ (unsigned char *) c_id,
+ 0 /* unused */);
+
+ scm_gnutls_release_array (&c_id_handle);
+
+ return (scm_from_bool (c_result == 0));
+}
+#undef FUNC_NAME
+
+
+/* Certificates. */
+
+SCM_DEFINE (scm_gnutls_set_certificate_credentials_openpgp_keys_x,
+ "set-certificate-credentials-openpgp-keys!",
+ 3, 0, 0,
+ (SCM cred, SCM pub, SCM sec),
+ "Use public key @var{pub} and secret key @var{sec} in "
+ "certificate credentials @var{cred}.")
+#define FUNC_NAME s_scm_gnutls_set_certificate_credentials_openpgp_keys_x
+{
+ int err;
+ gnutls_certificate_credentials_t c_cred;
+ gnutls_openpgp_key_t c_pub;
+ gnutls_openpgp_privkey_t c_sec;
+
+ c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
+ c_pub = scm_to_gnutls_openpgp_public_key (pub, 2, FUNC_NAME);
+ c_sec = scm_to_gnutls_openpgp_private_key (sec, 3, FUNC_NAME);
+
+ err = gnutls_certificate_set_openpgp_key (c_cred, c_pub, c_sec);
+ if (EXPECT_FALSE (err))
+ scm_gnutls_error (err, FUNC_NAME);
+
+ return SCM_UNSPECIFIED;
+}
+#undef FUNC_NAME
+
+
+/* Initialization. */
+
+void
+scm_init_gnutls_extra (void)
+{
+#include "extra.c.x"
+
+ (void) gnutls_global_init_extra ();
+
+ scm_gnutls_define_enums ();
+}
+
+/* arch-tag: 655f308d-5643-4bc7-9db4-1f84bd902bef
+ */