summaryrefslogtreecommitdiffstats
path: root/debian/patches/53-fips-fix-checking-on-hash-algorithm-used-in-ECDSA.patch
blob: 5e9080f218b4d236d0d7d22f54617c57d1c5e2f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
From 48bb9d0cf5de06cfb483aea66ff5a2c7aa3eb46f Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Tue, 20 Sep 2022 16:06:13 +0900
Subject: [PATCH 08/29] fips: fix checking on hash algorithm used in ECDSA

Previously we checked against the "preferred" hash algorithm based on
the curve, instead of the one actually used.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
 lib/crypto-backend.h | 12 ++++---
 lib/nettle/pk.c      | 33 ++++++++---------
 lib/pubkey.c         |  5 ++-
 tests/fips-test.c    | 86 ++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 111 insertions(+), 25 deletions(-)

--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -245,15 +245,17 @@ typedef enum {
 	GNUTLS_PK_FLAG_PROVABLE = 1,
 	GNUTLS_PK_FLAG_REPRODUCIBLE = 2,
 	GNUTLS_PK_FLAG_RSA_PSS_FIXED_SALT_LENGTH = 4
 } gnutls_pk_flag_t;
 
-#define FIX_SIGN_PARAMS(params, flags, dig) do {		\
-	if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) {	\
-		(params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE;	\
-		(params).dsa_dig = (dig);			\
-	}							\
+#define FIX_SIGN_PARAMS(params, flags, dig) do {			\
+	if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) {		\
+		(params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE;		\
+	}								\
+	if ((params).pk == GNUTLS_PK_DSA || (params).pk == GNUTLS_PK_ECDSA) { \
+		(params).dsa_dig = (dig);				\
+	}								\
 } while (0)
 
 void gnutls_pk_params_release(gnutls_pk_params_st * p);
 void gnutls_pk_params_clear(gnutls_pk_params_st * p);
 void gnutls_pk_params_init(gnutls_pk_params_st * p);
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -1102,29 +1102,29 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
 			dsa_signature_init(&sig);
 
 			me = _gnutls_dsa_q_to_hash(pk_params,
 						   &hash_len);
 
+			if (hash_len > vdata->size) {
+				gnutls_assert();
+				_gnutls_debug_log
+				    ("Security level of algorithm requires hash %s(%d) or better\n",
+				     _gnutls_mac_get_name(me), hash_len);
+				hash_len = vdata->size;
+			}
+
 			/* Only SHA-2 is allowed in FIPS 140-3 */
-			switch (me->id) {
+			switch (DIG_TO_MAC(sign_params->dsa_dig)) {
 			case GNUTLS_MAC_SHA256:
 			case GNUTLS_MAC_SHA384:
 			case GNUTLS_MAC_SHA512:
 			case GNUTLS_MAC_SHA224:
 				break;
 			default:
 				not_approved = true;
 			}
 
-			if (hash_len > vdata->size) {
-				gnutls_assert();
-				_gnutls_debug_log
-				    ("Security level of algorithm requires hash %s(%d) or better\n",
-				     _gnutls_mac_get_name(me), hash_len);
-				hash_len = vdata->size;
-			}
-
 			mpz_init(k);
 			if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
 			    (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
 				ret = _gnutls_ecdsa_compute_k(k,
 							      curve_id,
@@ -1543,11 +1543,10 @@ _wrap_nettle_pk_verify(gnutls_pk_algorit
 		{
 			struct ecc_point pub;
 			struct dsa_signature sig;
 			int curve_id = pk_params->curve;
 			const struct ecc_curve *curve;
-			const mac_entry_st *me;
 
 			curve = get_supported_nist_curve(curve_id);
 			if (curve == NULL) {
 				ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
 				goto cleanup;
@@ -1569,28 +1568,28 @@ _wrap_nettle_pk_verify(gnutls_pk_algorit
 			}
 
 			memcpy(sig.r, tmp[0], SIZEOF_MPZT);
 			memcpy(sig.s, tmp[1], SIZEOF_MPZT);
 
-			me = _gnutls_dsa_q_to_hash(pk_params, &hash_len);
+			(void)_gnutls_dsa_q_to_hash(pk_params, &hash_len);
+
+			if (hash_len > vdata->size)
+				hash_len = vdata->size;
 
 			/* SHA-1 is allowed for SigVer in FIPS 140-3 in legacy
 			 * mode */
-			switch (me->id) {
+			switch (DIG_TO_MAC(sign_params->dsa_dig)) {
 			case GNUTLS_MAC_SHA1:
 			case GNUTLS_MAC_SHA256:
 			case GNUTLS_MAC_SHA384:
 			case GNUTLS_MAC_SHA512:
 			case GNUTLS_MAC_SHA224:
 				break;
 			default:
 				not_approved = true;
 			}
 
-			if (hash_len > vdata->size)
-				hash_len = vdata->size;
-
 			ret =
 			    ecdsa_verify(&pub, hash_len, vdata->data,
 					 &sig);
 			if (ret == 0) {
 				gnutls_assert();
@@ -2388,12 +2387,14 @@ static int pct_test(gnutls_pk_algorithm_
 
 	memcpy(&spki, &params->spki, sizeof(spki));
 
 	if (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_EC) {
 		unsigned hash_len;
+		const mac_entry_st *me;
 
-		_gnutls_dsa_q_to_hash(params, &hash_len);
+		me = _gnutls_dsa_q_to_hash(params, &hash_len);
+		spki.dsa_dig = MAC_TO_DIG(me->id);
 		gen_data = gnutls_malloc(hash_len);
 		gnutls_rnd(GNUTLS_RND_NONCE, gen_data, hash_len);
 
 		ddata.data = (void*)gen_data;
 		ddata.size = hash_len;
--- a/lib/pubkey.c
+++ b/lib/pubkey.c
@@ -1983,11 +1983,11 @@ gnutls_pubkey_import_dsa_raw(gnutls_pubk
 /* Updates the gnutls_x509_spki_st parameters based on the signature
  * information, and reports any incompatibilities between the existing
  * parameters (if any) with the signature algorithm */
 static
 int fixup_spki_params(const gnutls_pk_params_st *key_params, const gnutls_sign_entry_st *se,
-		       const mac_entry_st *me, gnutls_x509_spki_st *params)
+		      const mac_entry_st *me, gnutls_x509_spki_st *params)
 {
 	unsigned bits;
 
 	if (se->pk != key_params->algo) {
 		if (!sign_supports_priv_pk_algorithm(se, key_params->algo)) {
@@ -2016,10 +2016,13 @@ int fixup_spki_params(const gnutls_pk_pa
 			params->salt_size = ret;
 		}
 
 		if (params->rsa_pss_dig != se->hash)
 			return gnutls_assert_val(GNUTLS_E_CONSTRAINT_ERROR);
+	} else if (params->pk == GNUTLS_PK_DSA ||
+		   params->pk == GNUTLS_PK_ECDSA) {
+		params->dsa_dig = se->hash;
 	}
 
 	return 0;
 }
 
--- a/tests/fips-test.c
+++ b/tests/fips-test.c
@@ -78,12 +78,26 @@ static const uint8_t rsa2342_sha1_sig_da
 static const gnutls_datum_t rsa2342_sha1_sig = {
 	.data = (unsigned char *)rsa2342_sha1_sig_data,
 	.size = sizeof(rsa2342_sha1_sig_data),
 };
 
+static const uint8_t ecc256_sha1_sig_data[] = {
+	0x30, 0x45, 0x02, 0x21, 0x00, 0x9a, 0x28, 0xc9, 0xbf, 0xc8, 0x70, 0x4f, 
+	0x27, 0x2d, 0xe1, 0x66, 0xc4, 0xa5, 0xc6, 0xf2, 0xdc, 0x33, 0xb9, 0x41, 
+	0xdf, 0x78, 0x98, 0x8a, 0x22, 0x4d, 0x29, 0x37, 0xa0, 0x0f, 0x6f, 0xd4, 
+	0xed, 0x02, 0x20, 0x0b, 0x15, 0xca, 0x30, 0x09, 0x2d, 0x55, 0x44, 0xb4, 
+	0x1d, 0x3f, 0x48, 0x7a, 0xc3, 0xd1, 0x2a, 0xc1, 0x0e, 0x47, 0xfa, 0xe6, 
+	0xe9, 0x0f, 0x03, 0xe2, 0x01, 0x4e, 0xe4, 0x73, 0x37, 0xa7, 0x90, 
+};
+
+static const gnutls_datum_t ecc256_sha1_sig = {
+	.data = (unsigned char *)ecc256_sha1_sig_data,
+	.size = sizeof(ecc256_sha1_sig_data),
+};
+
 static void
-rsa_import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
+import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
 		   const char *filename)
 {
 	const char *srcdir;
 	char path[256];
 	gnutls_datum_t tmp;
@@ -422,11 +436,11 @@ void doit(void)
 	gnutls_x509_privkey_deinit(xprivkey);
 	FIPS_POP_CONTEXT(ERROR);
 
 	/* Import 2432-bit RSA key; not a security function */
 	FIPS_PUSH_CONTEXT();
-	rsa_import_keypair(&privkey, &pubkey, "rsa-2432.pem");
+	import_keypair(&privkey, &pubkey, "rsa-2432.pem");
 	FIPS_POP_CONTEXT(INITIAL);
 
 	/* Create a signature with 2432-bit RSA and SHA256; approved */
 	FIPS_PUSH_CONTEXT();
 	ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
@@ -468,11 +482,11 @@ void doit(void)
 	gnutls_pubkey_deinit(pubkey);
 	gnutls_privkey_deinit(privkey);
 
 	/* Import 512-bit RSA key; not a security function */
 	FIPS_PUSH_CONTEXT();
-	rsa_import_keypair(&privkey, &pubkey, "rsa-512.pem");
+	import_keypair(&privkey, &pubkey, "rsa-512.pem");
 	FIPS_POP_CONTEXT(INITIAL);
 
 	/* Create a signature with 512-bit RSA and SHA256; not approved */
 	FIPS_PUSH_CONTEXT();
 	ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
@@ -491,10 +505,76 @@ void doit(void)
 	}
 	FIPS_POP_CONTEXT(NOT_APPROVED);
 	gnutls_free(signature.data);
 	gnutls_pubkey_deinit(pubkey);
 	gnutls_privkey_deinit(privkey);
+
+	/* Import ECDSA key; not a security function */
+	FIPS_PUSH_CONTEXT();
+	import_keypair(&privkey, &pubkey, "ecc256.pem");
+	FIPS_POP_CONTEXT(INITIAL);
+
+	/* Create a signature with ECDSA and SHA256; approved */
+	FIPS_PUSH_CONTEXT();
+	ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
+					&data, &signature);
+	if (ret < 0) {
+		fail("gnutls_privkey_sign_data2 failed\n");
+	}
+	FIPS_POP_CONTEXT(APPROVED);
+
+	/* Verify a signature with ECDSA and SHA256; approved */
+	FIPS_PUSH_CONTEXT();
+	ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
+					 &data, &signature);
+	if (ret < 0) {
+		fail("gnutls_pubkey_verify_data2 failed\n");
+	}
+	FIPS_POP_CONTEXT(APPROVED);
+	gnutls_free(signature.data);
+
+	/* Create a signature with ECDSA and SHA256 (old API); approved */
+	FIPS_PUSH_CONTEXT();
+	ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
+				       &data, &signature);
+	if (ret < 0) {
+		fail("gnutls_privkey_sign_data failed\n");
+	}
+	FIPS_POP_CONTEXT(APPROVED);
+	gnutls_free(signature.data);
+
+	/* Create a signature with ECDSA and SHA-1; not approved */
+	FIPS_PUSH_CONTEXT();
+	ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0,
+					&data, &signature);
+	if (ret < 0) {
+		fail("gnutls_privkey_sign_data2 failed\n");
+	}
+	FIPS_POP_CONTEXT(NOT_APPROVED);
+
+	/* Verify a signature created with ECDSA and SHA-1; approved */
+	FIPS_PUSH_CONTEXT();
+	ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA1,
+					 GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1, &data,
+					 &ecc256_sha1_sig);
+	if (ret < 0) {
+		fail("gnutls_pubkey_verify_data2 failed\n");
+	}
+	FIPS_POP_CONTEXT(APPROVED);
+	gnutls_free(signature.data);
+
+	/* Create a signature with ECDSA and SHA-1 (old API); not approved */
+	FIPS_PUSH_CONTEXT();
+	ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0,
+					&data, &signature);
+	if (ret < 0) {
+		fail("gnutls_privkey_sign_data failed\n");
+	}
+	FIPS_POP_CONTEXT(NOT_APPROVED);
+	gnutls_free(signature.data);
+	gnutls_pubkey_deinit(pubkey);
+	gnutls_privkey_deinit(privkey);
 
         /* Test RND functions */
 	FIPS_PUSH_CONTEXT();
 	ret = gnutls_rnd(GNUTLS_RND_RANDOM, key16, sizeof(key16));
 	if (ret < 0) {