summaryrefslogtreecommitdiff
path: root/pkcs11/gkm/gkm-dsa-mechanism.c
diff options
context:
space:
mode:
Diffstat (limited to 'pkcs11/gkm/gkm-dsa-mechanism.c')
-rw-r--r--pkcs11/gkm/gkm-dsa-mechanism.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/pkcs11/gkm/gkm-dsa-mechanism.c b/pkcs11/gkm/gkm-dsa-mechanism.c
new file mode 100644
index 00000000..65585048
--- /dev/null
+++ b/pkcs11/gkm/gkm-dsa-mechanism.c
@@ -0,0 +1,144 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkm-crypto.h"
+#include "gkm-dsa-mechanism.h"
+#include "gkm-session.h"
+#include "gkm-sexp.h"
+#include "gkm-sexp-key.h"
+
+#include "egg/egg-libgcrypt.h"
+#include "egg/egg-secure-memory.h"
+
+/* ----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+CK_RV
+gkm_dsa_mechanism_sign (gcry_sexp_t sexp, CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR signature, CK_ULONG_PTR n_signature)
+{
+ gcry_sexp_t ssig, splain;
+ gcry_error_t gcry;
+ gcry_mpi_t mpi;
+ CK_ULONG size;
+ CK_RV rv;
+
+ g_return_val_if_fail (sexp, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (n_signature, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (data, CKR_ARGUMENTS_BAD);
+
+ if (n_data != 20)
+ return CKR_DATA_LEN_RANGE;
+
+ /* If no output, then don't process */
+ if (!signature) {
+ *n_signature = 40;
+ return CKR_OK;
+ } else if (*n_signature < 40) {
+ *n_signature = 40;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ /* Prepare the input s-expression */
+ gcry = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, data, n_data, NULL);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+ gcry = gcry_sexp_build (&splain, NULL, "(data (flags raw) (value %m))", mpi);
+ gcry_mpi_release (mpi);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+ /* Do the magic */
+ gcry = gcry_pk_sign (&ssig, splain, sexp);
+ gcry_sexp_release (splain);
+
+ /* TODO: Certain codes should be returned (data too big etc... ) */
+ if (gcry) {
+ g_message ("signing of the data failed: %s", gcry_strerror (gcry));
+ return CKR_FUNCTION_FAILED;
+ }
+
+ g_assert (*n_signature >= 40);
+
+ size = 20;
+ rv = gkm_crypto_sexp_to_data (ssig, 20 * 8, signature, &size, NULL, "dsa", "r", NULL);
+ if (rv == CKR_OK) {
+ g_return_val_if_fail (size == 20, CKR_GENERAL_ERROR);
+ rv = gkm_crypto_sexp_to_data (ssig, 20 * 8, signature + 20, &size, NULL, "dsa", "s", NULL);
+ if (rv == CKR_OK) {
+ g_return_val_if_fail (size == 20, CKR_GENERAL_ERROR);
+ *n_signature = 40;
+ }
+ }
+
+ gcry_sexp_release (ssig);
+ return CKR_OK;
+}
+
+CK_RV
+gkm_dsa_mechanism_verify (gcry_sexp_t sexp, CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR signature, CK_ULONG n_signature)
+{
+ gcry_sexp_t ssig, splain;
+ gcry_error_t gcry;
+ gcry_mpi_t mpi, mpi2;
+
+ g_return_val_if_fail (sexp, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (signature, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (data, CKR_ARGUMENTS_BAD);
+
+ if (n_data != 20)
+ return CKR_DATA_LEN_RANGE;
+ if (n_signature != 40)
+ return CKR_SIGNATURE_LEN_RANGE;
+
+ /* Prepare the input s-expressions */
+ gcry = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, data, n_data, NULL);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+ gcry = gcry_sexp_build (&splain, NULL, "(data (flags raw) (value %m))", mpi);
+ gcry_mpi_release (mpi);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+ gcry = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, signature, 20, NULL);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+ gcry = gcry_mpi_scan (&mpi2, GCRYMPI_FMT_USG, signature + 20, 20, NULL);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+ gcry = gcry_sexp_build (&ssig, NULL, "(sig-val (dsa (r %m) (s %m)))", mpi, mpi2);
+ gcry_mpi_release (mpi);
+ gcry_mpi_release (mpi2);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+ /* Do the magic */
+ gcry = gcry_pk_verify (ssig, splain, sexp);
+ gcry_sexp_release (splain);
+ gcry_sexp_release (ssig);
+
+ /* TODO: See if any other codes should be mapped */
+ if (gcry_err_code (gcry) == GPG_ERR_BAD_SIGNATURE) {
+ return CKR_SIGNATURE_INVALID;
+ } else if (gcry) {
+ g_message ("signing of the data failed: %s", gcry_strerror (gcry));
+ return CKR_FUNCTION_FAILED;
+ }
+
+ return CKR_OK;
+}