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