#24 Allow disabling of SHA1 signatures
Merged 10 months ago by clang. Opened 10 months ago by clang.
rpms/ clang/openssl f36-sha1-rhbz2070977-rhbz2071615  into  f36

@@ -0,0 +1,503 @@ 

+ From b4f8964ad1903e24cd2ee07f42ce97c3047f4af4 Mon Sep 17 00:00:00 2001

+ From: Clemens Lang <cllang@redhat.com>

+ Date: Mon, 21 Feb 2022 17:24:44 +0100

+ Subject: [PATCH] Allow disabling of SHA1 signatures

+ MIME-Version: 1.0

+ Content-Type: text/plain; charset=UTF-8

+ Content-Transfer-Encoding: 8bit

+ 

+ NOTE: This patch is ported from CentOS 9 / RHEL 9, where it defaults to

+ denying SHA1 signatures. On Fedora, the default is – for now – to allow

+ SHA1 signatures.

+ 

+ In order to phase out SHA1 signatures, introduce a new configuration

+ option in the alg_section named 'rh-allow-sha1-signatures'. This option

+ defaults to true. If set to false, any signature creation or

+ verification operations that involve SHA1 as digest will fail.

+ 

+ This also affects TLS, where the signature_algorithms extension of any

+ ClientHello message sent by OpenSSL will no longer include signatures

+ with the SHA1 digest if rh-allow-sha1-signatures is false. For servers

+ that request a client certificate, the same also applies for

+ CertificateRequest messages sent by them.

+ 

+ For signatures created using the EVP_PKEY API, this is a best-effort

+ check that will deny signatures in cases where the digest algorithm is

+ known. This means, for example, that that following steps will still

+ work:

+ 

+  $> openssl dgst -sha1 -binary -out sha1 infile

+  $> openssl pkeyutl -inkey key.pem -sign -in sha1 -out sha1sig

+  $> openssl pkeyutl -inkey key.pem -verify -sigfile sha1sig -in sha1

+ 

+ whereas these will not:

+ 

+  $> openssl dgst -sha1 -binary -out sha1 infile

+  $> openssl pkeyutl -inkey kem.pem -sign -in sha1 -out sha1sig -pkeyopt digest:sha1

+  $> openssl pkeyutl -inkey kem.pem -verify -sigfile sha1sig -in sha1 -pkeyopt digest:sha1

+ 

+ This happens because in the first case, OpenSSL's signature

+ implementation does not know that it is signing a SHA1 hash (it could be

+ signing arbitrary data).

+ ---

+  crypto/evp/evp_cnf.c                          | 13 +++

+  crypto/evp/m_sigver.c                         | 85 +++++++++++++++++++

+  crypto/evp/pmeth_lib.c                        | 15 ++++

+  doc/man5/config.pod                           | 13 +++

+  include/internal/cryptlib.h                   |  3 +-

+  include/internal/sslconf.h                    |  4 +

+  providers/common/securitycheck.c              | 20 +++++

+  providers/common/securitycheck_default.c      |  9 +-

+  providers/implementations/signature/dsa_sig.c | 11 ++-

+  .../implementations/signature/ecdsa_sig.c     |  4 +

+  providers/implementations/signature/rsa_sig.c | 20 ++++-

+  ssl/t1_lib.c                                  |  8 ++

+  util/libcrypto.num                            |  2 +

+  13 files changed, 198 insertions(+), 9 deletions(-)

+ 

+ diff --git a/crypto/evp/evp_cnf.c b/crypto/evp/evp_cnf.c

+ index 0e7fe64cf9..b9d3b6d226 100644

+ --- a/crypto/evp/evp_cnf.c

+ +++ b/crypto/evp/evp_cnf.c

+ @@ -10,6 +10,7 @@

+  #include <stdio.h>

+  #include <openssl/crypto.h>

+  #include "internal/cryptlib.h"

+ +#include "internal/sslconf.h"

+  #include <openssl/conf.h>

+  #include <openssl/x509.h>

+  #include <openssl/x509v3.h>

+ @@ -57,6 +58,18 @@ static int alg_module_init(CONF_IMODULE *md, const CONF *cnf)

+                  ERR_raise(ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE);

+                  return 0;

+              }

+ +        } else if (strcmp(oval->name, "rh-allow-sha1-signatures") == 0) {

+ +            int m;

+ +

+ +            /* Detailed error already reported. */

+ +            if (!X509V3_get_value_bool(oval, &m))

+ +                return 0;

+ +

+ +            if (!ossl_ctx_legacy_digest_signatures_allowed_set(

+ +                    NCONF_get0_libctx((CONF *)cnf), m > 0, 0)) {

+ +                ERR_raise(ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE);

+ +                return 0;

+ +            }

+          } else {

+              ERR_raise_data(ERR_LIB_EVP, EVP_R_UNKNOWN_OPTION,

+                             "name=%s, value=%s", oval->name, oval->value);

+ diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c

+ index 76a6814b42..8da2183ce0 100644

+ --- a/crypto/evp/m_sigver.c

+ +++ b/crypto/evp/m_sigver.c

+ @@ -16,6 +16,79 @@

+  #include "internal/numbers.h"   /* includes SIZE_MAX */

+  #include "evp_local.h"

+  

+ +typedef struct ossl_legacy_digest_signatures_st {

+ +    int allowed;

+ +} OSSL_LEGACY_DIGEST_SIGNATURES;

+ +

+ +static void ossl_ctx_legacy_digest_signatures_free(void *vldsigs)

+ +{

+ +    OSSL_LEGACY_DIGEST_SIGNATURES *ldsigs = vldsigs;

+ +

+ +    if (ldsigs != NULL) {

+ +        OPENSSL_free(ldsigs);

+ +    }

+ +}

+ +

+ +static void *ossl_ctx_legacy_digest_signatures_new(OSSL_LIB_CTX *ctx)

+ +{

+ +    OSSL_LEGACY_DIGEST_SIGNATURES* ldsigs = OPENSSL_zalloc(sizeof(OSSL_LEGACY_DIGEST_SIGNATURES));

+ +    /* Warning: This patch differs from the same patch in CentOS and RHEL here,

+ +     * because the default on Fedora is to allow SHA-1 and support disabling

+ +     * it, while CentOS/RHEL disable it by default and allow enabling it. */

+ +    ldsigs->allowed = 1;

+ +    return ldsigs;

+ +}

+ +

+ +static const OSSL_LIB_CTX_METHOD ossl_ctx_legacy_digest_signatures_method = {

+ +    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,

+ +    ossl_ctx_legacy_digest_signatures_new,

+ +    ossl_ctx_legacy_digest_signatures_free,

+ +};

+ +

+ +static OSSL_LEGACY_DIGEST_SIGNATURES *ossl_ctx_legacy_digest_signatures(

+ +        OSSL_LIB_CTX *libctx, int loadconfig)

+ +{

+ +#ifndef FIPS_MODULE

+ +    if (loadconfig && !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL))

+ +        return NULL;

+ +#endif

+ +

+ +    return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_LEGACY_DIGEST_SIGNATURES,

+ +                                 &ossl_ctx_legacy_digest_signatures_method);

+ +}

+ +

+ +int ossl_ctx_legacy_digest_signatures_allowed(OSSL_LIB_CTX *libctx, int loadconfig)

+ +{

+ +    OSSL_LEGACY_DIGEST_SIGNATURES *ldsigs

+ +        = ossl_ctx_legacy_digest_signatures(libctx, loadconfig);

+ +

+ +#ifndef FIPS_MODULE

+ +    if (ossl_safe_getenv("OPENSSL_ENABLE_SHA1_SIGNATURES") != NULL)

+ +        /* used in tests */

+ +        return 1;

+ +#endif

+ +

+ +    /* Warning: This patch differs from the same patch in CentOS and RHEL here,

+ +     * because the default on Fedora is to allow SHA-1 and support disabling

+ +     * it, while CentOS/RHEL disable it by default and allow enabling it. */

+ +    return ldsigs != NULL ? ldsigs->allowed : 1;

+ +}

+ +

+ +int ossl_ctx_legacy_digest_signatures_allowed_set(OSSL_LIB_CTX *libctx, int allow,

+ +                                                  int loadconfig)

+ +{

+ +    OSSL_LEGACY_DIGEST_SIGNATURES *ldsigs

+ +        = ossl_ctx_legacy_digest_signatures(libctx, loadconfig);

+ +

+ +    if (ldsigs == NULL) {

+ +        ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);

+ +        return 0;

+ +    }

+ +

+ +    ldsigs->allowed = allow;

+ +    return 1;

+ +}

+ +

+  #ifndef FIPS_MODULE

+  

+  static int update(EVP_MD_CTX *ctx, const void *data, size_t datalen)

+ @@ -258,6 +331,18 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,

+          }

+      }

+  

+ +    if (ctx->reqdigest != NULL

+ +            && !EVP_PKEY_is_a(locpctx->pkey, SN_hmac)

+ +            && !EVP_PKEY_is_a(locpctx->pkey, SN_tls1_prf)

+ +            && !EVP_PKEY_is_a(locpctx->pkey, SN_hkdf)) {

+ +        int mdnid = EVP_MD_nid(ctx->reqdigest);

+ +        if (!ossl_ctx_legacy_digest_signatures_allowed(locpctx->libctx, 0)

+ +                && (mdnid == NID_sha1 || mdnid == NID_md5_sha1)) {

+ +            ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_DIGEST);

+ +            goto err;

+ +        }

+ +    }

+ +

+      if (ver) {

+          if (signature->digest_verify_init == NULL) {

+              ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);

+ diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c

+ index 2b9c6c2351..3c5a1e6f5d 100644

+ --- a/crypto/evp/pmeth_lib.c

+ +++ b/crypto/evp/pmeth_lib.c

+ @@ -33,6 +33,7 @@

+  #include "internal/ffc.h"

+  #include "internal/numbers.h"

+  #include "internal/provider.h"

+ +#include "internal/sslconf.h"

+  #include "evp_local.h"

+  

+  #ifndef FIPS_MODULE

+ @@ -946,6 +947,20 @@ static int evp_pkey_ctx_set_md(EVP_PKEY_CTX *ctx, const EVP_MD *md,

+          return -2;

+      }

+  

+ +    if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)

+ +            && md != NULL

+ +            && ctx->pkey != NULL

+ +            && !EVP_PKEY_is_a(ctx->pkey, SN_hmac)

+ +            && !EVP_PKEY_is_a(ctx->pkey, SN_tls1_prf)

+ +            && !EVP_PKEY_is_a(ctx->pkey, SN_hkdf)) {

+ +        int mdnid = EVP_MD_nid(md);

+ +        if ((mdnid == NID_sha1 || mdnid == NID_md5_sha1)

+ +                && !ossl_ctx_legacy_digest_signatures_allowed(ctx->libctx, 0)) {

+ +            ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_DIGEST);

+ +            return -1;

+ +        }

+ +    }

+ +

+      if (fallback)

+          return EVP_PKEY_CTX_ctrl(ctx, -1, op, ctrl, 0, (void *)(md));

+  

+ diff --git a/doc/man5/config.pod b/doc/man5/config.pod

+ index 77a8055e81..0c9110d28a 100644

+ --- a/doc/man5/config.pod

+ +++ b/doc/man5/config.pod

+ @@ -296,6 +296,19 @@ Within the algorithm properties section, the following names have meaning:

+  The value may be anything that is acceptable as a property query

+  string for EVP_set_default_properties().

+  

+ +=item B<rh-allow-sha1-signatures>

+ +

+ +The value is a boolean that can be B<yes> or B<no>.  If the value is not set,

+ +it behaves as if it was set to B<yes>.

+ +

+ +When set to B<no>, any attempt to create or verify a signature with a SHA1

+ +digest will fail.  To test whether your software will work with future versions

+ +of OpenSSL, set this option to B<no>.  This setting also affects TLS, where

+ +signature algorithms that use SHA1 as digest will no longer be supported if

+ +this option is set to B<no>.  Because TLS 1.1 or lower use MD5-SHA1 as

+ +pseudorandom function (PRF) to derive key material, disabling

+ +B<rh-allow-sha1-signatures> requires the use of TLS 1.2 or newer.

+ +

+  =item B<fips_mode> (deprecated)

+  

+  The value is a boolean that can be B<yes> or B<no>.  If the value is

+ diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h

+ index 1291299b6e..e234341e6a 100644

+ --- a/include/internal/cryptlib.h

+ +++ b/include/internal/cryptlib.h

+ @@ -168,7 +168,8 @@ typedef struct ossl_ex_data_global_st {

+  # define OSSL_LIB_CTX_PROVIDER_CONF_INDEX           16

+  # define OSSL_LIB_CTX_BIO_CORE_INDEX                17

+  # define OSSL_LIB_CTX_CHILD_PROVIDER_INDEX          18

+ -# define OSSL_LIB_CTX_MAX_INDEXES                   19

+ +# define OSSL_LIB_CTX_LEGACY_DIGEST_SIGNATURES      19

+ +# define OSSL_LIB_CTX_MAX_INDEXES                   20

+  

+  # define OSSL_LIB_CTX_METHOD_LOW_PRIORITY          -1

+  # define OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY       0

+ diff --git a/include/internal/sslconf.h b/include/internal/sslconf.h

+ index fd7f7e3331..05464b0655 100644

+ --- a/include/internal/sslconf.h

+ +++ b/include/internal/sslconf.h

+ @@ -18,4 +18,8 @@ int conf_ssl_name_find(const char *name, size_t *idx);

+  void conf_ssl_get_cmd(const SSL_CONF_CMD *cmd, size_t idx, char **cmdstr,

+                        char **arg);

+  

+ +/* Methods to support disabling all signatures with legacy digests */

+ +int ossl_ctx_legacy_digest_signatures_allowed(OSSL_LIB_CTX *libctx, int loadconfig);

+ +int ossl_ctx_legacy_digest_signatures_allowed_set(OSSL_LIB_CTX *libctx, int allow,

+ +                                                  int loadconfig);

+  #endif

+ diff --git a/providers/common/securitycheck.c b/providers/common/securitycheck.c

+ index 699ada7c52..e534ad0a5f 100644

+ --- a/providers/common/securitycheck.c

+ +++ b/providers/common/securitycheck.c

+ @@ -19,6 +19,7 @@

+  #include <openssl/core_names.h>

+  #include <openssl/obj_mac.h>

+  #include "prov/securitycheck.h"

+ +#include "internal/sslconf.h"

+  

+  /*

+   * FIPS requires a minimum security strength of 112 bits (for encryption or

+ @@ -235,6 +236,15 @@ int ossl_digest_get_approved_nid_with_sha1(OSSL_LIB_CTX *ctx, const EVP_MD *md,

+              mdnid = -1; /* disallowed by security checks */

+      }

+  # endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */

+ +

+ +#ifndef FIPS_MODULE

+ +    if (!ossl_ctx_legacy_digest_signatures_allowed(ctx, 0))

+ +        /* SHA1 is globally disabled, check whether we want to locally allow

+ +         * it. */

+ +        if (mdnid == NID_sha1 && !sha1_allowed)

+ +            mdnid = -1;

+ +#endif

+ +

+      return mdnid;

+  }

+  

+ @@ -244,5 +254,15 @@ int ossl_digest_is_allowed(OSSL_LIB_CTX *ctx, const EVP_MD *md)

+      if (ossl_securitycheck_enabled(ctx))

+          return ossl_digest_get_approved_nid(md) != NID_undef;

+  # endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */

+ +

+ +#ifndef FIPS_MODULE

+ +    {

+ +        int mdnid = EVP_MD_nid(md);

+ +        if ((mdnid == NID_sha1 || mdnid == NID_md5_sha1)

+ +                && !ossl_ctx_legacy_digest_signatures_allowed(ctx, 0))

+ +            return 0;

+ +    }

+ +#endif

+ +

+      return 1;

+  }

+ diff --git a/providers/common/securitycheck_default.c b/providers/common/securitycheck_default.c

+ index de7f0d3a0a..ce54a94fbc 100644

+ --- a/providers/common/securitycheck_default.c

+ +++ b/providers/common/securitycheck_default.c

+ @@ -15,6 +15,7 @@

+  #include <openssl/obj_mac.h>

+  #include "prov/securitycheck.h"

+  #include "internal/nelem.h"

+ +#include "internal/sslconf.h"

+  

+  /* Disable the security checks in the default provider */

+  int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx)

+ @@ -23,9 +24,10 @@ int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx)

+  }

+  

+  int ossl_digest_rsa_sign_get_md_nid(OSSL_LIB_CTX *ctx, const EVP_MD *md,

+ -                                    ossl_unused int sha1_allowed)

+ +                                    int sha1_allowed)

+  {

+      int mdnid;

+ +    int ldsigs_allowed;

+  

+      static const OSSL_ITEM name_to_nid[] = {

+          { NID_md5,       OSSL_DIGEST_NAME_MD5       },

+ @@ -36,8 +38,11 @@ int ossl_digest_rsa_sign_get_md_nid(OSSL_LIB_CTX *ctx, const EVP_MD *md,

+          { NID_ripemd160, OSSL_DIGEST_NAME_RIPEMD160 },

+      };

+  

+ -    mdnid = ossl_digest_get_approved_nid_with_sha1(ctx, md, 1);

+ +    ldsigs_allowed = ossl_ctx_legacy_digest_signatures_allowed(ctx, 0);

+ +    mdnid = ossl_digest_get_approved_nid_with_sha1(ctx, md, sha1_allowed || ldsigs_allowed);

+      if (mdnid == NID_undef)

+          mdnid = ossl_digest_md_to_nid(md, name_to_nid, OSSL_NELEM(name_to_nid));

+ +    if (mdnid == NID_md5_sha1 && !ldsigs_allowed)

+ +        mdnid = -1;

+      return mdnid;

+  }

+ diff --git a/providers/implementations/signature/dsa_sig.c b/providers/implementations/signature/dsa_sig.c

+ index 28fd7c498e..fa3822f39f 100644

+ --- a/providers/implementations/signature/dsa_sig.c

+ +++ b/providers/implementations/signature/dsa_sig.c

+ @@ -124,12 +124,17 @@ static int dsa_setup_md(PROV_DSA_CTX *ctx,

+          mdprops = ctx->propq;

+  

+      if (mdname != NULL) {

+ -        int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN);

+          WPACKET pkt;

+          EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);

+ -        int md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md,

+ -                                                            sha1_allowed);

+ +        int md_nid;

+          size_t mdname_len = strlen(mdname);

+ +#ifdef FIPS_MODULE

+ +        int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN);

+ +#else

+ +        int sha1_allowed = 0;

+ +#endif

+ +        md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md,

+ +                                                            sha1_allowed);

+  

+          if (md == NULL || md_nid < 0) {

+              if (md == NULL)

+ diff --git a/providers/implementations/signature/ecdsa_sig.c b/providers/implementations/signature/ecdsa_sig.c

+ index 865d49d100..99b228e82c 100644

+ --- a/providers/implementations/signature/ecdsa_sig.c

+ +++ b/providers/implementations/signature/ecdsa_sig.c

+ @@ -237,7 +237,11 @@ static int ecdsa_setup_md(PROV_ECDSA_CTX *ctx, const char *mdname,

+                         "%s could not be fetched", mdname);

+          return 0;

+      }

+ +#ifdef FIPS_MODULE

+      sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN);

+ +#else

+ +    sha1_allowed = 0;

+ +#endif

+      md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md,

+                                                      sha1_allowed);

+      if (md_nid < 0) {

+ diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c

+ index 325e855333..bea397f0c1 100644

+ --- a/providers/implementations/signature/rsa_sig.c

+ +++ b/providers/implementations/signature/rsa_sig.c

+ @@ -26,6 +26,7 @@

+  #include "internal/cryptlib.h"

+  #include "internal/nelem.h"

+  #include "internal/sizes.h"

+ +#include "internal/sslconf.h"

+  #include "crypto/rsa.h"

+  #include "prov/providercommon.h"

+  #include "prov/implementations.h"

+ @@ -34,6 +35,7 @@

+  #include "prov/securitycheck.h"

+  

+  #define RSA_DEFAULT_DIGEST_NAME OSSL_DIGEST_NAME_SHA1

+ +#define RSA_DEFAULT_DIGEST_NAME_NONLEGACY OSSL_DIGEST_NAME_SHA2_256

+  

+  static OSSL_FUNC_signature_newctx_fn rsa_newctx;

+  static OSSL_FUNC_signature_sign_init_fn rsa_sign_init;

+ @@ -289,10 +291,15 @@ static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname,

+  

+      if (mdname != NULL) {

+          EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);

+ +        int md_nid;

+ +        size_t mdname_len = strlen(mdname);

+ +#ifdef FIPS_MODULE

+          int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN);

+ -        int md_nid = ossl_digest_rsa_sign_get_md_nid(ctx->libctx, md,

+ +#else

+ +        int sha1_allowed = 0;

+ +#endif

+ +        md_nid = ossl_digest_rsa_sign_get_md_nid(ctx->libctx, md,

+                                                       sha1_allowed);

+ -        size_t mdname_len = strlen(mdname);

+  

+          if (md == NULL

+              || md_nid <= 0

+ @@ -1348,8 +1355,15 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])

+      prsactx->pad_mode = pad_mode;

+  

+      if (prsactx->md == NULL && pmdname == NULL

+ -        && pad_mode == RSA_PKCS1_PSS_PADDING)

+ +        && pad_mode == RSA_PKCS1_PSS_PADDING) {

+          pmdname = RSA_DEFAULT_DIGEST_NAME;

+ +#ifndef FIPS_MODULE

+ +        if (!ossl_ctx_legacy_digest_signatures_allowed(prsactx->libctx, 0)) {

+ +            pmdname = RSA_DEFAULT_DIGEST_NAME_NONLEGACY;

+ +        }

+ +#endif

+ +    }

+ +

+  

+      if (pmgf1mdname != NULL

+          && !rsa_setup_mgf1_md(prsactx, pmgf1mdname, pmgf1mdprops))

+ diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c

+ index 41fddf22a7..dcd487ec2e 100644

+ --- a/ssl/t1_lib.c

+ +++ b/ssl/t1_lib.c

+ @@ -20,6 +20,7 @@

+  #include <openssl/bn.h>

+  #include <openssl/provider.h>

+  #include <openssl/param_build.h>

+ +#include "internal/sslconf.h"

+  #include "internal/nelem.h"

+  #include "internal/sizes.h"

+  #include "internal/tlsgroups.h"

+ @@ -1145,11 +1146,13 @@ int ssl_setup_sig_algs(SSL_CTX *ctx)

+          = OPENSSL_malloc(sizeof(*lu) * OSSL_NELEM(sigalg_lookup_tbl));

+      EVP_PKEY *tmpkey = EVP_PKEY_new();

+      int ret = 0;

+ +    int ldsigs_allowed;

+  

+      if (cache == NULL || tmpkey == NULL)

+          goto err;

+  

+      ERR_set_mark();

+ +    ldsigs_allowed = ossl_ctx_legacy_digest_signatures_allowed(ctx->libctx, 0);

+      for (i = 0, lu = sigalg_lookup_tbl;

+           i < OSSL_NELEM(sigalg_lookup_tbl); lu++, i++) {

+          EVP_PKEY_CTX *pctx;

+ @@ -1169,6 +1172,11 @@ int ssl_setup_sig_algs(SSL_CTX *ctx)

+              cache[i].enabled = 0;

+              continue;

+          }

+ +        if ((lu->hash == NID_sha1 || lu->hash == NID_md5_sha1)

+ +                && !ldsigs_allowed) {

+ +            cache[i].enabled = 0;

+ +            continue;

+ +        }

+  

+          if (!EVP_PKEY_set_type(tmpkey, lu->sig)) {

+              cache[i].enabled = 0;

+ diff --git a/util/libcrypto.num b/util/libcrypto.num

+ index 10b4e57d79..2d3c363bb0 100644

+ --- a/util/libcrypto.num

+ +++ b/util/libcrypto.num

+ @@ -5426,3 +5426,5 @@ ASN1_item_d2i_ex                        5552	3_0_0	EXIST::FUNCTION:

+  EVP_PKEY_get0_provider                  5554	3_0_0	EXIST::FUNCTION:

+  EVP_PKEY_CTX_get0_provider              5555	3_0_0	EXIST::FUNCTION:

+  ossl_safe_getenv                        ?	3_0_0	EXIST::FUNCTION:

+ +ossl_ctx_legacy_digest_signatures_allowed ?	3_0_1	EXIST::FUNCTION:

+ +ossl_ctx_legacy_digest_signatures_allowed_set ?	3_0_1	EXIST::FUNCTION:

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,217 @@ 

+ From f695f140255f9b564cac4d5e9e38ba27ec927256 Mon Sep 17 00:00:00 2001

+ From: Clemens Lang <cllang@redhat.com>

+ Date: Tue, 1 Mar 2022 15:44:18 +0100

+ Subject: [PATCH 2/2] Allow SHA1 in seclevel 1 if rh-allow-sha1-signatures =

+  yes

+ 

+ NOTE: This patch is ported from CentOS 9 / RHEL 9, where it allows SHA1

+ in seclevel 2 if rh-allow-sha1-signatures = yes. This was chosen because

+ on CentOS 9 and RHEL 9, the LEGACY crypto policy sets the security level

+ to 2.

+ 

+ On Fedora 35 (with OpenSSL 1.1) the legacy crypto policy uses security

+ level 1. Because Fedora 36 supports both OpenSSL 1.1 and OpenSSL 3, and

+ we want the legacy crypto policy to allow SHA-1 in TLS, the only option

+ to make this happen consistently in both OpenSSL 1.1 and OpenSSL 3 is

+ SECLEVEL=1 (which will allow SHA-1 in OpenSSL 1.1) and this change to

+ allow SHA-1 in SECLEVEL=1 with rh-allow-sha1-signatures = yes (which

+ will allow SHA-1 in OpenSSL 3).

+ 

+ The change from CentOS 9 / RHEL 9 cannot be applied unmodified, because

+ rh-allow-sha1-signatures will default to yes in Fedora (according to our

+ current plans including until F38), and the security level in the

+ DEFAULT crypto policy is 2, i.e., the unmodified change would weaken the

+ default configuration.

+ 

+ Related: rhbz#2055796

+ Related: rhbz#2070977

+ ---

+  crypto/x509/x509_vfy.c        | 19 ++++++++++-

+  doc/man5/config.pod           |  7 ++++

+  ssl/t1_lib.c                  | 64 ++++++++++++++++++++++++++++-------

+  test/recipes/25-test_verify.t |  4 +--

+  4 files changed, 78 insertions(+), 16 deletions(-)

+ 

+ diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c

+ index 2f175ca517..60aa26f552 100644

+ --- a/crypto/x509/x509_vfy.c

+ +++ b/crypto/x509/x509_vfy.c

+ @@ -25,6 +25,7 @@

+  #include <openssl/objects.h>

+  #include <openssl/core_names.h>

+  #include "internal/dane.h"

+ +#include "internal/sslconf.h"

+  #include "crypto/x509.h"

+  #include "x509_local.h"

+  

+ @@ -3441,14 +3442,30 @@ static int check_sig_level(X509_STORE_CTX *ctx, X509 *cert)

+  {

+      int secbits = -1;

+      int level = ctx->param->auth_level;

+ +    int nid;

+ +    OSSL_LIB_CTX *libctx = NULL;

+  

+      if (level <= 0)

+          return 1;

+      if (level > NUM_AUTH_LEVELS)

+          level = NUM_AUTH_LEVELS;

+  

+ -    if (!X509_get_signature_info(cert, NULL, NULL, &secbits, NULL))

+ +    if (ctx->libctx)

+ +        libctx = ctx->libctx;

+ +    else if (cert->libctx)

+ +        libctx = cert->libctx;

+ +    else

+ +        libctx = OSSL_LIB_CTX_get0_global_default();

+ +

+ +    if (!X509_get_signature_info(cert, &nid, NULL, &secbits, NULL))

+          return 0;

+  

+ +    if (nid == NID_sha1

+ +            && ossl_ctx_legacy_digest_signatures_allowed(libctx, 0)

+ +            && ctx->param->auth_level < 2)

+ +        /* When rh-allow-sha1-signatures = yes and security level <= 1,

+ +         * explicitly allow SHA1 for backwards compatibility. */

+ +        return 1;

+ +

+      return secbits >= minbits_table[level - 1];

+  }

+ diff --git a/doc/man5/config.pod b/doc/man5/config.pod

+ index 0c9110d28a..02e7ca706f 100644

+ --- a/doc/man5/config.pod

+ +++ b/doc/man5/config.pod

+ @@ -309,6 +309,13 @@ this option is set to B<no>.  Because TLS 1.1 or lower use MD5-SHA1 as

+  pseudorandom function (PRF) to derive key material, disabling

+  B<rh-allow-sha1-signatures> requires the use of TLS 1.2 or newer.

+  

+ +Note that enabling B<rh-allow-sha1-signatures> will allow TLS signature

+ +algorithms that use SHA1 in security level 1, despite the definition of

+ +security level 1 of FIXME bits of security, which SHA1 does not meet.  This

+ +allows using SHA1 in TLS in the LEGACY crypto-policy on Fedora without

+ +requiring to set the security level to 0, which would include further insecure

+ +algorithms.

+ +

+  =item B<fips_mode> (deprecated)

+  

+  The value is a boolean that can be B<yes> or B<no>.  If the value is

+ diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c

+ index dcd487ec2e..e47ddf56f1 100644

+ --- a/ssl/t1_lib.c

+ +++ b/ssl/t1_lib.c

+ @@ -20,6 +20,7 @@

+  #include <openssl/bn.h>

+  #include <openssl/provider.h>

+  #include <openssl/param_build.h>

+ +#include "crypto/x509.h"

+  #include "internal/sslconf.h"

+  #include "internal/nelem.h"

+  #include "internal/sizes.h"

+ @@ -1561,19 +1562,27 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)

+          SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_UNKNOWN_DIGEST);

+          return 0;

+      }

+ -    /*

+ -     * Make sure security callback allows algorithm. For historical

+ -     * reasons we have to pass the sigalg as a two byte char array.

+ -     */

+ -    sigalgstr[0] = (sig >> 8) & 0xff;

+ -    sigalgstr[1] = sig & 0xff;

+ -    secbits = sigalg_security_bits(s->ctx, lu);

+ -    if (secbits == 0 ||

+ -        !ssl_security(s, SSL_SECOP_SIGALG_CHECK, secbits,

+ -                      md != NULL ? EVP_MD_get_type(md) : NID_undef,

+ -                      (void *)sigalgstr)) {

+ -        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_WRONG_SIGNATURE_TYPE);

+ -        return 0;

+ +

+ +    if (lu->hash == NID_sha1

+ +            && ossl_ctx_legacy_digest_signatures_allowed(s->ctx->libctx, 0)

+ +            && SSL_get_security_level(s) < 2) {

+ +        /* when rh-allow-sha1-signatures = yes and security level <= 1,

+ +         * explicitly allow SHA1 for backwards compatibility */

+ +    } else {

+ +        /*

+ +         * Make sure security callback allows algorithm. For historical

+ +         * reasons we have to pass the sigalg as a two byte char array.

+ +         */

+ +        sigalgstr[0] = (sig >> 8) & 0xff;

+ +        sigalgstr[1] = sig & 0xff;

+ +        secbits = sigalg_security_bits(s->ctx, lu);

+ +        if (secbits == 0 ||

+ +            !ssl_security(s, SSL_SECOP_SIGALG_CHECK, secbits,

+ +                          md != NULL ? EVP_MD_get_type(md) : NID_undef,

+ +                          (void *)sigalgstr)) {

+ +            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_WRONG_SIGNATURE_TYPE);

+ +            return 0;

+ +        }

+      }

+      /* Store the sigalg the peer uses */

+      s->s3.tmp.peer_sigalg = lu;

+ @@ -2106,6 +2115,14 @@ static int tls12_sigalg_allowed(const SSL *s, int op, const SIGALG_LOOKUP *lu)

+          }

+      }

+  

+ +    if (lu->hash == NID_sha1

+ +            && ossl_ctx_legacy_digest_signatures_allowed(s->ctx->libctx, 0)

+ +            && SSL_get_security_level(s) < 2) {

+ +        /* when rh-allow-sha1-signatures = yes and security level <= 1,

+ +         * explicitly allow SHA1 for backwards compatibility */

+ +        return 1;

+ +    }

+ +

+      /* Finally see if security callback allows it */

+      secbits = sigalg_security_bits(s->ctx, lu);

+      sigalgstr[0] = (lu->sigalg >> 8) & 0xff;

+ @@ -2977,6 +2994,8 @@ static int ssl_security_cert_sig(SSL *s, SSL_CTX *ctx, X509 *x, int op)

+  {

+      /* Lookup signature algorithm digest */

+      int secbits, nid, pknid;

+ +    OSSL_LIB_CTX *libctx = NULL;

+ +

+      /* Don't check signature if self signed */

+      if ((X509_get_extension_flags(x) & EXFLAG_SS) != 0)

+          return 1;

+ @@ -2985,6 +3004,25 @@ static int ssl_security_cert_sig(SSL *s, SSL_CTX *ctx, X509 *x, int op)

+      /* If digest NID not defined use signature NID */

+      if (nid == NID_undef)

+          nid = pknid;

+ +

+ +    if (x && x->libctx)

+ +        libctx = x->libctx;

+ +    else if (ctx && ctx->libctx)

+ +        libctx = ctx->libctx;

+ +    else if (s && s->ctx && s->ctx->libctx)

+ +        libctx = s->ctx->libctx;

+ +    else

+ +        libctx = OSSL_LIB_CTX_get0_global_default();

+ +

+ +    if (nid == NID_sha1

+ +            && ossl_ctx_legacy_digest_signatures_allowed(libctx, 0)

+ +            && ((s != NULL && SSL_get_security_level(s) < 2)

+ +                || (ctx != NULL && SSL_CTX_get_security_level(ctx) < 2)

+ +            ))

+ +        /* When rh-allow-sha1-signatures = yes and security level <= 1,

+ +         * explicitly allow SHA1 for backwards compatibility. */

+ +        return 1;

+ +

+      if (s)

+          return ssl_security(s, op, secbits, nid, x);

+      else

+ diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t

+ index 700bbd849c..280477bc9d 100644

+ --- a/test/recipes/25-test_verify.t

+ +++ b/test/recipes/25-test_verify.t

+ @@ -387,8 +387,8 @@ ok(verify("ee-pss-sha1-cert", "", ["root-cert"], ["ca-cert"], "-auth_level", "0"

+  ok(verify("ee-pss-sha256-cert", "", ["root-cert"], ["ca-cert"], ),

+      "CA with PSS signature using SHA256");

+  

+ -ok(!verify("ee-pss-sha1-cert", "", ["root-cert"], ["ca-cert"], "-auth_level", "1"),

+ -    "Reject PSS signature using SHA1 and auth level 1");

+ +ok(!verify("ee-pss-sha1-cert", "", ["root-cert"], ["ca-cert"], "-auth_level", "2"),

+ +    "Reject PSS signature using SHA1 and auth level 2");

+  

+  ok(verify("ee-pss-sha256-cert", "", ["root-cert"], ["ca-cert"], "-auth_level", "2"),

+      "PSS signature using SHA256 and auth level 2");

+ -- 

+ 2.35.1

+ 

file added
+9
@@ -0,0 +1,9 @@ 

+ # capi.so is a dummy only used on Windows, it doesn't need dependency information

+ addFilter("E: shared-lib(rary)?-without-dependency-information /usr/lib64/engines-3/capi.so")

+ 

+ # The sources are hobbled and thus not a valid URL. That's expected.

+ addFilter("W: invalid-url Source0: openssl-[0-9\\.]+-hobbled.tar.gz")

+ 

+ # Technically this warning is correct, but in the case of the openssl binary we

+ # want to allow SSL_CTX_set_cipher_list

+ addFilter("W: crypto-policy-non-compliance-openssl /usr/bin/openssl SSL_CTX_set_cipher_list")

file modified
+17 -1
@@ -15,7 +15,7 @@ 

  Summary: Utilities from the general purpose cryptography library with TLS implementation

  Name: openssl

  Version: 3.0.2

- Release: 1%{?dist}

+ Release: 2%{?dist}

  Epoch: 1

  # We have to remove certain patented algorithms from the openssl source

  # tarball with the hobble-openssl script which is included below.
@@ -24,6 +24,7 @@ 

  Source1: hobble-openssl

  Source2: Makefile.certificate

  Source3: genpatches

+ Source4: openssl.rpmlintrc

  Source6: make-dummy-cert

  Source7: renew-dummy-cert

  Source9: configuration-switch.h
@@ -56,8 +57,12 @@ 

  Patch12: 0012-Disable-explicit-ec.patch

  # Instructions to load legacy provider in openssl.cnf

  Patch24: 0024-load-legacy-prov.patch

+ # Selectively disallow SHA1 signatures rhbz#2070977

+ Patch49: 0049-Allow-disabling-of-SHA1-signatures.patch

  # Backport of patch for RHEL for Edge rhbz #2027261

  Patch51: 0051-Support-different-R_BITS-lengths-for-KBKDF.patch

+ # Support SHA1 in TLS in LEGACY crypto-policy (which is SECLEVEL=1)

+ Patch52: 0052-Allow-SHA1-in-seclevel-1-if-rh-allow-sha1-signatures.patch

  

  License: ASL 2.0

  URL: http://www.openssl.org/
@@ -384,6 +389,17 @@ 

  %ldconfig_scriptlets libs

  

  %changelog

+ * Thu Apr 07 2022 Clemens Lang <cllang@redhat.com> - 1:3.0.2-2

+ - Silence a few rpmlint false positives.

+ 

+ * Thu Apr 07 2022 Clemens Lang <cllang@redhat.com> - 1:3.0.2-2

+ - Allow disabling SHA1 signature creation and verification.

+   Set rh-allow-sha1-signatures = no to disable.

+   Allow SHA1 in TLS in SECLEVEL 1 if rh-allow-sha1-signatures = yes. This will

+   support SHA1 in TLS in the LEGACY crypto-policy.

+   Resolves: rhbz#2070977, rhbz#2071615

+   Related: rhbz#2031742, rhbz#2062640

+ 

  * Fri Mar 18 2022 Dmitry Belyavskiy <dbelyavs@redhat.com> - 1:3.0.2-1

  - Rebase to upstream version 3.0.2

  

NOTE: This patch is ported from CentOS 9 / RHEL 9, where it defaults to
denying SHA1 signatures. On Fedora, the default is – for now – to allow
SHA1 signatures.

In order to phase out SHA1 signatures, introduce a new configuration
option in the alg_section named 'rh-allow-sha1-signatures'. This option
defaults to true. If set to false, any signature creation or
verification operations that involve SHA1 as digest will fail.

This also affects TLS, where the signature_algorithms extension of any
ClientHello message sent by OpenSSL will no longer include signatures
with the SHA1 digest if rh-allow-sha1-signatures is false. For servers
that request a client certificate, the same also applies for
CertificateRequest messages sent by them.

(cherry picked from commit 05fc78f)

Resolves: rhbz#2070977
Resolves: rhbz#2071615
Related: rhbz#2031742, rhbz#2062640
Signed-off-by: Clemens Lang cllang@redhat.com

Build failed. More information on how to proceed and troubleshoot errors available at https://fedoraproject.org/wiki/Zuul-based-ci

2 new commits added

  • Silence rpmlint false positives
  • Allow disabling of SHA1 signatures
10 months ago

Build succeeded.

rebased onto 2fdd24a

10 months ago

Build succeeded.

Pull-Request has been merged by clang

10 months ago