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
|
From 02faaf6f8b490fee465d07e020473386425ffdd2 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Thu, 29 Sep 2022 17:13:00 +0900
Subject: [PATCH 09/29] fips: mark composite signature API not-approved
This makes the FIPS service indicator to transit to not-approved when
gnutls_privkey_sign_hash* is used. In FIPS, single-shot
API (gnutls_privkey_sign_data*) is preferred over composite API.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/privkey.c | 42 ++++++++++++++++++++++---------
tests/fips-test.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 94 insertions(+), 12 deletions(-)
--- a/lib/privkey.c
+++ b/lib/privkey.c
@@ -1249,31 +1249,40 @@ gnutls_privkey_sign_hash2(gnutls_privkey
/* the corresponding signature algorithm is SIGN_RSA_RAW,
* irrespective of hash algorithm. */
se = _gnutls_sign_to_entry(GNUTLS_SIGN_RSA_RAW);
} else {
se = _gnutls_sign_to_entry(algo);
- if (unlikely(se == NULL))
- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
-
+ if (unlikely(se == NULL)) {
+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ goto cleanup;
+ }
}
ret = _gnutls_privkey_get_spki_params(signer, ¶ms);
if (ret < 0) {
gnutls_assert();
- return ret;
+ goto cleanup;
}
ret = _gnutls_privkey_update_spki_params(signer, se->pk, se->hash,
flags, ¶ms);
if (ret < 0) {
gnutls_assert();
- return ret;
+ goto cleanup;
}
FIX_SIGN_PARAMS(params, flags, se->hash);
- return privkey_sign_prehashed(signer, se, hash_data, signature, ¶ms);
+ ret = privkey_sign_prehashed(signer, se, hash_data, signature, ¶ms);
+
+ cleanup:
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ }
+ return ret;
}
int
privkey_sign_and_hash_data(gnutls_privkey_t signer,
const gnutls_sign_entry_st *se,
@@ -1364,18 +1373,18 @@ gnutls_privkey_sign_hash(gnutls_privkey_
const gnutls_sign_entry_st *se;
ret = _gnutls_privkey_get_spki_params(signer, ¶ms);
if (ret < 0) {
gnutls_assert();
- return ret;
+ goto cleanup;
}
ret = _gnutls_privkey_update_spki_params(signer, signer->pk_algorithm,
hash_algo, flags, ¶ms);
if (ret < 0) {
gnutls_assert();
- return ret;
+ goto cleanup;
}
/* legacy callers of this API could use a hash algorithm of 0 (unknown)
* to indicate raw hashing. As we now always want to know the signing
* algorithm involved, we try discovering the hash algorithm. */
@@ -1389,17 +1398,26 @@ gnutls_privkey_sign_hash(gnutls_privkey_
se = _gnutls_sign_to_entry(GNUTLS_SIGN_RSA_RAW);
} else {
se = _gnutls_pk_to_sign_entry(params.pk, hash_algo);
}
- if (unlikely(se == NULL))
- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ if (unlikely(se == NULL)) {
+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ goto cleanup;
+ }
FIX_SIGN_PARAMS(params, flags, hash_algo);
- return privkey_sign_prehashed(signer, se,
- hash_data, signature, ¶ms);
+ ret = privkey_sign_prehashed(signer, se,
+ hash_data, signature, ¶ms);
+ cleanup:
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ }
+ return ret;
}
static int
privkey_sign_prehashed(gnutls_privkey_t signer,
const gnutls_sign_entry_st *se,
--- a/tests/fips-test.c
+++ b/tests/fips-test.c
@@ -286,10 +286,12 @@ void doit(void)
gnutls_datum_t key = { key16, sizeof(key16) };
gnutls_datum_t iv = { iv16, sizeof(iv16) };
gnutls_datum_t signature;
unsigned int bits;
uint8_t hmac[64];
+ uint8_t hash[64];
+ gnutls_datum_t hashed_data;
fprintf(stderr,
"Please note that if in FIPS140 mode, you need to assure the library's integrity prior to running this test\n");
gnutls_global_set_log_function(tls_log_func);
@@ -538,10 +540,40 @@ void doit(void)
&data, &signature);
if (ret < 0) {
fail("gnutls_privkey_sign_data failed\n");
}
FIPS_POP_CONTEXT(APPROVED);
+
+ /* Create a SHA256 hashed data for 2-pass signature API; not a
+ * crypto operation */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, data.data, data.size, hash);
+ if (ret < 0) {
+ fail("gnutls_hash_fast failed\n");
+ }
+ hashed_data.data = hash;
+ hashed_data.size = 32;
+ FIPS_POP_CONTEXT(INITIAL);
+
+ /* Create a signature with ECDSA and SHA256 (2-pass API); not-approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_hash2(privkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
+ &hashed_data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_hash2 failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a signature with ECDSA and SHA256 (2-pass old API); not-approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA256, 0,
+ &hashed_data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_hash failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_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,
@@ -569,10 +601,42 @@ void doit(void)
if (ret < 0) {
fail("gnutls_privkey_sign_data failed\n");
}
FIPS_POP_CONTEXT(NOT_APPROVED);
gnutls_free(signature.data);
+
+ /* Create a SHA1 hashed data for 2-pass signature API; not a
+ * crypto operation */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, data.data, data.size, hash);
+ if (ret < 0) {
+ fail("gnutls_hash_fast failed\n");
+ }
+ hashed_data.data = hash;
+ hashed_data.size = 20;
+ FIPS_POP_CONTEXT(INITIAL);
+
+ /* Create a signature with ECDSA and SHA1 (2-pass API); not-approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_hash2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0,
+ &hashed_data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_hash2 failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a signature with ECDSA and SHA1 (2-pass old API); not-approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA1, 0,
+ &hashed_data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_hash 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();
|