+
+#ifndef OPENSSL_NO_DH
+DH *ssl_get_auto_dh(SSL *s)
+ {
+ int dh_secbits = 80;
+ if (s->cert->dh_tmp_auto == 2)
+ return DH_get_1024_160();
+ if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+ {
+ if (s->s3->tmp.new_cipher->strength_bits == 256)
+ dh_secbits = 128;
+ else
+ dh_secbits = 80;
+ }
+ else
+ {
+ CERT_PKEY *cpk = ssl_get_server_send_pkey(s);
+ dh_secbits = EVP_PKEY_security_bits(cpk->privatekey);
+ }
+
+ if (dh_secbits >= 128)
+ {
+ DH *dhp = DH_new();
+ if (!dhp)
+ return NULL;
+ dhp->g = BN_new();
+ if (dhp->g)
+ BN_set_word(dhp->g, 2);
+ if (dh_secbits >= 192)
+ dhp->p = get_rfc3526_prime_8192(NULL);
+ else
+ dhp->p = get_rfc3526_prime_3072(NULL);
+ if (!dhp->p || !dhp->g)
+ {
+ DH_free(dhp);
+ return NULL;
+ }
+ return dhp;
+ }
+ if (dh_secbits >= 112)
+ return DH_get_2048_224();
+ return DH_get_1024_160();
+ }
+#endif
+
+static int ssl_security_cert_key(SSL *s, SSL_CTX *ctx, X509 *x, int op)
+ {
+ int secbits;
+ EVP_PKEY *pkey = X509_get_pubkey(x);
+ if (pkey)
+ {
+ secbits = EVP_PKEY_security_bits(pkey);
+ EVP_PKEY_free(pkey);
+ }
+ else
+ secbits = -1;
+ if (s)
+ return ssl_security(s, op, secbits, 0, x);
+ else
+ return ssl_ctx_security(ctx, op, secbits, 0, x);
+ }
+
+static int ssl_security_cert_sig(SSL *s, SSL_CTX *ctx, X509 *x, int op)
+ {
+ /* Lookup signature algorithm digest */
+ int secbits = -1, md_nid = NID_undef, sig_nid;
+ sig_nid = X509_get_signature_nid(x);
+ if (sig_nid && OBJ_find_sigid_algs(sig_nid, &md_nid, NULL))
+ {
+ const EVP_MD *md;
+ if (md_nid && (md = EVP_get_digestbynid(md_nid)))
+ secbits = EVP_MD_size(md) * 4;
+ }
+ if (s)
+ return ssl_security(s, op, secbits, md_nid, x);
+ else
+ return ssl_ctx_security(ctx, op, secbits, md_nid, x);
+ }
+
+int ssl_security_cert(SSL *s, SSL_CTX *ctx, X509 *x, int vfy, int is_ee)
+ {
+ if (vfy)
+ vfy = SSL_SECOP_PEER;
+ if (is_ee)
+ {
+ if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_EE_KEY | vfy))
+ return SSL_R_EE_KEY_TOO_SMALL;
+ }
+ else
+ {
+ if (!ssl_security_cert_key(s, ctx, x, SSL_SECOP_CA_KEY | vfy))
+ return SSL_R_CA_KEY_TOO_SMALL;
+ }
+ if (!ssl_security_cert_sig(s, ctx, x, SSL_SECOP_CA_MD | vfy))
+ return SSL_R_CA_MD_TOO_WEAK;
+ return 1;
+ }
+
+/* Check security of a chain, if sk includes the end entity certificate
+ * then x is NULL. If vfy is 1 then we are verifying a peer chain and
+ * not sending one to the peer.
+ * Return values: 1 if ok otherwise error code to use
+ */
+
+int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *x, int vfy)
+ {
+ int rv, start_idx, i;
+ if (x == NULL)
+ {
+ x = sk_X509_value(sk, 0);
+ start_idx = 1;
+ }
+ else
+ start_idx = 0;
+
+ rv = ssl_security_cert(s, NULL, x, vfy, 1);
+ if (rv != 1)
+ return rv;
+
+ for (i = start_idx; i < sk_X509_num(sk); i++)
+ {
+ x = sk_X509_value(sk, i);
+ rv = ssl_security_cert(s, NULL, x, vfy, 0);
+ if (rv != 1)
+ return rv;
+ }
+ return 1;
+ }