1 /*
2 * gnome-keyring
3 *
4 * Copyright (C) 2008 Stefan Walter
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include "gkm-crypto.h"
24 #include "gkm-dsa-mechanism.h"
25 #include "gkm-session.h"
26 #include "gkm-sexp.h"
27 #include "gkm-sexp-key.h"
28
29 #include "egg/egg-libgcrypt.h"
30 #include "egg/egg-secure-memory.h"
31
32 /* ----------------------------------------------------------------------------
33 * PUBLIC
34 */
35
36 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)37 gkm_dsa_mechanism_sign (gcry_sexp_t sexp, CK_BYTE_PTR data, CK_ULONG n_data,
38 CK_BYTE_PTR signature, CK_ULONG_PTR n_signature)
39 {
40 gcry_sexp_t ssig, splain;
41 gcry_error_t gcry;
42 gcry_mpi_t mpi;
43 CK_ULONG size;
44 CK_RV rv;
45
46 g_return_val_if_fail (sexp, CKR_GENERAL_ERROR);
47 g_return_val_if_fail (n_signature, CKR_ARGUMENTS_BAD);
48 g_return_val_if_fail (data, CKR_ARGUMENTS_BAD);
49
50 if (n_data != 20)
51 return CKR_DATA_LEN_RANGE;
52
53 /* If no output, then don't process */
54 if (!signature) {
55 *n_signature = 40;
56 return CKR_OK;
57 } else if (*n_signature < 40) {
58 *n_signature = 40;
59 return CKR_BUFFER_TOO_SMALL;
60 }
61
62 /* Prepare the input s-expression */
63 gcry = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, data, n_data, NULL);
64 g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
65 gcry = gcry_sexp_build (&splain, NULL, "(data (flags raw) (value %m))", mpi);
66 gcry_mpi_release (mpi);
67 g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
68
69 /* Do the magic */
70 gcry = gcry_pk_sign (&ssig, splain, sexp);
71 gcry_sexp_release (splain);
72
73 /* TODO: Certain codes should be returned (data too big etc... ) */
74 if (gcry) {
75 g_message ("signing of the data failed: %s", gcry_strerror (gcry));
76 return CKR_FUNCTION_FAILED;
77 }
78
79 g_assert (*n_signature >= 40);
80
81 size = 20;
82 rv = gkm_crypto_sexp_to_data (ssig, 20 * 8, signature, &size, NULL, "dsa", "r", NULL);
83 if (rv == CKR_OK) {
84 g_return_val_if_fail (size == 20, CKR_GENERAL_ERROR);
85 rv = gkm_crypto_sexp_to_data (ssig, 20 * 8, signature + 20, &size, NULL, "dsa", "s", NULL);
86 if (rv == CKR_OK) {
87 g_return_val_if_fail (size == 20, CKR_GENERAL_ERROR);
88 *n_signature = 40;
89 }
90 }
91
92 gcry_sexp_release (ssig);
93 return rv;
94 }
95
96 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)97 gkm_dsa_mechanism_verify (gcry_sexp_t sexp, CK_BYTE_PTR data, CK_ULONG n_data,
98 CK_BYTE_PTR signature, CK_ULONG n_signature)
99 {
100 gcry_sexp_t ssig, splain;
101 gcry_error_t gcry;
102 gcry_mpi_t mpi, mpi2;
103
104 g_return_val_if_fail (sexp, CKR_GENERAL_ERROR);
105 g_return_val_if_fail (signature, CKR_ARGUMENTS_BAD);
106 g_return_val_if_fail (data, CKR_ARGUMENTS_BAD);
107
108 if (n_data != 20)
109 return CKR_DATA_LEN_RANGE;
110 if (n_signature != 40)
111 return CKR_SIGNATURE_LEN_RANGE;
112
113 /* Prepare the input s-expressions */
114 gcry = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, data, n_data, NULL);
115 g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
116 gcry = gcry_sexp_build (&splain, NULL, "(data (flags raw) (value %m))", mpi);
117 gcry_mpi_release (mpi);
118 g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
119
120 gcry = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, signature, 20, NULL);
121 g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
122 gcry = gcry_mpi_scan (&mpi2, GCRYMPI_FMT_USG, signature + 20, 20, NULL);
123 g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
124 gcry = gcry_sexp_build (&ssig, NULL, "(sig-val (dsa (r %m) (s %m)))", mpi, mpi2);
125 gcry_mpi_release (mpi);
126 gcry_mpi_release (mpi2);
127 g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
128
129 /* Do the magic */
130 gcry = gcry_pk_verify (ssig, splain, sexp);
131 gcry_sexp_release (splain);
132 gcry_sexp_release (ssig);
133
134 /* TODO: See if any other codes should be mapped */
135 if (gcry_err_code (gcry) == GPG_ERR_BAD_SIGNATURE) {
136 return CKR_SIGNATURE_INVALID;
137 } else if (gcry) {
138 g_message ("verifying of the data failed: %s", gcry_strerror (gcry));
139 return CKR_FUNCTION_FAILED;
140 }
141
142 return CKR_OK;
143 }
144