]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Change PBES2 KDF default salt length to 16 bytes.
authorslontis <shane.lontis@oracle.com>
Mon, 28 Aug 2023 02:47:51 +0000 (12:47 +1000)
committerPauli <pauli@openssl.org>
Mon, 4 Sep 2023 04:15:34 +0000 (14:15 +1000)
The PKCS5 (RFC 8018) standard uses a 64 bit salt length for PBE, and
recommends a minimum of 64 bits for PBES2. For FIPS compliance PBKDF2
requires a salt length of 128 bits.
This affects OpenSSL command line applications such as "genrsa" and "pkcs8"
and API's such as PEM_write_bio_PrivateKey() that are reliant on the
default salt length.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21858)

CHANGES.md
crypto/asn1/p5_pbe.c
crypto/asn1/p5_pbev2.c
crypto/asn1/p5_scrypt.c
doc/man3/PKCS5_PBE_keyivgen.pod
include/crypto/evp.h
test/recipes/15-test_genrsa.t
test/recipes/25-test_pkcs8.t

index 78e74c41fa1f81fa86bf1a141904efc47d43e432..8f1e757f8ca5e87aaec739e078579f9de2d31b7e 100644 (file)
@@ -25,6 +25,16 @@ OpenSSL 3.2
 
 ### Changes between 3.1 and 3.2 [xx XXX xxxx]
 
+ * Changed the default salt length used by PBES2 KDF's (PBKDF2 and scrypt)
+   from 8 bytes to 16 bytes.
+   The PKCS5 (RFC 8018) standard uses a 64 bit salt length for PBE, and
+   recommends a minimum of 64 bits for PBES2. For FIPS compliance PBKDF2
+   requires a salt length of 128 bits. This affects OpenSSL command line
+   applications such as "genrsa" and "pkcs8" and API's such as
+   PEM_write_bio_PrivateKey() that are reliant on the default value.
+
+   *Shane Lontis*
+
  * Changed the default value of the `ess_cert_id_alg` configuration
    option which is used to calculate the TSA's public key certificate
    identifier. The default algorithm is updated to be sha256 instead
index 13b3f19bae89bb68b8abd93330b926ee845cee19..c595973fe5166f3c0f8824d1eb9093887bfa619f 100644 (file)
@@ -12,6 +12,7 @@
 #include <openssl/asn1t.h>
 #include <openssl/x509.h>
 #include <openssl/rand.h>
+#include "crypto/evp.h"
 
 /* PKCS#5 password based encryption structure */
 
@@ -45,7 +46,7 @@ int PKCS5_pbe_set0_algor_ex(X509_ALGOR *algor, int alg, int iter,
         goto err;
     }
     if (!saltlen)
-        saltlen = PKCS5_SALT_LEN;
+        saltlen = PKCS5_DEFAULT_PBE1_SALT_LEN;
     if (saltlen < 0)
         goto err;
 
index e710cf3c35813adb9ecd9cd5e1ef06f66fe7f256..c188a08a6eb236103e33f46c574d1c4bcede2b05 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include "crypto/asn1.h"
+#include "crypto/evp.h"
 #include <openssl/asn1t.h>
 #include <openssl/core.h>
 #include <openssl/core_names.h>
@@ -196,7 +197,7 @@ X509_ALGOR *PKCS5_pbkdf2_set_ex(int iter, unsigned char *salt, int saltlen,
         goto err;
     }
     if (saltlen == 0)
-        saltlen = PKCS5_SALT_LEN;
+        saltlen = PKCS5_DEFAULT_PBE2_SALT_LEN;
     if ((osalt->data = OPENSSL_malloc(saltlen)) == NULL)
         goto err;
 
index 94b77fd3ab29797a1e91acd106504e6850d149f4..d6ec2445fa1b6aad521dc9b847d9819f2bf80f1d 100644 (file)
@@ -166,7 +166,7 @@ static X509_ALGOR *pkcs5_scrypt_set(const unsigned char *salt, size_t saltlen,
     }
 
     if (!saltlen)
-        saltlen = PKCS5_SALT_LEN;
+        saltlen = PKCS5_DEFAULT_PBE2_SALT_LEN;
 
     /* This will either copy salt or grow the buffer */
     if (ASN1_STRING_set(sparam->salt, salt, saltlen) == 0) {
index 72de3153b97defdb13f53062a48307d726f91675..f697628db13bb5429ff835461ef7a5bf3e150807 100644 (file)
@@ -127,6 +127,12 @@ associated parameters for the PBKDF2 algorithm.
 PKCS5_pbe_set0_algor() and PKCS5_pbe_set0_algor_ex() set the PBE algorithm OID and
 parameters into the supplied B<X509_ALGOR>.
 
+If I<salt> is NULL, then I<saltlen> specifies the size in bytes of the random salt to
+generate. If I<saltlen> is 0 then a default size is used.
+For PBE related functions such as PKCS5_pbe_set_ex() the default salt length is 8 bytes.
+For PBE2 related functions that use PBKDF2 such as PKCS5_pbkdf2_set(),
+PKCS5_pbe2_set_scrypt() and PKCS5_pbe2_set() the default salt length is 16 bytes.
+
 =head1 NOTES
 
 The *_keyivgen() functions are typically used in PKCS#12 to encrypt objects.
@@ -165,9 +171,13 @@ PKCS5_pbkdf2_set_ex() were added in OpenSSL 3.0.
 From OpenSSL 3.0 the PBKDF1 algorithm used in PKCS5_PBE_keyivgen() and
 PKCS5_PBE_keyivgen_ex() has been moved to the legacy provider as an EVP_KDF.
 
+In OpenSSL 3.2 the default salt length changed from 8 bytes to 16 bytes for PBE2
+related functions such as PKCS5_pbe2_set().
+This is required for PBKDF2 FIPS compliance.
+
 =head1 COPYRIGHT
 
-Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2021-2023 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the Apache License 2.0 (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index 566b7889dbcfc058371e79fe43faeb23f1b87bb3..9605c9daa53fffcaa0a337939bfabc03d36df290 100644 (file)
 # include "internal/refcount.h"
 # include "crypto/ecx.h"
 
+/*
+ * Default PKCS5 PBE KDF salt lengths
+ * In RFC 8018, PBE1 uses 8 bytes (64 bits) for its salt length.
+ * It also specifies to use at least 8 bytes for PBES2.
+ * The NIST requirement for PBKDF2 is 128 bits so we use this as the
+ * default for PBE2 (scrypt and HKDF2)
+ */
+# define PKCS5_DEFAULT_PBE1_SALT_LEN     PKCS5_SALT_LEN
+# define PKCS5_DEFAULT_PBE2_SALT_LEN     16
 /*
  * Don't free up md_ctx->pctx in EVP_MD_CTX_reset, use the reserved flag
  * values in evp.h
index fe99f3369490c0a0ac59626d55712a32a060339c..5632efe5fc5c230fdb3705778115b0c7048bbaa3 100644 (file)
@@ -25,7 +25,7 @@ my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0);
 
 plan tests =>
     ($no_fips ? 0 : 5)          # Extra FIPS related tests
-    + 15;
+    + 16;
 
 # We want to know that an absurdly small number of bits isn't support
 is(run(app([ 'openssl', 'genpkey', '-out', 'genrsatest.pem',
@@ -106,6 +106,13 @@ ok(run(app([ 'openssl', 'rsa', '-check', '-in', 'genrsatest.pem', '-noout' ])),
 ok(run(app([ 'openssl', 'rsa', '-in', 'genrsatest.pem', '-out', 'genrsatest-enc.pem',
    '-aes256', '-passout', 'pass:x' ])),
    "rsa encrypt");
+# Check the default salt length for PBKDF2 is 16 bytes
+# We expect the output to be of the form "0:d=0  hl=2 l=  16 prim: OCTET STRING      [HEX DUMP]:FAC7F37508E6B7A805BF4B13861B3687"
+# i.e. 2 byte header + 16 byte salt.
+ok(run(app(([ 'openssl', 'asn1parse',
+              '-in', 'genrsatest-enc.pem',
+              '-offset', '34', '-length', '18']))),
+   "Check the default size of the PBKDF2 PARAM 'salt length' is 16");
 ok(run(app([ 'openssl', 'rsa', '-in', 'genrsatest-enc.pem', '-passin', 'pass:x' ])),
    "rsa decrypt");
 
index 299a56b85222af350ee29974f8b6e42afdafc37a..7a06be19e4e59c1cc955ebfb25acd95c434ba00e 100644 (file)
@@ -15,7 +15,58 @@ use OpenSSL::Test qw/:DEFAULT srctop_file ok_nofips is_nofips/;
 
 setup("test_pkcs8");
 
-plan tests => 3;
+plan tests => 9;
+
+ok(run(app(([ 'openssl', 'pkcs8', '-topk8',
+              '-in', srctop_file('test', 'certs', 'pc5-key.pem'),
+              '-out', 'pbkdf2_default_saltlen.pem',
+              '-passout', 'pass:password']))),
+   "Convert a private key to PKCS5 v2.0 format using PBKDF2 with the default saltlen");
+
+# We expect the output to be of the form "0:d=0  hl=2 l=  16 prim: OCTET STRING      [HEX DUMP]:FAC7F37508E6B7A805BF4B13861B3687"
+# i.e. 2 byte header + 16 byte salt.
+ok(run(app(([ 'openssl', 'asn1parse',
+              '-in', 'pbkdf2_default_saltlen.pem',
+              '-offset', '34', '-length', '18']))),
+   "Check the default size of the PBKDF2 PARAM 'salt length' is 16");
+
+SKIP: {
+    skip "scrypt is not supported by this OpenSSL build", 2
+        if disabled("scrypt");
+
+    ok(run(app(([ 'openssl', 'pkcs8', '-topk8',
+                  '-in', srctop_file('test', 'certs', 'pc5-key.pem'),
+                  '-scrypt',
+                  '-out', 'scrypt_default_saltlen.pem',
+                  '-passout', 'pass:password']))),
+       "Convert a private key to PKCS5 v2.0 format using scrypt with the default saltlen");
+
+# We expect the output to be of the form "0:d=0  hl=2 l=  8 prim: OCTET STRING      [HEX DUMP]:FAC7F37508E6B7A805BF4B13861B3687"
+# i.e. 2 byte header + 16 byte salt.
+    ok(run(app(([ 'openssl', 'asn1parse',
+                  '-in', 'scrypt_default_saltlen.pem',
+                  '-offset', '34', '-length', '18']))),
+       "Check the default size of the SCRYPT PARAM 'salt length' = 16");
+}
+
+SKIP: {
+    skip "legacy provider is not supported by this OpenSSL build", 2
+        if disabled('legacy') || disabled("des");
+
+    ok(run(app(([ 'openssl', 'pkcs8', '-topk8',
+                  '-in', srctop_file('test', 'certs', 'pc5-key.pem'),
+                  '-v1', "PBE-MD5-DES",
+                  '-provider', 'legacy',
+                  '-provider', 'default',
+                  '-out', 'pbe1.pem',
+                  '-passout', 'pass:password']))),
+       "Convert a private key to PKCS5 v1.5 format using pbeWithMD5AndDES-CBC with the default saltlen");
+
+    ok(run(app(([ 'openssl', 'asn1parse',
+                  '-in', 'pbe1.pem',
+                  '-offset', '19', '-length', '10']))),
+       "Check the default size of the PBE PARAM 'salt length' = 8");
+};
 
 SKIP: {
     skip "SM2, SM3 or SM4 is not supported by this OpenSSL build", 3