diff -up openssl-1.0.2j/crypto/asn1/a_verify.c.deprecate-algos openssl-1.0.2j/crypto/asn1/a_verify.c --- openssl-1.0.2j/crypto/asn1/a_verify.c.deprecate-algos 2016-09-26 11:49:07.000000000 +0200 +++ openssl-1.0.2j/crypto/asn1/a_verify.c 2017-01-09 16:47:11.666994197 +0100 @@ -56,6 +56,9 @@ * [including the GNU Public Licence.] */ +/* for secure_getenv */ +#define _GNU_SOURCE + #include #include @@ -133,6 +136,30 @@ int ASN1_verify(i2d_of_void *i2d, X509_A #endif +static int legacy_mds[] = { NID_md5, NID_sha, NID_md4, NID_md2, 0 }; +extern int private_ossl_allowed_legacy_mds[]; + +static int is_md_legacy_disallowed(int mdnid) +{ + int i; + + if (mdnid == NID_md5 && secure_getenv("OPENSSL_ENABLE_MD5_VERIFY") != NULL) + return 0; + + for (i = 0; legacy_mds[i] != 0; ++i) { + if (mdnid == legacy_mds[i]) { + int j; + + for (j = 0; private_ossl_allowed_legacy_mds[j] != 0; ++j) { + if (mdnid == private_ossl_allowed_legacy_mds[j]) + return 0; + } + return 1; + } + } + return 0; +} + int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey) { @@ -174,6 +201,10 @@ int ASN1_item_verify(const ASN1_ITEM *it if (ret != 2) goto err; ret = -1; + } else if (is_md_legacy_disallowed(mdnid)) { + ASN1err(ASN1_F_ASN1_ITEM_VERIFY, + ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); + goto err; } else { const EVP_MD *type; type = EVP_get_digestbynid(mdnid); diff -up openssl-1.0.2j/crypto/o_init.c.deprecate-algos openssl-1.0.2j/crypto/o_init.c --- openssl-1.0.2j/crypto/o_init.c.deprecate-algos 2017-01-05 17:49:00.000000000 +0100 +++ openssl-1.0.2j/crypto/o_init.c 2017-01-09 16:52:29.018298611 +0100 @@ -64,11 +64,21 @@ # include # include # include +# include +# include +# include +# include # include # include +# include +# include # define FIPS_MODE_SWITCH_FILE "/proc/sys/crypto/fips_enabled" +# define LEGACY_SETTINGS_FILE "/etc/pki/tls/legacy-settings" + +# define NUM_MAX_LEGACY_MDS 8 + static void init_fips_mode(void) { char buf[2] = "0"; @@ -98,6 +108,115 @@ static void init_fips_mode(void) } #endif +int private_ossl_allowed_legacy_mds[NUM_MAX_LEGACY_MDS + 1]; /* zero terminated */ + +int private_ossl_minimum_dh_bits; + +static void parse_legacy_mds(char *p) +{ + int idx = 0; + char *e = p; + + while (p[0] != '\0') { + while (e[0] != '\0' && !isspace(e[0]) && e[0] != ',') { + ++e; + } + if (e[0] != '\0') { + e[0] = '\0'; + ++e; + } + + if (strcasecmp(p, "md5") == 0) { + private_ossl_allowed_legacy_mds[idx++] = NID_md5; + } else if (strcasecmp(p, "md4") == 0) { + private_ossl_allowed_legacy_mds[idx++] = NID_md4; + } else if (strcasecmp(p, "sha") == 0) { + private_ossl_allowed_legacy_mds[idx++] = NID_sha; + } else if (strcasecmp(p, "md2") == 0) { + private_ossl_allowed_legacy_mds[idx++] = NID_md2; + } + + if (idx >= + sizeof(private_ossl_allowed_legacy_mds) / + sizeof(private_ossl_allowed_legacy_mds[0])) { + break; + } + + while (e[0] == ',' || isspace(e[0])) { + ++e; + } + + p = e; + } +} + +static void parse_minimum_dh_bits(char *p) +{ + private_ossl_minimum_dh_bits = strtol(p, NULL, 10); + if (private_ossl_minimum_dh_bits < 512 + || private_ossl_minimum_dh_bits > OPENSSL_DH_MAX_MODULUS_BITS) { + /* use default */ + private_ossl_minimum_dh_bits = 0; + } +} + +static void load_legacy_settings(void) +{ + FILE *f; + char *line = NULL; + size_t len = 0; + + if ((f = fopen(LEGACY_SETTINGS_FILE, "r")) == NULL) { + return; + } + + while (getline(&line, &len, f) > 0) { + char *p = line, *e, *val; + + /* skip initial whitespace */ + while (isspace(p[0])) { + ++p; + } + + e = p; + + while (e[0] != '\0' && !isspace(e[0])) { + ++e; + } + + /* terminate name, skip whitespace between name and value */ + if (e[0] != '\0') { + e[0] = '\0'; + ++e; + while (isspace(e[0])) { + ++e; + } + } + + val = e; + + e = e + strlen(val); + + /* trim terminating whitespace */ + while (e > val) { + --e; + if (isspace(e[0])) { + e[0] = '\0'; + } else { + break; + } + } + + if (strcasecmp(p, "LegacySigningMDs") == 0) { + parse_legacy_mds(val); + } else if (strcasecmp(line, "MinimumDHBits") == 0) { + parse_minimum_dh_bits(val); + } + /* simply skip other unrecognized lines */ + } + (void)fclose(f); +} + /* * Perform any essential OpenSSL initialization operations. Currently only * sets FIPS callbacks @@ -109,6 +228,7 @@ void __attribute__ ((constructor)) OPENS if (done) return; done = 1; + load_legacy_settings(); #ifdef OPENSSL_FIPS if (!FIPS_module_installed()) { return; diff -up openssl-1.0.2j/ssl/s3_clnt.c.deprecate-algos openssl-1.0.2j/ssl/s3_clnt.c --- openssl-1.0.2j/ssl/s3_clnt.c.deprecate-algos 2016-09-26 11:49:07.000000000 +0200 +++ openssl-1.0.2j/ssl/s3_clnt.c 2017-01-09 17:01:19.428506961 +0100 @@ -3478,6 +3478,8 @@ int ssl3_send_client_certificate(SSL *s) #define has_bits(i,m) (((i)&(m)) == (m)) +extern int private_ossl_minimum_dh_bits; + int ssl3_check_cert_and_algorithm(SSL *s) { int i, idx; @@ -3608,8 +3610,7 @@ int ssl3_check_cert_and_algorithm(SSL *s DH_free(dh_srvr); } - if ((!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 1024) - || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 512)) { + if (dh_size < (private_ossl_minimum_dh_bits ? private_ossl_minimum_dh_bits : 1024)) { SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_DH_KEY_TOO_SMALL); goto f_err; }