=item - the derived key length is at least 112 bits.
+=item - the password length is at least minimum length.
+
+The default minimum password length can be configured when OpenSSL is
+compiled by setting B<-DKDF_PBKDF2_MIN_PASSWORD_LEN=length>. If not
+set then 1 is used for the default provider and 8 for the FIPS
+provider since 4.0.0. Please consult the security policy document of
+your FIPS provider from your vendor for further details, as
+implementation often vary by each vendor.
+
=back
The default provider uses a default mode of 1 for backwards compatibility,
This option is used by the OpenSSL FIPS provider.
-A getter that returns 1 if the operation is FIPS approved, or 0 otherwise.
-This may be used after calling EVP_KDF_derive. It returns 0 if "pkcs5"
-is set to 1 and the derived key length, salt length or iteration count test
-fails.
+A getter that returns 1 if the operation is FIPS approved, or 0
+otherwise. This may be used after calling EVP_KDF_derive. It returns
+0 if "pkcs5" is set to 1 and the password length, derived key length,
+salt length or iteration count test fails.
=back
#define KDF_PBKDF2_MAX_KEY_LEN_DIGEST_RATIO 0xFFFFFFFF
#define KDF_PBKDF2_MIN_ITERATIONS 1000
#define KDF_PBKDF2_MIN_SALT_LEN (128 / 8)
+/*
+ * The Implementation Guidance for FIPS 140-3 says in section D.N
+ * "Password-Based Key Derivation for Storage Applications" that "the vendor
+ * shall document in the module's Security Policy the length of
+ * a password/passphrase used in key derivation and establish an upper bound
+ * for the probability of having this parameter guessed at random. This
+ * probability shall take into account not only the length of the
+ * password/passphrase, but also the difficulty of guessing it. The decision on
+ * the minimum length of a password used for key derivation is the vendor's,
+ * but the vendor shall at a minimum informally justify the decision."
+ *
+ * ACVP may assume 8, most FIPS modules choose 8, BC-FJA chose 14.
+ *
+ * Allow setting this for default provider too, in case consistency is
+ * desired for FIPS and Default providers. Because password being
+ * accepted on one system, but not the other, is very confusing.
+ */
+#ifndef KDF_PBKDF2_MIN_PASSWORD_LEN
+# ifdef FIPS_MODULE
+# define KDF_PBKDF2_MIN_PASSWORD_LEN (8)
+# else
+# define KDF_PBKDF2_MIN_PASSWORD_LEN (1)
+# endif
+#endif
static OSSL_FUNC_kdf_newctx_fn kdf_pbkdf2_new;
static OSSL_FUNC_kdf_dupctx_fn kdf_pbkdf2_dup;
}
static int pbkdf2_lower_bound_check_passed(int saltlen, uint64_t iter,
- size_t keylen, int *error,
- const char **desc)
+ size_t keylen, size_t passlen,
+ int *error, const char **desc)
{
+ if (passlen < KDF_PBKDF2_MIN_PASSWORD_LEN) {
+ *error = PROV_R_PASSWORD_STRENGTH_TOO_WEAK;
+ if (desc != NULL)
+ *desc = "Weak password";
+ return 0;
+ }
if ((keylen * 8) < KDF_PBKDF2_MIN_KEY_LEN_BITS) {
*error = PROV_R_KEY_SIZE_TOO_SMALL;
if (desc != NULL)
#ifdef FIPS_MODULE
static int fips_lower_bound_check_passed(KDF_PBKDF2 *ctx, int saltlen,
- uint64_t iter, size_t keylen)
+ uint64_t iter, size_t keylen,
+ size_t passlen)
{
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
int error = 0;
const char *desc = NULL;
int approved = pbkdf2_lower_bound_check_passed(saltlen, iter, keylen,
- &error, &desc);
+ passlen, &error, &desc);
if (!approved) {
if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, libctx,
#endif
static int lower_bound_check_passed(KDF_PBKDF2 *ctx, int saltlen, uint64_t iter,
- size_t keylen, int lower_bound_checks)
+ size_t keylen, size_t passlen,
+ int lower_bound_checks)
{
#ifdef FIPS_MODULE
- if (!fips_lower_bound_check_passed(ctx, saltlen, iter, keylen))
+ if (!fips_lower_bound_check_passed(ctx, saltlen, iter, keylen, passlen))
return 0;
#else
if (lower_bound_checks) {
int error = 0;
int passed = pbkdf2_lower_bound_check_passed(saltlen, iter, keylen,
- &error, NULL);
+ passlen, &error, NULL);
if (!passed) {
ERR_raise(ERR_LIB_PROV, error);
#endif
}
- if (p.pw != NULL && !pbkdf2_set_membuf(&ctx->pass, &ctx->pass_len, p.pw))
+ if (p.pw != NULL) {
+ if (ctx->lower_bound_checks != 0
+ && p.pw->data_size < KDF_PBKDF2_MIN_PASSWORD_LEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_PASSWORD_STRENGTH_TOO_WEAK);
return 0;
+ }
+ if (!pbkdf2_set_membuf(&ctx->pass, &ctx->pass_len, p.pw))
+ return 0;
+ }
if (p.salt != NULL) {
if (!lower_bound_check_passed(ctx, (int)p.salt->data_size, UINT64_MAX, SIZE_MAX,
- ctx->lower_bound_checks))
+ SIZE_MAX, ctx->lower_bound_checks))
return 0;
if (!pbkdf2_set_membuf(&ctx->salt, &ctx->salt_len, p.salt))
return 0;
if (!OSSL_PARAM_get_uint64(p.iter, &iter))
return 0;
if (!lower_bound_check_passed(ctx, INT_MAX, iter, SIZE_MAX,
- ctx->lower_bound_checks))
+ SIZE_MAX, ctx->lower_bound_checks))
return 0;
ctx->iter = iter;
}
return 0;
}
- if (!lower_bound_check_passed(ctx, saltlen, iter, keylen, lower_bound_checks))
+ if (!lower_bound_check_passed(ctx, saltlen, iter, keylen, passlen, lower_bound_checks))
return 0;
hctx_tpl = HMAC_CTX_new();