]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
fips: plumb service indicator to public key crypto operations
authorDaiki Ueno <ueno@gnu.org>
Tue, 31 Aug 2021 11:29:45 +0000 (13:29 +0200)
committerDaiki Ueno <ueno@gnu.org>
Sat, 8 Jan 2022 07:54:20 +0000 (08:54 +0100)
This installs service indicator state transitions in certain public
key operations in gnutls_crypto_pk_st, namely:

* fallible operations
  - encrypt
  - sign
  - generate_keys
  - derive

* infallible operations
  - decrypt, decrypt2
  - verify

other operations, such as generate_params, are not considered as
crypto operation.  Note that fallible operations above mean that those
return value could indicate error, while infallible operations do not
have distinction between errors and failures: decrypt/verify failures
are treated as a successful completion of the operation.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
Co-authored-by: Pedro Monreal <pmonrealgonzalez@suse.de>
lib/nettle/pk.c
lib/pk.c
lib/pubkey.c
tests/dh-compute.c
tests/fips-test.c
tests/privkey-keygen.c

index 6af19c459f9bc70aecb5318d180e2bf72d4e321a..a14656826658045329aa3f6c6ba6dec64c6d4267 100644 (file)
@@ -293,6 +293,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
                                  unsigned int flags)
 {
        int ret;
+       bool not_approved = false;
 
        switch (algo) {
        case GNUTLS_PK_DH: {
@@ -300,8 +301,10 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
                bigint_t k = NULL, primesub1 = NULL, r = NULL;
                unsigned int bits;
 
-               if (nonce != NULL)
-                       return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+               if (nonce != NULL) {
+                       ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       goto cleanup;
+               }
 
                f = pub->params[DH_Y];
                x = priv->params[DH_X];
@@ -309,8 +312,10 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
                prime = priv->params[DH_P];
 
                ret = _gnutls_mpi_init_multi(&k, &primesub1, &r, NULL);
-               if (ret < 0)
-                       return gnutls_assert_val(ret);
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto cleanup;
+               }
 
                ret = _gnutls_mpi_sub_ui(primesub1, prime, 1);
                if (ret < 0) {
@@ -343,7 +348,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
                } else if ((flags & PK_DERIVE_TLS13) &&
                           _gnutls_fips_mode_enabled()) {
                        /* Mandatory in FIPS mode for TLS 1.3 */
-                       ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+                       ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
                        goto dh_cleanup;
                }
 
@@ -355,6 +360,9 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
                        goto dh_cleanup;
                }
 
+               if (bits < 2048) {
+                       not_approved = true;
+               }
 
                ret = _gnutls_mpi_powm(k, f, x, prime);
                if (ret < 0) {
@@ -366,8 +374,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo,
                if ((_gnutls_mpi_cmp_ui(k, 1) == 0)
                    || (_gnutls_mpi_cmp_ui(k, 0) == 0)
                    || (_gnutls_mpi_cmp(k, primesub1) == 0)) {
-                       gnutls_assert();
-                       ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+                       ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
                        goto dh_cleanup;
                }
 
@@ -402,24 +409,34 @@ dh_cleanup:
 
                        out->data = NULL;
 
-                       if (nonce != NULL)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       if (nonce != NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        curve = get_supported_nist_curve(priv->curve);
-                       if (curve == NULL)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       if (curve == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
+
+                       /* P-192 is not supported in FIPS 140-3 */
+                       if (priv->curve == GNUTLS_ECC_CURVE_SECP192R1) {
+                               not_approved = true;
+                       }
 
                        ret = _ecc_params_to_pubkey(pub, &ecc_pub, curve);
-                       if (ret < 0)
-                               return gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
                        ret =
                            _ecc_params_to_privkey(priv, &ecc_priv, curve);
                        if (ret < 0) {
                                ecc_point_clear(&ecc_pub);
-                               return gnutls_assert_val(ret);
+                               gnutls_assert();
+                               goto cleanup;
                        }
 
                        out->size = gnutls_ecc_curve_get_size(priv->curve);
@@ -449,13 +466,20 @@ dh_cleanup:
                {
                        unsigned size = gnutls_ecc_curve_get_size(priv->curve);
 
-                       if (nonce != NULL)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       /* Edwards curves are not approved */
+                       not_approved = true;
+
+                       if (nonce != NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        /* The point is in pub, while the private part (scalar) in priv. */
 
-                       if (size == 0 || priv->raw_priv.size != size)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       if (size == 0 || priv->raw_priv.size != size) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        out->data = gnutls_malloc(size);
                        if (out->data == NULL) {
@@ -486,25 +510,35 @@ dh_cleanup:
                struct ecc_point ecc_pub;
                const struct ecc_curve *curve;
 
+               /* GOST curves are not approved */
+               not_approved = true;
+
                out->data = NULL;
 
                curve = get_supported_gost_curve(priv->curve);
-               if (curve == NULL)
-                       return
-                           gnutls_assert_val
-                           (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+               if (curve == NULL) {
+                       gnutls_assert();
+                       ret = GNUTLS_E_ECC_UNSUPPORTED_CURVE;
+                       goto cleanup;
+               }
 
-               if (nonce == NULL)
-                       return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+               if (nonce == NULL) {
+                       gnutls_assert();
+                       ret = GNUTLS_E_INVALID_REQUEST;
+                       goto cleanup;
+               }
 
                ret = _gost_params_to_pubkey(pub, &ecc_pub, curve);
-               if (ret < 0)
-                       return gnutls_assert_val(ret);
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto cleanup;
+               }
 
                ret = _gost_params_to_privkey(priv, &ecc_priv, curve);
                if (ret < 0) {
                        ecc_point_clear(&ecc_pub);
-                       return gnutls_assert_val(ret);
+                       gnutls_assert();
+                       goto cleanup;
                }
 
                out->size = 2 * gnutls_ecc_curve_get_size(priv->curve);
@@ -535,6 +569,13 @@ dh_cleanup:
        ret = 0;
 
       cleanup:
+       if (ret < 0) {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+       } else if (not_approved) {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+       } else {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+       }
 
        return ret;
 }
@@ -598,6 +639,12 @@ _wrap_nettle_pk_encrypt(gnutls_pk_algorithm_t algo,
        ret = 0;
 
       cleanup:
+       if (ret < 0) {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+       } else {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+       }
+
        mpz_clear(p);
 
        FAIL_IF_LIB_ERROR;
@@ -628,14 +675,15 @@ _wrap_nettle_pk_decrypt(gnutls_pk_algorithm_t algo,
 
                        _rsa_params_to_privkey(pk_params, &priv);
                        ret = _rsa_params_to_pubkey(pk_params, &pub);
-                       if (ret < 0)
-                               return
-                                   gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
-                       if (ciphertext->size != pub.size)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_DECRYPTION_FAILED);
+                       if (ciphertext->size != pub.size) {
+                               ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
+                               goto cleanup;
+                       }
 
                        if (_gnutls_mpi_init_scan_nz
                            (&c, ciphertext->data,
@@ -684,8 +732,12 @@ _wrap_nettle_pk_decrypt(gnutls_pk_algorithm_t algo,
        ret = 0;
 
       cleanup:
-       if (ret < 0)
+       if (ret < 0) {
                gnutls_free(plaintext->data);
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+       } else {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+       }
 
        FAIL_IF_LIB_ERROR;
        return ret;
@@ -711,21 +763,26 @@ _wrap_nettle_pk_decrypt2(gnutls_pk_algorithm_t algo,
        FAIL_IF_LIB_ERROR;
 
        if (algo != GNUTLS_PK_RSA || plaintext == NULL) {
-               gnutls_assert();
-               return GNUTLS_E_INTERNAL_ERROR;
+               ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+               goto fail;
        }
 
        _rsa_params_to_privkey(pk_params, &priv);
        ret = _rsa_params_to_pubkey(pk_params, &pub);
-       if (ret < 0)
-               return gnutls_assert_val(ret);
+       if (ret < 0) {
+               gnutls_assert();
+               goto fail;
+       }
 
-       if (ciphertext->size != pub.size)
-               return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
+       if (ciphertext->size != pub.size) {
+               ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
+               goto fail;
+       }
 
        if (_gnutls_mpi_init_scan_nz(&c, ciphertext->data,
                                     ciphertext->size) != 0) {
-               return gnutls_assert_val (GNUTLS_E_MPI_SCAN_FAILED);
+               ret = gnutls_assert_val(GNUTLS_E_MPI_SCAN_FAILED);
+               goto fail;
        }
 
        if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST)
@@ -734,6 +791,13 @@ _wrap_nettle_pk_decrypt2(gnutls_pk_algorithm_t algo,
                random_func = rnd_nonce_func;
        ret = rsa_sec_decrypt(&pub, &priv, NULL, random_func,
                             plaintext_size, plaintext, TOMPZ(c));
+
+       /* The decrypt operation is infallible; treat the approved
+        * operation as complete at this point, regardless of any
+        * decryption failure detected below.
+        */
+       _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+
        /* after this point, any conditional on failure that cause differences
         * in execution may create a timing or cache access pattern side
         * channel that can be used as an oracle, so thread very carefully */
@@ -747,6 +811,11 @@ _wrap_nettle_pk_decrypt2(gnutls_pk_algorithm_t algo,
        is_err |= CONSTCHECK_EQUAL(ret, 0);
        /* then return GNUTLS_E_DECRYPTION_FAILED */
        return (int)((is_err * UINT_MAX) & GNUTLS_E_DECRYPTION_FAILED);
+
+ fail:
+       _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+
+       return ret;
 }
 
 #define CHECK_INVALID_RSA_PSS_PARAMS(dig_size, salt_size, pub_size, err) \
@@ -881,22 +950,25 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
        int ret;
        unsigned int hash_len;
        const mac_entry_st *me;
+       bool not_approved = false;
 
        FAIL_IF_LIB_ERROR;
 
-       if (IS_EC(algo)) {
-               /* check if the curve relates to the algorithm used */
-               if (gnutls_ecc_curve_get_pk(pk_params->curve) != algo)
-                       return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+       /* check if the curve relates to the algorithm used */
+       if (IS_EC(algo) && gnutls_ecc_curve_get_pk(pk_params->curve) != algo) {
+               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+               goto cleanup;
        }
 
        /* deterministic ECDSA/DSA is prohibited under FIPS except in
         * the selftests */
-       if (_gnutls_fips_mode_enabled() &&
-           _gnutls_get_lib_state() != LIB_STATE_SELFTEST &&
-           (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_ECDSA) &&
-           (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE))
-               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+       if ((algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_ECDSA) &&
+           (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE) &&
+           _gnutls_fips_mode_enabled() &&
+           _gnutls_get_lib_state() != LIB_STATE_SELFTEST) {
+               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+               goto cleanup;
+       }
 
        switch (algo) {
        case GNUTLS_PK_EDDSA_ED25519:   /* we do EdDSA */
@@ -904,12 +976,19 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                {
                        const gnutls_ecc_curve_entry_st *e;
 
-                       if (unlikely(get_eddsa_curve(algo) != pk_params->curve))
-                               return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       /* EdDSA is not approved yet */
+                       not_approved = true;
+
+                       if (unlikely(get_eddsa_curve(algo) != pk_params->curve)) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
 
                        e = _gnutls_ecc_curve_get_params(pk_params->curve);
-                       if (e == NULL)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       if (e == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        signature->data = gnutls_malloc(e->sig_size);
                        if (signature->data == NULL) {
@@ -943,28 +1022,33 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                        struct dsa_signature sig;
                        const struct ecc_curve *curve;
 
+                       /* GOSTDSA is not approved */
+                       not_approved = true;
+
                        curve = get_supported_gost_curve(pk_params->curve);
-                       if (curve == NULL)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       if (curve == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
 
                        ret =
                            _ecc_params_to_privkey(pk_params, &priv,
                                                   curve);
-                       if (ret < 0)
-                               return gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
                        /* This call will return a valid MAC entry and
                         * getters will check that is not null anyway. */
                        me = hash_to_entry(_gnutls_gost_digest(pk_params->algo));
                        if (_gnutls_mac_get_algo_len(me) != vdata->size) {
-                               gnutls_assert();
                                _gnutls_debug_log
                                    ("Security level of algorithm requires hash %s(%zd)\n",
                                     _gnutls_mac_get_name(me),
                                     _gnutls_mac_get_algo_len(me));
-                               return GNUTLS_E_INVALID_REQUEST;
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
                        }
 
                        dsa_signature_init(&sig);
@@ -997,22 +1081,40 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                        nettle_random_func *random_func;
 
                        curve = get_supported_nist_curve(curve_id);
-                       if (curve == NULL)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       if (curve == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
+
+                       /* P-192 is not supported in FIPS 140-3 */
+                       if (curve_id == GNUTLS_ECC_CURVE_SECP192R1) {
+                               not_approved = true;
+                       }
 
                        ret =
                            _ecc_params_to_privkey(pk_params, &priv,
                                                   curve);
-                       if (ret < 0)
-                               return gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
                        dsa_signature_init(&sig);
 
                        me = _gnutls_dsa_q_to_hash(pk_params,
                                                   &hash_len);
 
+                       /* Only SHA-2 is allowed in FIPS 140-3 */
+                       switch (me->id) {
+                       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
@@ -1071,6 +1173,10 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                        void *random_ctx;
                        nettle_random_func *random_func;
 
+                       /* DSA is currently being defined as sunset with the
+                        * current draft of FIPS 186-5 */
+                       not_approved = true;
+
                        memset(&priv, 0, sizeof(priv));
                        memset(&pub, 0, sizeof(pub));
                        _dsa_params_get(pk_params, &pub);
@@ -1140,10 +1246,20 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                        mpz_t s;
 
                        _rsa_params_to_privkey(pk_params, &priv);
+
+                       /* RSA key size should be 2048-bit or larger in FIPS
+                        * 140-3.  In addition to this, only SHA-2 is allowed
+                        * for SigGen; it is checked in pk_prepare_hash lib/pk.c
+                        */
+                       if (unlikely(priv.size < 256)) {
+                               not_approved = true;
+                       }
+
                        ret = _rsa_params_to_pubkey(pk_params, &pub);
-                       if (ret < 0)
-                               return
-                                   gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
                        mpz_init(s);
 
@@ -1181,10 +1297,22 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                        mpz_t s;
 
                        _rsa_params_to_privkey(pk_params, &priv);
+
+                       /* RSA key size should be 2048-bit or larger in FIPS
+                        * 140-3.  In addition to this, only SHA-2 is allowed
+                        * for SigGen; however, Nettle only support SHA256,
+                        * SHA384, and SHA512 for RSA-PSS (see
+                        * _rsa_pss_sign_digest_tr in this file for details).
+                        */
+                       if (unlikely(priv.size < 256)) {
+                               not_approved = true;
+                       }
+
                        ret = _rsa_params_to_pubkey(pk_params, &pub);
-                       if (ret < 0)
-                               return
-                                   gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
                        mpz_init(s);
 
@@ -1223,6 +1351,13 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
        ret = 0;
 
       cleanup:
+       if (ret < 0) {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+       } else if (not_approved) {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+       } else {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+       }
 
        FAIL_IF_LIB_ERROR;
        return ret;
@@ -1302,13 +1437,14 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
        int ret;
        unsigned int hash_len;
        bigint_t tmp[2] = { NULL, NULL };
+       bool not_approved = false;
 
        FAIL_IF_LIB_ERROR;
 
-       if (IS_EC(algo)) {
-               /* check if the curve relates to the algorithm used */
-               if (gnutls_ecc_curve_get_pk(pk_params->curve) != algo)
-                       return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+       /* check if the curve relates to the algorithm used */
+       if (IS_EC(algo) && gnutls_ecc_curve_get_pk(pk_params->curve) != algo) {
+               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+               goto cleanup;
        }
 
        switch (algo) {
@@ -1317,18 +1453,29 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                {
                        const gnutls_ecc_curve_entry_st *e;
 
-                       if (unlikely(get_eddsa_curve(algo) != pk_params->curve))
-                               return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       /* EdDSA is not approved yet */
+                       not_approved = true;
+
+                       if (unlikely(get_eddsa_curve(algo) != pk_params->curve)) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
 
                        e = _gnutls_ecc_curve_get_params(pk_params->curve);
-                       if (e == NULL)
-                               return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       if (e == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
 
-                       if (signature->size != e->sig_size)
-                               return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                       if (signature->size != e->sig_size) {
+                               ret = gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                               goto cleanup;
+                       }
 
-                       if (pk_params->raw_pub.size != e->size)
-                               return gnutls_assert_val(GNUTLS_E_PK_SIGN_FAILED);
+                       if (pk_params->raw_pub.size != e->size) {
+                               ret = gnutls_assert_val(GNUTLS_E_PK_SIGN_FAILED);
+                               goto cleanup;
+                       }
 
                        ret = eddsa_verify(algo,
                                           pk_params->raw_pub.data,
@@ -1346,23 +1493,30 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                        const struct ecc_curve *curve;
                        const mac_entry_st *me;
 
+                       /* GOSTDSA is not approved */
+                       not_approved = true;
+
                        curve = get_supported_gost_curve(pk_params->curve);
-                       if (curve == NULL)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       if (curve == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
 
                        /* This call will return a valid MAC entry and
                         * getters will check that is not null anyway. */
                        me = hash_to_entry(_gnutls_gost_digest(pk_params->algo));
-                       if (_gnutls_mac_get_algo_len(me) != vdata->size)
-                               return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                       if (_gnutls_mac_get_algo_len(me) != vdata->size) {
+                               ret = gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                               goto cleanup;
+                       }
 
                        ret =
                            _gnutls_decode_gost_rs(signature, &tmp[0],
                                                  &tmp[1]);
-                       if (ret < 0)
-                               return gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
                        ret =
                            _gost_params_to_pubkey(pk_params, &pub, curve);
@@ -1391,18 +1545,21 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                        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)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       if (curve == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
 
                        ret =
                            _gnutls_decode_ber_rs(signature, &tmp[0],
                                                  &tmp[1]);
-                       if (ret < 0)
-                               return gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
                        ret =
                            _ecc_params_to_pubkey(pk_params, &pub, curve);
@@ -1414,7 +1571,20 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                        memcpy(sig.r, tmp[0], SIZEOF_MPZT);
                        memcpy(sig.s, tmp[1], SIZEOF_MPZT);
 
-                       _gnutls_dsa_q_to_hash(pk_params, &hash_len);
+                       me = _gnutls_dsa_q_to_hash(pk_params, &hash_len);
+
+                       /* SHA-1 is allowed for SigVer in FIPS 140-3 in legacy
+                        * mode */
+                       switch (me->id) {
+                       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;
@@ -1437,6 +1607,10 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                        struct dsa_signature sig;
                        bigint_t y;
 
+                       /* DSA is currently being defined as sunset with the
+                        * current draft of FIPS 186-5 */
+                       not_approved = true;
+
                        ret =
                            _gnutls_decode_ber_rs(signature, &tmp[0],
                                                  &tmp[1]);
@@ -1471,14 +1645,24 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                        struct rsa_public_key pub;
 
                        ret = _rsa_params_to_pubkey(pk_params, &pub);
-                       if (ret < 0)
-                               return
-                                   gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
-                       if (signature->size != pub.size)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                       /* RSA key size should be 2048-bit or larger in FIPS
+                        * 140-3.  In addition to this, only SHA-1 and SHA-2 are
+                        * allowed for SigVer; it is checked in
+                        * _pkcs1_rsa_verify_sig in lib/pubkey.c
+                        */
+                       if (unlikely(pub.size < 256)) {
+                               not_approved = true;
+                       }
+
+                       if (signature->size != pub.size) {
+                               ret = gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                               goto cleanup;
+                       }
 
                        ret =
                            _gnutls_mpi_init_scan_nz(&tmp[0], signature->data,
@@ -1507,19 +1691,30 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                        if ((sign_params->flags &
                             GNUTLS_PK_FLAG_RSA_PSS_FIXED_SALT_LENGTH) &&
                            sign_params->salt_size != vdata->size) {
-                               return gnutls_assert_val
-                                       (GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                               ret = gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                               goto cleanup;
                        }
 
                        ret = _rsa_params_to_pubkey(pk_params, &pub);
-                       if (ret < 0)
-                               return
-                                   gnutls_assert_val(ret);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
 
-                       if (signature->size != pub.size)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                       /* RSA key size should be 2048-bit or larger in FIPS
+                        * 140-3.  In addition to this, only SHA-1 and SHA-2 are
+                        * allowed for SigVer, while Nettle only supports
+                        * SHA256, SHA384, and SHA512 for RSA-PSS (see
+                        * _rsa_pss_verify_digest in this file for the details).
+                        */
+                       if (unlikely(pub.size < 256)) {
+                               not_approved = true;
+                       }
+
+                       if (signature->size != pub.size) {
+                               ret = gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+                               goto cleanup;
+                       }
 
                        ret =
                            _gnutls_mpi_init_scan_nz(&tmp[0], signature->data,
@@ -1550,6 +1745,13 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
        }
 
       cleanup:
+       if (ret < 0) {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+       } else if (not_approved) {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+       } else {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+       }
 
        _gnutls_mpi_release(&tmp[0]);
        _gnutls_mpi_release(&tmp[1]);
@@ -2081,15 +2283,16 @@ int _gnutls_ecdh_compute_key(gnutls_ecc_curve_t curve,
 
 static int pct_test(gnutls_pk_algorithm_t algo, const gnutls_pk_params_st* params)
 {
-int ret;
-gnutls_datum_t sig = {NULL, 0};
-const char const_data[20] = "onetwothreefourfive";
-const char const_data_sha256[32] = "onetwothreefourfivesixseveneight";
-const char const_data_sha384[48] = "onetwothreefourfivesixseveneightnineteneleventwe";
-const char const_data_sha512[64] = "onetwothreefourfivesixseveneightnineteneleventwelvethirteenfourt";
-gnutls_datum_t ddata, tmp = {NULL,0};
-char* gen_data = NULL;
-gnutls_x509_spki_st spki;
+       int ret;
+       gnutls_datum_t sig = {NULL, 0};
+       const char const_data[20] = "onetwothreefourfive";
+       const char const_data_sha256[32] = "onetwothreefourfivesixseveneight";
+       const char const_data_sha384[48] = "onetwothreefourfivesixseveneightnineteneleventwe";
+       const char const_data_sha512[64] = "onetwothreefourfivesixseveneightnineteneleventwelvethirteenfourt";
+       gnutls_datum_t ddata, tmp = {NULL,0};
+       char* gen_data = NULL;
+       gnutls_x509_spki_st spki;
+       gnutls_fips140_context_t context;
 
        memcpy(&spki, &params->spki, sizeof(spki));
 
@@ -2136,28 +2339,44 @@ gnutls_x509_spki_st spki;
 
        switch (algo) {
        case GNUTLS_PK_RSA:
-               ret = _gnutls_pk_encrypt(algo, &sig, &ddata, params);
-               if (ret < 0) {
+               /* Push a temporary FIPS context because _gnutls_pk_encrypt and
+                * _gnutls_pk_decrypt below will mark RSAES-PKCS1-v1_5 operation
+                * non-approved */
+               if (gnutls_fips140_context_init(&context) < 0) {
                        ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
                        goto cleanup;
                }
-
-               if (ddata.size == sig.size && memcmp(ddata.data, sig.data, sig.size) == 0) {
+               if (gnutls_fips140_push_context(context) < 0) {
                        ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
-                       gnutls_assert();
+                       gnutls_fips140_context_deinit(context);
                        goto cleanup;
                }
 
-               ret = _gnutls_pk_decrypt(algo, &tmp, &sig, params);
+               ret = _gnutls_pk_encrypt(algo, &sig, &ddata, params);
                if (ret < 0) {
                        ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
-                       gnutls_assert();
-                       goto cleanup;
+               }
+               if (ret == 0 &&
+                   ddata.size == sig.size &&
+                   memcmp(ddata.data, sig.data, sig.size) == 0) {
+                       ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
+               }
+               if (ret == 0 &&
+                   _gnutls_pk_decrypt(algo, &tmp, &sig, params) < 0) {
+                       ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
+               }
+               if (ret == 0 &&
+                   !(tmp.size == ddata.size &&
+                     memcmp(tmp.data, ddata.data, tmp.size) == 0)) {
+                       ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
                }
 
-               if (tmp.size != ddata.size || memcmp(tmp.data, ddata.data, tmp.size) != 0) {
+               if (unlikely(gnutls_fips140_pop_context() < 0)) {
                        ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
-                       gnutls_assert();
+               }
+               gnutls_fips140_context_deinit(context);
+
+               if (ret < 0) {
                        goto cleanup;
                }
 
@@ -2300,13 +2519,14 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
        unsigned int i;
        unsigned rnd_level;
        nettle_random_func *rnd_func;
+       bool not_approved = false;
 
        FAIL_IF_LIB_ERROR;
 
-       if (IS_EC(algo)) {
-               /* check if the curve relates to the algorithm used */
-               if (gnutls_ecc_curve_get_pk(level) != algo)
-                       return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+       /* check if the curve relates to the algorithm used */
+       if (IS_EC(algo) && gnutls_ecc_curve_get_pk(level) != algo) {
+               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+               goto cleanup;
        }
 
        if (ephemeral) {
@@ -2324,8 +2544,14 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                        struct dsa_params pub;
                        mpz_t x, y;
 
-                       if (params->params[DSA_Q] == NULL)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       /* DSA is currently being defined as sunset with the
+                        * current draft of FIPS 186-5 */
+                       not_approved = true;
+
+                       if (params->params[DSA_Q] == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        _dsa_params_get(params, &pub);
 
@@ -2357,7 +2583,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                        mpz_clear(y);
 
                        if (ret < 0)
-                               goto fail;
+                               goto cleanup;
 
                        break;
                }
@@ -2374,8 +2600,10 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                        mpz_t primesub1;
                        mpz_t ypowq;
 
-                       if (algo != params->algo)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       if (algo != params->algo) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        _dsa_params_get(params, &pub);
 
@@ -2383,8 +2611,10 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                                have_q = 1;
 
                        /* This check is for the case !ENABLE_FIPS140 */
-                       if (algo == GNUTLS_PK_DSA && have_q == 0)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       if (algo == GNUTLS_PK_DSA && have_q == 0) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        mpz_init(r);
                        mpz_init(x);
@@ -2480,7 +2710,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                        mpz_clear(ypowq);
 
                        if (ret < 0)
-                               goto fail;
+                               goto cleanup;
 
                        break;
                }
@@ -2526,6 +2756,8 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                                        } while (ret != 1 && ++retries < 3);
                                }
                        } else {
+                               not_approved = true;
+
                                ret =
                                    rsa_generate_keypair(&pub, &priv, NULL,
                                                 rnd_func, NULL, NULL,
@@ -2547,6 +2779,10 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                                params->params_nr++;
                        }
 
+                       /* In FIPS 140-3, pub.n should be 2048-bit or larger; it
+                        * is assured in rsa_generate_fips186_4_keypair in
+                        * lib/nettle/int/rsa-keygen-fips186.c. */
+
                        mpz_set(TOMPZ(params->params[RSA_MODULUS]), pub.n);
                        mpz_set(TOMPZ(params->params[RSA_PUB]), pub.e);
                        mpz_set(TOMPZ(params->params[RSA_PRIV]), priv.d);
@@ -2563,7 +2799,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                        rsa_public_key_clear(&pub);
 
                        if (ret < 0)
-                               goto fail;
+                               goto cleanup;
 
                        break;
                }
@@ -2572,31 +2808,42 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                {
                        unsigned size = gnutls_ecc_curve_get_size(level);
 
-                       if (params->pkflags & GNUTLS_PK_FLAG_PROVABLE)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       /* EdDSA is not approved yet */
+                       not_approved = true;
+
+                       if (params->pkflags & GNUTLS_PK_FLAG_PROVABLE) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
-                       if (unlikely(get_eddsa_curve(algo) != level))
-                               return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       if (unlikely(get_eddsa_curve(algo) != level)) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
 
-                       if (size == 0)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       if (size == 0) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        params->curve = level;
 
                        params->raw_priv.data = gnutls_malloc(size);
-                       if (params->raw_priv.data == NULL)
-                               return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+                       if (params->raw_priv.data == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+                               goto cleanup;
+                       }
 
                        params->raw_pub.data = gnutls_malloc(size);
                        if (params->raw_pub.data == NULL) {
                                ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
-                               goto fail;
+                               goto cleanup;
                        }
 
                        ret = gnutls_rnd(rnd_level, params->raw_priv.data, size);
                        if (ret < 0) {
                                ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
-                               goto fail;
+                               goto cleanup;
                        }
                        params->raw_pub.size = size;
                        params->raw_priv.size = size;
@@ -2605,7 +2852,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                                               params->raw_pub.data,
                                               params->raw_priv.data);
                        if (ret < 0)
-                               goto fail;
+                               goto cleanup;
 
                        break;
                }
@@ -2623,10 +2870,15 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                        mpz_t x, y, xx, yy, nn, mm;
 
                        curve = get_supported_nist_curve(level);
-                       if (curve == NULL)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       if (curve == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
+
+                       /* P-192 is not supported in FIPS 140-3 */
+                       if (level == GNUTLS_ECC_CURVE_SECP192R1) {
+                               not_approved = true;
+                       }
 
                        mpz_init(x);
                        mpz_init(y);
@@ -2734,6 +2986,8 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                                        ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
                                        goto ecc_fail;
                                }
+                       } else {
+                               not_approved = true;
                        }
 #endif
 
@@ -2758,7 +3012,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                        ecc_scalar_clear(&m);
 
                        if (ret < 0)
-                               goto fail;
+                               goto cleanup;
 
                        break;
                }
@@ -2775,15 +3029,20 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                        const struct ecc_curve *curve;
                        const mac_entry_st *me;
 
+                       /* GOST curves are not approved */
+                       not_approved = true;
+
                        curve = get_supported_gost_curve(level);
-                       if (curve == NULL)
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       if (curve == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               goto cleanup;
+                       }
 
                        me = hash_to_entry(_gnutls_gost_digest(algo));
-                       if (!me || me->output_size * 8 != ecc_bit_size(curve))
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       if (!me || me->output_size * 8 != ecc_bit_size(curve)) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        ecc_scalar_init(&key, curve);
                        ecc_point_init(&pub, curve);
@@ -2816,7 +3075,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                        ecc_scalar_clear(&key);
 
                        if (ret < 0)
-                               goto fail;
+                               goto cleanup;
 
                        break;
                }
@@ -2826,32 +3085,38 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
                {
                        unsigned size = gnutls_ecc_curve_get_size(level);
 
-                       if (size == 0)
-                               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                       not_approved = true;
+
+                       if (size == 0) {
+                               ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+                               goto cleanup;
+                       }
 
                        params->curve = level;
 
                        params->raw_priv.data = gnutls_malloc(size);
-                       if (params->raw_priv.data == NULL)
-                               return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+                       if (params->raw_priv.data == NULL) {
+                               ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+                               goto cleanup;
+                       }
 
                        params->raw_pub.data = gnutls_malloc(size);
                        if (params->raw_pub.data == NULL) {
                                ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
-                               goto fail;
+                               goto cleanup;
                        }
 
                        ret = gnutls_rnd(rnd_level, params->raw_priv.data, size);
                        if (ret < 0) {
                                ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
-                               goto fail;
+                               goto cleanup;
                        }
                        params->raw_pub.size = size;
                        params->raw_priv.size = size;
 
                        ret = edwards_curve_mul_g(algo, params->raw_pub.data, params->raw_priv.data);
                        if (ret < 0)
-                               goto fail;
+                               goto cleanup;
                        break;
                }
        default:
@@ -2865,21 +3130,24 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
        ret = pct_test(algo, params);
        if (ret < 0) {
                gnutls_assert();
-               goto fail;
+               goto cleanup;
        }
 #endif
 
-       FAIL_IF_LIB_ERROR;
-       return 0;
-
-      fail:
-
-       for (i = 0; i < params->params_nr; i++) {
-               _gnutls_mpi_release(&params->params[i]);
+ cleanup:
+       if (ret < 0) {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+               for (i = 0; i < params->params_nr; i++) {
+                       _gnutls_mpi_release(&params->params[i]);
+               }
+               params->params_nr = 0;
+               gnutls_free(params->raw_priv.data);
+               gnutls_free(params->raw_pub.data);
+       } else if (not_approved) {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+       } else {
+               _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
        }
-       params->params_nr = 0;
-       gnutls_free(params->raw_priv.data);
-       gnutls_free(params->raw_pub.data);
 
        FAIL_IF_LIB_ERROR;
        return ret;
index 1904f594535944cfff0b23067d601913390d3b42..c5600a32a384a5b70ab2729062ef48edfbf7c82f 100644 (file)
--- a/lib/pk.c
+++ b/lib/pk.c
@@ -1200,6 +1200,18 @@ pk_prepare_hash(gnutls_pk_algorithm_t pk,
        case GNUTLS_PK_RSA:
                if (unlikely(hash == NULL))
                        return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+               /* Only SHA-2 is allowed in FIPS 140-3 */
+               switch (hash->id) {
+               case GNUTLS_MAC_SHA256:
+               case GNUTLS_MAC_SHA384:
+               case GNUTLS_MAC_SHA512:
+               case GNUTLS_MAC_SHA224:
+                       break;
+               default:
+                       _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+               }
+
                /* Encode the digest as a DigestInfo
                 */
                if ((ret =
index 14171f68d7bf8f32f774cd93d567bc45248d09cb..eba1f5b7b35fe48771430cc3cbbbdfae0ee9b066 100644 (file)
@@ -2367,6 +2367,19 @@ _pkcs1_rsa_verify_sig(gnutls_pk_algorithm_t pk,
        d.size = digest_size;
 
        if (pk == GNUTLS_PK_RSA) {
+               /* SHA-1 is allowed for SigVer in FIPS 140-3 in legacy
+                * mode */
+               switch (me->id) {
+               case GNUTLS_MAC_SHA1:
+               case GNUTLS_MAC_SHA256:
+               case GNUTLS_MAC_SHA384:
+               case GNUTLS_MAC_SHA512:
+               case GNUTLS_MAC_SHA224:
+                       break;
+               default:
+                       _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+               }
+
                /* decrypted is a BER encoded data of type DigestInfo
                 */
                ret = encode_ber_digest_info(me, &d, &di);
index 64eb2c5804a9fe7669745b6c82897f63eb129aff..828fb05e9c1ab652c182c030dd731f2838ebc05f 100644 (file)
@@ -95,6 +95,8 @@ struct dh_test_data {
        const gnutls_datum_t generator;
        const gnutls_datum_t peer_key;
        int expected_error;
+       gnutls_fips140_operation_state_t fips_state_genkey;
+       gnutls_fips140_operation_state_t fips_state_compute_key;
 };
 
 void doit(void)
@@ -106,7 +108,10 @@ void doit(void)
                        gnutls_ffdhe_2048_group_q,
                        gnutls_ffdhe_2048_group_generator,
                        { (void *)"\x00", 1 },
-                       GNUTLS_E_MPI_SCAN_FAILED
+                       GNUTLS_E_MPI_SCAN_FAILED,
+                       GNUTLS_FIPS140_OP_APPROVED,
+                       /* does not reach _wrap_nettle_pk_derive */
+                       GNUTLS_FIPS140_OP_INITIAL,
                },
                {
                        "[y < 2]",
@@ -114,7 +119,9 @@ void doit(void)
                        gnutls_ffdhe_2048_group_q,
                        gnutls_ffdhe_2048_group_generator,
                        { (void *)"\x01", 1 },
-                       GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
+                       GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER,
+                       GNUTLS_FIPS140_OP_APPROVED,
+                       GNUTLS_FIPS140_OP_ERROR,
                },
                {
                        "[y > p - 2]",
@@ -122,7 +129,9 @@ void doit(void)
                        gnutls_ffdhe_2048_group_q,
                        gnutls_ffdhe_2048_group_generator,
                        gnutls_ffdhe_2048_group_prime,
-                       GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
+                       GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER,
+                       GNUTLS_FIPS140_OP_APPROVED,
+                       GNUTLS_FIPS140_OP_ERROR,
                },
                {
                        "[y ^ q mod p == 1]",
@@ -130,7 +139,9 @@ void doit(void)
                        gnutls_ffdhe_2048_group_q,
                        gnutls_ffdhe_2048_group_generator,
                        gnutls_ffdhe_2048_group_q,
-                       GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
+                       GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER,
+                       GNUTLS_FIPS140_OP_APPROVED,
+                       GNUTLS_FIPS140_OP_ERROR,
                },
                {
                        "Legal Input",
@@ -138,27 +149,76 @@ void doit(void)
                        gnutls_ffdhe_2048_group_q,
                        gnutls_ffdhe_2048_group_generator,
                        { (void *)"\x02", 1 },
-                       0
+                       0,
+                       GNUTLS_FIPS140_OP_APPROVED,
+                       GNUTLS_FIPS140_OP_APPROVED,
                },
                { NULL }
        };
 
+#define FIPS_PUSH_CONTEXT() do {                                       \
+       if (gnutls_fips140_mode_enabled()) {                            \
+               ret = gnutls_fips140_push_context(fips_context);        \
+               if (ret < 0) {                                          \
+                       fail("gnutls_fips140_push_context failed\n");   \
+               }                                                       \
+       }                                                               \
+} while (0)
+
+#define FIPS_POP_CONTEXT(state) do {                                   \
+       if (gnutls_fips140_mode_enabled()) {                            \
+               ret = gnutls_fips140_pop_context();                     \
+               if (ret < 0) {                                          \
+                       fail("gnutls_fips140_context_pop failed\n");    \
+               }                                                       \
+               fips_state = gnutls_fips140_get_operation_state(fips_context); \
+               if (fips_state != state) {                              \
+                       fail("operation state is not %d (%d)\n",        \
+                            state, fips_state);                        \
+               }                                                       \
+       }                                                               \
+} while (0)
+
        for (int i = 0; test_data[i].name != NULL; i++) {
                gnutls_datum_t priv_key, pub_key;
                gnutls_dh_params_t dh_params;
-
+               gnutls_fips140_context_t fips_context;
+               gnutls_fips140_operation_state_t fips_state;
+               int ret;
+
+               if (gnutls_fips140_mode_enabled()) {
+                       ret = gnutls_fips140_context_init(&fips_context);
+                       if (ret < 0) {
+                               fail("Cannot initialize FIPS context\n");
+                       }
+               }
+
+               FIPS_PUSH_CONTEXT();
                params(&dh_params, &test_data[i].prime, &test_data[i].q,
                       &test_data[i].generator);
+               FIPS_POP_CONTEXT(GNUTLS_FIPS140_OP_INITIAL);
 
+               success("%s genkey\n", test_data[i].name);
+
+               FIPS_PUSH_CONTEXT();
                genkey(dh_params, &priv_key, &pub_key);
+               FIPS_POP_CONTEXT(test_data[i].fips_state_genkey);
 
+               success("%s compute_key\n", test_data[i].name);
+               
+               FIPS_PUSH_CONTEXT();
                compute_key(test_data[i].name, dh_params, &priv_key,
                            &pub_key, &test_data[i].peer_key,
                            test_data[i].expected_error, NULL, 0);
+               FIPS_POP_CONTEXT(test_data[i].fips_state_compute_key);
 
                gnutls_dh_params_deinit(dh_params);
                gnutls_free(priv_key.data);
                gnutls_free(pub_key.data);
+
+               if (gnutls_fips140_mode_enabled()) {
+                       gnutls_fips140_context_deinit(fips_context);
+               }
        }
 
        success("all ok\n");
index 23d23181226110d8427386797b19d5c2a45f0ee0..bf6ec2643591f95ffba0b5059506515da1ef48c5 100644 (file)
@@ -22,6 +22,93 @@ static void tls_log_func(int level, const char *str)
 static uint8_t key16[16];
 static uint8_t iv16[16];
 
+static const gnutls_datum_t data = { .data = (unsigned char *)"foo", 3 };
+static const uint8_t rsa2342_sha1_sig_data[] = {
+       0x9b, 0x3e, 0x15, 0x36, 0xec, 0x9d, 0x51, 0xd7, 0xa2, 0xb1, 0x3a, 0x15,
+       0x1a, 0xfe, 0x4e, 0x12, 0x43, 0x3c, 0xa8, 0x58, 0x4c, 0x2a, 0x82, 0xc1,
+       0x02, 0x3f, 0xc0, 0x6f, 0xa2, 0x23, 0xba, 0x58, 0x9f, 0xc0, 0xfc, 0x87,
+       0x5e, 0xfd, 0x13, 0x32, 0xa6, 0xd9, 0x72, 0x63, 0x04, 0x68, 0xb9, 0x0f,
+       0x46, 0x21, 0x3f, 0x7f, 0xe1, 0xa2, 0xb0, 0xfa, 0x66, 0x84, 0xd9, 0x64,
+       0x87, 0x40, 0x31, 0x27, 0xec, 0xb3, 0xbb, 0x53, 0xb5, 0x8f, 0xf9, 0x3c,
+       0x45, 0x1c, 0xcc, 0x30, 0xf5, 0xab, 0x9e, 0x1b, 0x86, 0x92, 0x6a, 0x58,
+       0xeb, 0xa1, 0x87, 0x71, 0x40, 0xfb, 0x9d, 0x8f, 0x2c, 0x82, 0x32, 0xe1,
+       0x7f, 0xfc, 0xe9, 0xd1, 0x76, 0xa3, 0x56, 0xdf, 0x38, 0xdb, 0xe2, 0x8a,
+       0xd3, 0x7e, 0xb4, 0xe2, 0xc9, 0x6a, 0xb2, 0x02, 0xe8, 0xf6, 0x34, 0xde,
+       0x51, 0x36, 0xd7, 0x3a, 0xba, 0x0f, 0x51, 0x3d, 0xb0, 0xe8, 0x8e, 0x58,
+       0x72, 0x1c, 0x89, 0xac, 0x68, 0xa5, 0x03, 0xb1, 0xd6, 0x5d, 0x32, 0x2f,
+       0x3c, 0x71, 0xcc, 0xc2, 0xd7, 0xf9, 0x51, 0xb1, 0xc8, 0x07, 0x07, 0x63,
+       0xe7, 0xa9, 0x9b, 0x9f, 0xdb, 0xc5, 0xb5, 0x68, 0xfd, 0xed, 0x11, 0x0c,
+       0xa7, 0xfa, 0x08, 0x59, 0xa8, 0x84, 0xcd, 0x36, 0x6b, 0xa5, 0xfe, 0xf9,
+       0xd3, 0xe1, 0x36, 0xaf, 0x71, 0x47, 0x39, 0x1e, 0xb7, 0xbc, 0x06, 0x66,
+       0xb8, 0xd7, 0x6d, 0x37, 0x6d, 0x52, 0x85, 0x34, 0x2b, 0x05, 0x62, 0x2e,
+       0xbe, 0x6d, 0xa3, 0x76, 0xcd, 0xe0, 0xd6, 0x3e, 0x9d, 0xcf, 0x74, 0xf9,
+       0xb4, 0x6b, 0xc0, 0x20, 0xe9, 0xd7, 0x19, 0x2d, 0xe6, 0x8a, 0xfd, 0xa2,
+       0xa4, 0x4a, 0xea, 0x01, 0x91, 0xf5, 0xb5, 0x29, 0x7a, 0xda, 0x68, 0xc6,
+       0x6c, 0xa0, 0x99, 0x5b, 0x79, 0x18, 0x96, 0xb1, 0xbe, 0x38, 0x74, 0x66,
+       0x4b, 0x47, 0x46, 0x89, 0xea, 0x25, 0x2a, 0x9e, 0x3a, 0xdc, 0x49, 0x6b,
+       0xba, 0xcb, 0xe4, 0x7a, 0x8f, 0x60, 0x35, 0xf3, 0x9f, 0x9d, 0xeb, 0x9d,
+       0xfa, 0x0c, 0xaf, 0x6e, 0x47, 0x65, 0xaf, 0x17, 0x18, 0x56, 0x16, 0xe8,
+       0x01, 0xd5, 0x55, 0xdf, 0xca, 0x41, 0x63, 0xd0, 0x48, 0x9b, 0x08, 0xdb,
+       0xdd, 0x73, 0x4a, 0xa5,
+};
+
+static const gnutls_datum_t rsa2342_sha1_sig = {
+       .data = (unsigned char *)rsa2342_sha1_sig_data,
+       .size = sizeof(rsa2342_sha1_sig_data),
+};
+
+static void
+rsa_import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
+                  const char *filename)
+{
+       const char *srcdir;
+       char path[256];
+       gnutls_datum_t tmp;
+       gnutls_x509_privkey_t xprivkey;
+       int ret;
+
+       ret = gnutls_x509_privkey_init(&xprivkey);
+       if (ret < 0) {
+               fail("gnutls_x509_privkey_init failed\n");
+       }
+       srcdir = getenv("srcdir");
+       if (!srcdir) {
+               srcdir = ".";
+       }
+       snprintf(path, sizeof(path), "%s/certs/%s", srcdir, filename);
+       ret = gnutls_load_file(path, &tmp);
+       if (ret < 0) {
+               fail("gnutls_load_file failed\n");
+       }
+       ret = gnutls_x509_privkey_import(xprivkey, &tmp, GNUTLS_X509_FMT_PEM);
+       if (ret < 0) {
+               fail("gnutls_x509_privkey_import failed\n");
+       }
+       gnutls_free(tmp.data);
+
+       ret = gnutls_privkey_init(privkey);
+       if (ret < 0) {
+               fail("gnutls_privkey_init failed\n");
+       }
+       ret = gnutls_privkey_import_x509(*privkey, xprivkey,
+                                        GNUTLS_PRIVKEY_IMPORT_COPY);
+       if (ret < 0) {
+               fail("gnutls_privkey_import_x509 failed\n");
+       }
+       gnutls_x509_privkey_deinit(xprivkey);
+
+       ret = gnutls_pubkey_init(pubkey);
+       if (ret < 0) {
+               fail("gnutls_pubkey_init failed\n");
+       }
+       ret = gnutls_pubkey_import_privkey(*pubkey, *privkey,
+                                          GNUTLS_KEY_DIGITAL_SIGNATURE, 0);
+       if (ret < 0) {
+               fail("gnutls_pubkey_import_privkey failed\n");
+       }
+
+}
+
 void doit(void)
 {
        int ret;
@@ -34,6 +121,10 @@ void doit(void)
        gnutls_privkey_t privkey;
        gnutls_datum_t key = { key16, sizeof(key16) };
        gnutls_datum_t iv = { iv16, sizeof(iv16) };
+       gnutls_fips140_context_t fips_context;
+       gnutls_fips140_operation_state_t fips_state;
+       gnutls_datum_t signature;
+       unsigned int bits;
 
        fprintf(stderr,
                "Please note that if in FIPS140 mode, you need to assure the library's integrity prior to running this test\n");
@@ -53,6 +144,38 @@ void doit(void)
                fail("Cannot initialize library\n");
        }
 
+       ret = gnutls_fips140_context_init(&fips_context);
+       if (ret < 0) {
+               fail("Cannot initialize FIPS context\n");
+       }
+       fips_state = gnutls_fips140_get_operation_state(fips_context);
+       if (fips_state != GNUTLS_FIPS140_OP_INITIAL) {
+               fail("operation state is not initial\n");
+       }
+       ret = gnutls_fips140_pop_context();
+       if (ret != GNUTLS_E_INVALID_REQUEST) {
+               fail("gnutls_fips140_pop_context succeeded while not pushed\n");
+       }
+
+#define FIPS_PUSH_CONTEXT() do {                               \
+       ret = gnutls_fips140_push_context(fips_context);        \
+       if (ret < 0) {                                          \
+               fail("gnutls_fips140_push_context failed\n");   \
+       }                                                       \
+} while (0)
+
+#define FIPS_POP_CONTEXT(state) do {                                   \
+       ret = gnutls_fips140_pop_context();                             \
+       if (ret < 0) {                                                  \
+               fail("gnutls_fips140_context_pop failed\n");            \
+       }                                                               \
+       fips_state = gnutls_fips140_get_operation_state(fips_context);  \
+       if (fips_state != GNUTLS_FIPS140_OP_ ## state) {                \
+               fail("operation state is not " # state " (%d)\n",       \
+                    fips_state);                                       \
+       }                                                               \
+} while (0)
+
        /* Try crypto.h functionality */
        ret =
            gnutls_cipher_init(&ch, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
@@ -101,6 +224,23 @@ void doit(void)
        }
        gnutls_deinit(session);
 
+       /* Generate 2048-bit RSA key */
+       FIPS_PUSH_CONTEXT();
+       ret = gnutls_x509_privkey_init(&xprivkey);
+       if (ret < 0) {
+               fail("gnutls_privkey_init failed\n");
+       }
+       bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_RSA, GNUTLS_SEC_PARAM_MEDIUM);
+       ret = gnutls_x509_privkey_generate(xprivkey, GNUTLS_PK_RSA, bits, 0);
+       if (ret < 0) {
+               fail("gnutls_x509_privkey_generate failed (%d) for %u-bit key\n",
+                    ret, bits);
+       }
+       gnutls_x509_privkey_deinit(xprivkey);
+       FIPS_POP_CONTEXT(APPROVED);
+
+       /* Generate 512-bit RSA key */
+       FIPS_PUSH_CONTEXT();
        ret = gnutls_x509_privkey_init(&xprivkey);
        if (ret < 0) {
                fail("gnutls_privkey_init failed\n");
@@ -110,6 +250,60 @@ void doit(void)
                fail("gnutls_x509_privkey_generate succeeded (%d) for 512-bit key\n", ret);
        }
        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");
+       FIPS_POP_CONTEXT(INITIAL);
+
+       /* Create a signature with SHA256; 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");
+       }
+       gnutls_free(signature.data);
+       FIPS_POP_CONTEXT(APPROVED);
+
+       /* Create a signature with SHA-1; 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");
+       }
+       gnutls_free(signature.data);
+       FIPS_POP_CONTEXT(NOT_APPROVED);
+
+       /* Verify a signature created with SHA-1; approved */
+       FIPS_PUSH_CONTEXT();
+       ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &data,
+                                        &rsa2342_sha1_sig);
+       if (ret < 0) {
+               fail("gnutls_pubkey_verify_data2 failed\n");
+       }
+       FIPS_POP_CONTEXT(APPROVED);
+       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");
+       FIPS_POP_CONTEXT(INITIAL);
+
+       /* Create a signature; not 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");
+       }
+       gnutls_free(signature.data);
+       FIPS_POP_CONTEXT(NOT_APPROVED);
+       gnutls_pubkey_deinit(pubkey);
+       gnutls_privkey_deinit(privkey);
 
        /* Test when FIPS140 is set to error state */
        _gnutls_lib_simulate_error();
@@ -152,6 +346,7 @@ void doit(void)
                fail("gnutls_init succeeded when in FIPS140 error state\n");
        }
 
+       gnutls_fips140_context_deinit(fips_context);
        gnutls_global_deinit();
        return;
 }
index 565beccb20524d44ce58a7c7412d300ee9848617..cac530fc435f405fa31decfa32392da066b2f75d 100644 (file)
@@ -49,7 +49,7 @@ static int sec_param[MAX_TRIES] =
 
 static void tls_log_func(int level, const char *str)
 {
-       fprintf(stderr, "%s |<%d>| %s", "crq_key_id", level, str);
+       fprintf(stderr, "%s |<%d>| %s", "privkey-keygen", level, str);
 }
 
 const gnutls_datum_t raw_data = {
@@ -102,10 +102,47 @@ static void sign_verify_data(gnutls_pk_algorithm_t algorithm, gnutls_x509_privke
        gnutls_free(signature.data);
 }
 
+static unsigned int
+is_approved_pk_algo(gnutls_pk_algorithm_t algo) {
+       switch (algo) {
+       case GNUTLS_PK_RSA:
+       case GNUTLS_PK_RSA_PSS:
+       case GNUTLS_PK_EC:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
 void doit(void)
 {
        gnutls_x509_privkey_t pkey, dst;
        int ret, algorithm, i;
+       gnutls_fips140_context_t fips_context;
+       gnutls_fips140_operation_state_t fips_state;
+
+#define FIPS_PUSH_CONTEXT() do {                                       \
+       if (gnutls_fips140_mode_enabled()) {                            \
+               ret = gnutls_fips140_push_context(fips_context);        \
+               if (ret < 0) {                                          \
+                       fail("gnutls_fips140_push_context failed\n");   \
+               }                                                       \
+       }                                                               \
+} while (0)
+
+#define FIPS_POP_CONTEXT(state) do {                                   \
+       if (gnutls_fips140_mode_enabled()) {                            \
+               ret = gnutls_fips140_pop_context();                     \
+               if (ret < 0) {                                          \
+                       fail("gnutls_fips140_context_pop failed\n");    \
+               }                                                       \
+               fips_state = gnutls_fips140_get_operation_state(fips_context); \
+               if (fips_state != GNUTLS_FIPS140_OP_ ## state) {        \
+                       fail("operation state is not " # state " (%d)\n", \
+                            fips_state);                               \
+               }                                                       \
+       }                                                               \
+} while (0)
 
        ret = global_init();
        if (ret < 0)
@@ -115,6 +152,11 @@ void doit(void)
        if (debug)
                gnutls_global_set_log_level(4711);
 
+       ret = gnutls_fips140_context_init(&fips_context);
+       if (ret < 0) {
+               fail("Cannot initialize FIPS context\n");
+       }
+
        for (i = 0; i < MAX_TRIES; i++) {
                for (algorithm = GNUTLS_PK_RSA; algorithm <= GNUTLS_PK_MAX;
                     algorithm++) {
@@ -150,6 +192,7 @@ void doit(void)
                                     ret);
                        }
 
+                       FIPS_PUSH_CONTEXT();
                        ret =
                            gnutls_x509_privkey_generate(pkey, algorithm,
                                                         gnutls_sec_param_to_pk_bits
@@ -164,6 +207,11 @@ void doit(void)
                                        gnutls_pk_algorithm_get_name
                                        (algorithm), ret);
                        }
+                       if (is_approved_pk_algo(algorithm)) {
+                               FIPS_POP_CONTEXT(APPROVED);
+                       } else {
+                               FIPS_POP_CONTEXT(NOT_APPROVED);
+                       }
 
                        ret = gnutls_x509_privkey_verify_params(pkey);
                        if (ret < 0) {
@@ -181,8 +229,21 @@ void doit(void)
                                fail("gnutls_x509_privkey_generate after cpy (%s): %s (%d)\n", gnutls_pk_algorithm_get_name(algorithm), gnutls_strerror(ret), ret);
                        }
 
+                       FIPS_PUSH_CONTEXT();
                        sign_verify_data(algorithm, pkey);
+                       if (is_approved_pk_algo(algorithm)) {
+                               FIPS_POP_CONTEXT(APPROVED);
+                       } else {
+                               FIPS_POP_CONTEXT(NOT_APPROVED);
+                       }
+
+                       FIPS_PUSH_CONTEXT();
                        sign_verify_data(algorithm, dst);
+                       if (is_approved_pk_algo(algorithm)) {
+                               FIPS_POP_CONTEXT(APPROVED);
+                       } else {
+                               FIPS_POP_CONTEXT(NOT_APPROVED);
+                       }
 
                        gnutls_x509_privkey_deinit(pkey);
                        gnutls_x509_privkey_deinit(dst);