static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
const unsigned char *sess_id, int sesslen,
SSL_SESSION **psess);
+static int ssl_check_clienthello_tlsext_early(SSL *s);
+int ssl_check_serverhello_tlsext(SSL *s);
#endif
SSL3_ENC_METHOD TLSv1_enc_data={
0,17, /* secp160r2 (17) */
};
+static const unsigned char suiteb_curves[] =
+ {
+ 0, TLSEXT_curve_P_256,
+ 0, TLSEXT_curve_P_384
+ };
+
int tls1_ec_curve_id2nid(int curve_id)
{
/* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
{
*pcurves = s->session->tlsext_ellipticcurvelist;
*pcurveslen = s->session->tlsext_ellipticcurvelist_length;
+ return;
}
- else
+ /* For Suite B mode only include P-256, P-384 */
+ switch (tls1_suiteb(s))
{
+ case SSL_CERT_FLAG_SUITEB_128_LOS:
+ *pcurves = suiteb_curves;
+ *pcurveslen = sizeof(suiteb_curves);
+ break;
+
+ case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+ *pcurves = suiteb_curves;
+ *pcurveslen = 2;
+ break;
+
+ case SSL_CERT_FLAG_SUITEB_192_LOS:
+ *pcurves = suiteb_curves + 2;
+ *pcurveslen = 2;
+ break;
+ default:
*pcurves = s->tlsext_ellipticcurvelist;
*pcurveslen = s->tlsext_ellipticcurvelist_length;
}
- /* If not set use default: for now static structure */
if (!*pcurves)
{
*pcurves = eccurves_default;
*pcurveslen = sizeof(eccurves_default);
}
}
+/* Check a curve is one of our preferences */
+int tls1_check_curve(SSL *s, const unsigned char *p, size_t len)
+ {
+ const unsigned char *curves;
+ size_t curveslen, i;
+ unsigned int suiteb_flags = tls1_suiteb(s);
+ if (len != 3 || p[0] != NAMED_CURVE_TYPE)
+ return 0;
+ /* Check curve matches Suite B preferences */
+ if (suiteb_flags)
+ {
+ unsigned long cid = s->s3->tmp.new_cipher->id;
+ if (p[1])
+ return 0;
+ if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+ {
+ if (p[2] != TLSEXT_curve_P_256)
+ return 0;
+ }
+ else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+ {
+ if (p[2] != TLSEXT_curve_P_384)
+ return 0;
+ }
+ else /* Should never happen */
+ return 0;
+ }
+ tls1_get_curvelist(s, 0, &curves, &curveslen);
+ for (i = 0; i < curveslen; i += 2, curves += 2)
+ {
+ if (p[1] == curves[0] && p[2] == curves[1])
+ return 1;
+ }
+ return 0;
+ }
-/* Return any common values from two lists. One list is used as a
- * preference list where we return the most preferred match.
+/* Return nth shared curve. If nmatch == -1 return number of
+ * matches. For nmatch == -2 return the NID of the curve to use for
+ * an EC tmp key.
*/
-int tls1_shared_list(SSL *s,
- const unsigned char *l1, size_t l1len,
- const unsigned char *l2, size_t l2len,
- int nmatch)
+
+int tls1_shared_curve(SSL *s, int nmatch)
{
const unsigned char *pref, *supp;
size_t preflen, supplen, i, j;
int k;
- l1len /= 2;
- l2len /= 2;
- if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
- {
- pref = l1;
- preflen = l1len;
- supp = l2;
- supplen = l2len;
- }
- else
+ /* Can't do anything on client side */
+ if (s->server == 0)
+ return -1;
+ if (nmatch == -2)
{
- supp = l1;
- supplen = l1len;
- pref = l2;
- preflen = l2len;
+ if (tls1_suiteb(s))
+ {
+ /* For Suite B ciphersuite determines curve: we
+ * already know these are acceptable due to previous
+ * checks.
+ */
+ unsigned long cid = s->s3->tmp.new_cipher->id;
+ if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+ return NID_X9_62_prime256v1; /* P-256 */
+ if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+ return NID_secp384r1; /* P-384 */
+ /* Should never happen */
+ return NID_undef;
+ }
+ /* If not Suite B just return first preference shared curve */
+ nmatch = 0;
}
+ tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
+ &supp, &supplen);
+ tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
+ &pref, &preflen);
+ preflen /= 2;
+ supplen /= 2;
k = 0;
for (i = 0; i < preflen; i++, pref+=2)
{
if (pref[0] == tsupp[0] && pref[1] == tsupp[1])
{
if (nmatch == k)
- return (pref[0] << 8) | pref[1];
+ {
+ int id = (pref[0] << 8) | pref[1];
+ return tls1_ec_curve_id2nid(id);
+ }
k++;
}
}
}
- if (nmatch == -1 && k > 0)
- return k;
- return -1;
- }
-
-int tls1_shared_curve(SSL *s, int nmatch)
- {
- const unsigned char *l1, *l2;
- size_t l1len, l2len;
- int id;
- /* Can't do anything on client side */
- if (s->server == 0)
- return -1;
- /* Get supported curves */
- tls1_get_curvelist(s, 0, &l1, &l1len);
- tls1_get_curvelist(s, 1, &l2, &l2len);
-
- id = tls1_shared_list(s, l1, l1len, l2, l2len, nmatch);
if (nmatch == -1)
- return id;
- return tls1_ec_curve_id2nid(id);
+ return k;
+ return 0;
}
int tls1_set_curves(unsigned char **pext, size_t *pextlen,
ncb.nidcnt = 0;
if (!CONF_parse_list(str, ':', 1, nid_cb, &ncb))
return 0;
+ if (pext == NULL)
+ return 1;
return tls1_set_curves(pext, pextlen, ncb.nid_arr, ncb.nidcnt);
}
/* For an EC key set TLS id and required compression based on parameters */
{
const unsigned char *p;
size_t plen, i;
+ int j;
/* If point formats extension present check it, otherwise everything
* is supported (see RFC4492).
*/
if (i == plen)
return 0;
}
- /* If curve list present check it, otherwise everything is
- * supported.
- */
- if (s->session->tlsext_ellipticcurvelist)
+ if (!curve_id)
+ return 1;
+ /* Check curve is consistent with client and server preferences */
+ for (j = 0; j <= 1; j++)
{
- p = s->session->tlsext_ellipticcurvelist;
- plen = s->session->tlsext_ellipticcurvelist_length;
+ tls1_get_curvelist(s, j, &p, &plen);
for (i = 0; i < plen; i+=2, p+=2)
{
if (p[0] == curve_id[0] && p[1] == curve_id[1])
- return 1;
+ break;
}
- return 0;
+ if (i == plen)
+ return 0;
+ /* For clients can only check sent curve list */
+ if (!s->server)
+ return 1;
}
return 1;
}
-/* Check EC server key is compatible with client extensions */
-int tls1_check_ec_server_key(SSL *s)
+
+static void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+ size_t *pformatslen)
+ {
+ /* If we have a custom point format list use it otherwise
+ * use default */
+ if (s->tlsext_ecpointformatlist)
+ {
+ *pformats = s->tlsext_ecpointformatlist;
+ *pformatslen = s->tlsext_ecpointformatlist_length;
+ }
+ else
+ {
+ *pformats = ecformats_default;
+ /* For Suite B we don't support char2 fields */
+ if (tls1_suiteb(s))
+ *pformatslen = sizeof(ecformats_default) - 1;
+ else
+ *pformatslen = sizeof(ecformats_default);
+ }
+ }
+
+/* Check cert parameters compatible with extensions: currently just checks
+ * EC certificates have compatible curves and compression.
+ */
+static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
{
- int rv;
- CERT_PKEY *cpk = s->cert->pkeys + SSL_PKEY_ECC;
- EVP_PKEY *pkey;
unsigned char comp_id, curve_id[2];
- if (!cpk->x509 || !cpk->privatekey)
- return 0;
- pkey = X509_get_pubkey(cpk->x509);
+ EVP_PKEY *pkey;
+ int rv;
+ pkey = X509_get_pubkey(x);
if (!pkey)
return 0;
+ /* If not EC nothing to do */
+ if (pkey->type != EVP_PKEY_EC)
+ {
+ EVP_PKEY_free(pkey);
+ return 1;
+ }
rv = tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec);
EVP_PKEY_free(pkey);
if (!rv)
return 0;
- return tls1_check_ec_key(s, curve_id, &comp_id);
+ /* Can't check curve_id for client certs as we don't have a
+ * supported curves extension.
+ */
+ rv = tls1_check_ec_key(s, s->server ? curve_id : NULL, &comp_id);
+ if (!rv)
+ return 0;
+ /* Special case for suite B. We *MUST* sign using SHA256+P-256 or
+ * SHA384+P-384, adjust digest if necessary.
+ */
+ if (set_ee_md && tls1_suiteb(s))
+ {
+ int check_md;
+ size_t i;
+ CERT *c = s->cert;
+ if (curve_id[0])
+ return 0;
+ /* Check to see we have necessary signing algorithm */
+ if (curve_id[1] == TLSEXT_curve_P_256)
+ check_md = NID_ecdsa_with_SHA256;
+ else if (curve_id[1] == TLSEXT_curve_P_384)
+ check_md = NID_ecdsa_with_SHA384;
+ else
+ return 0; /* Should never happen */
+ for (i = 0; i < c->shared_sigalgslen; i++)
+ if (check_md == c->shared_sigalgs[i].signandhash_nid)
+ break;
+ if (i == c->shared_sigalgslen)
+ return 0;
+ if (set_ee_md == 2)
+ {
+ if (check_md == NID_ecdsa_with_SHA256)
+ c->pkeys[SSL_PKEY_ECC].digest = EVP_sha256();
+ else
+ c->pkeys[SSL_PKEY_ECC].digest = EVP_sha384();
+ }
+ }
+ return rv;
}
/* Check EC temporary key is compatible with client extensions */
-int tls1_check_ec_tmp_key(SSL *s)
+int tls1_check_ec_tmp_key(SSL *s, unsigned long cid)
{
unsigned char curve_id[2];
EC_KEY *ec = s->cert->ecdh_tmp;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+ /* Allow any curve: not just those peer supports */
+ if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
+ return 1;
+#endif
+ /* If Suite B, AES128 MUST use P-256 and AES256 MUST use P-384,
+ * no other curves permitted.
+ */
+ if (tls1_suiteb(s))
+ {
+ /* Curve to check determined by ciphersuite */
+ if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+ curve_id[1] = TLSEXT_curve_P_256;
+ else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+ curve_id[1] = TLSEXT_curve_P_384;
+ else
+ return 0;
+ curve_id[0] = 0;
+ /* Check this curve is acceptable */
+ if (!tls1_check_ec_key(s, curve_id, NULL))
+ return 0;
+ /* If auto or setting curve from callback assume OK */
+ if (s->cert->ecdh_tmp_auto || s->cert->ecdh_tmp_cb)
+ return 1;
+ /* Otherwise check curve is acceptable */
+ else
+ {
+ unsigned char curve_tmp[2];
+ if (!ec)
+ return 0;
+ if (!tls1_set_ec_id(curve_tmp, NULL, ec))
+ return 0;
+ if (!curve_tmp[0] || curve_tmp[1] == curve_id[1])
+ return 1;
+ return 0;
+ }
+
+ }
+ if (s->cert->ecdh_tmp_auto)
+ {
+ /* Need a shared curve */
+ if (tls1_shared_curve(s, 0))
+ return 1;
+ else return 0;
+ }
if (!ec)
{
if (s->cert->ecdh_tmp_cb)
return 0;
}
if (!tls1_set_ec_id(curve_id, NULL, ec))
- return 1;
+ return 0;
+/* Set this to allow use of invalid curves for testing */
+#if 0
+ return 1;
+#else
return tls1_check_ec_key(s, curve_id, NULL);
+#endif
}
#endif /* OPENSSL_NO_EC */
#endif
};
-int tls12_get_req_sig_algs(SSL *s, unsigned char *p)
+static unsigned char suiteb_sigalgs[] = {
+ tlsext_sigalg_ecdsa(TLSEXT_hash_sha256)
+ tlsext_sigalg_ecdsa(TLSEXT_hash_sha384)
+};
+
+size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs)
{
- size_t slen = sizeof(tls12_sigalgs);
+ /* If Suite B mode use Suite B sigalgs only, ignore any other
+ * preferences.
+ */
+ switch (tls1_suiteb(s))
+ {
+ case SSL_CERT_FLAG_SUITEB_128_LOS:
+ *psigs = suiteb_sigalgs;
+ return sizeof(suiteb_sigalgs);
+
+ case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+ *psigs = suiteb_sigalgs;
+ return 2;
+
+ case SSL_CERT_FLAG_SUITEB_192_LOS:
+ *psigs = suiteb_sigalgs + 2;
+ return 2;
+ }
+
+ /* If server use client authentication sigalgs if not NULL */
+ if (s->server && s->cert->client_sigalgs)
+ {
+ *psigs = s->cert->client_sigalgs;
+ return s->cert->client_sigalgslen;
+ }
+ else if (s->cert->conf_sigalgs)
+ {
+ *psigs = s->cert->conf_sigalgs;
+ return s->cert->conf_sigalgslen;
+ }
+ else
+ {
+ *psigs = tls12_sigalgs;
#ifdef OPENSSL_FIPS
- /* If FIPS mode don't include MD5 which is last */
- if (FIPS_mode())
- slen -= 2;
+ /* If FIPS mode don't include MD5 which is last */
+ if (FIPS_mode())
+ return sizeof(tls12_sigalgs) - 2;
+ else
+#endif
+ return sizeof(tls12_sigalgs);
+ }
+ }
+/* Check signature algorithm is consistent with sent supported signature
+ * algorithms and if so return relevant digest.
+ */
+int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
+ const unsigned char *sig, EVP_PKEY *pkey)
+ {
+ const unsigned char *sent_sigs;
+ size_t sent_sigslen, i;
+ int sigalg = tls12_get_sigid(pkey);
+ /* Should never happen */
+ if (sigalg == -1)
+ return -1;
+ /* Check key type is consistent with signature */
+ if (sigalg != (int)sig[1])
+ {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
+ if (pkey->type == EVP_PKEY_EC)
+ {
+ unsigned char curve_id[2], comp_id;
+ /* Check compression and curve matches extensions */
+ if (!tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec))
+ return 0;
+ if (!s->server && !tls1_check_ec_key(s, curve_id, &comp_id))
+ {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_CURVE);
+ return 0;
+ }
+ /* If Suite B only P-384+SHA384 or P-256+SHA-256 allowed */
+ if (tls1_suiteb(s))
+ {
+ if (curve_id[0])
+ return 0;
+ if (curve_id[1] == TLSEXT_curve_P_256)
+ {
+ if (sig[0] != TLSEXT_hash_sha256)
+ {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
+ SSL_R_ILLEGAL_SUITEB_DIGEST);
+ return 0;
+ }
+ }
+ else if (curve_id[1] == TLSEXT_curve_P_384)
+ {
+ if (sig[0] != TLSEXT_hash_sha384)
+ {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
+ SSL_R_ILLEGAL_SUITEB_DIGEST);
+ return 0;
+ }
+ }
+ else
+ return 0;
+ }
+ }
+ else if (tls1_suiteb(s))
+ return 0;
+
+ /* Check signature matches a type we sent */
+ sent_sigslen = tls12_get_psigalgs(s, &sent_sigs);
+ for (i = 0; i < sent_sigslen; i+=2, sent_sigs+=2)
+ {
+ if (sig[0] == sent_sigs[0] && sig[1] == sent_sigs[1])
+ break;
+ }
+ /* Allow fallback to SHA1 if not strict mode */
+ if (i == sent_sigslen && (sig[0] != TLSEXT_hash_sha1 || s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT))
+ {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
+ return 0;
+ }
+ *pmd = tls12_get_hash(sig[0]);
+ if (*pmd == NULL)
+ {
+ SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_UNKNOWN_DIGEST);
+ return 0;
+ }
+ /* Store the digest used so applications can retrieve it if they
+ * wish.
+ */
+ if (s->session && s->session->sess_cert)
+ s->session->sess_cert->peer_key->digest = *pmd;
+ return 1;
+ }
+/* Get a mask of disabled algorithms: an algorithm is disabled
+ * if it isn't supported or doesn't appear in supported signature
+ * algorithms. Unlike ssl_cipher_get_disabled this applies to a specific
+ * session and not global settings.
+ *
+ */
+void ssl_set_client_disabled(SSL *s)
+ {
+ CERT *c = s->cert;
+ const unsigned char *sigalgs;
+ size_t i, sigalgslen;
+ int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
+ c->mask_a = 0;
+ c->mask_k = 0;
+ /* If less than TLS 1.2 don't allow TLS 1.2 only ciphers */
+ if (TLS1_get_client_version(s) < TLS1_2_VERSION)
+ c->mask_ssl = SSL_TLSV1_2;
+ else
+ c->mask_ssl = 0;
+ /* Now go through all signature algorithms seeing if we support
+ * any for RSA, DSA, ECDSA. Do this for all versions not just
+ * TLS 1.2.
+ */
+ sigalgslen = tls12_get_psigalgs(s, &sigalgs);
+ for (i = 0; i < sigalgslen; i += 2, sigalgs += 2)
+ {
+ switch(sigalgs[1])
+ {
+#ifndef OPENSSL_NO_RSA
+ case TLSEXT_signature_rsa:
+ have_rsa = 1;
+ break;
+#endif
+#ifndef OPENSSL_NO_DSA
+ case TLSEXT_signature_dsa:
+ have_dsa = 1;
+ break;
#endif
- if (p)
- memcpy(p, tls12_sigalgs, slen);
- return (int)slen;
+#ifndef OPENSSL_NO_ECDSA
+ case TLSEXT_signature_ecdsa:
+ have_ecdsa = 1;
+ break;
+#endif
+ }
+ }
+ /* Disable auth and static DH if we don't include any appropriate
+ * signature algorithms.
+ */
+ if (!have_rsa)
+ {
+ c->mask_a |= SSL_aRSA;
+ c->mask_k |= SSL_kDHr|SSL_kECDHr;
+ }
+ if (!have_dsa)
+ {
+ c->mask_a |= SSL_aDSS;
+ c->mask_k |= SSL_kDHd;
+ }
+ if (!have_ecdsa)
+ {
+ c->mask_a |= SSL_aECDSA;
+ c->mask_k |= SSL_kECDHe;
+ }
+#ifndef OPENSSL_NO_KRB5
+ if (!kssl_tgt_is_available(s->kssl_ctx))
+ {
+ c->mask_a |= SSL_aKRB5;
+ c->mask_k |= SSL_kKRB5;
+ }
+#endif
+#ifndef OPENSSL_NO_PSK
+ /* with PSK there must be client callback set */
+ if (!s->psk_client_callback)
+ {
+ c->mask_a |= SSL_aPSK;
+ c->mask_k |= SSL_kPSK;
+ }
+#endif /* OPENSSL_NO_PSK */
+ c->valid = 1;
}
+/* byte_compare is a compare function for qsort(3) that compares bytes. */
+static int byte_compare(const void *in_a, const void *in_b)
+ {
+ unsigned char a = *((const unsigned char*) in_a);
+ unsigned char b = *((const unsigned char*) in_b);
+
+ if (a > b)
+ return 1;
+ else if (a < b)
+ return -1;
+ return 0;
+}
+
unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
{
int extdatalen=0;
long lenmax;
const unsigned char *plist;
size_t plistlen;
- /* If we have a custom point format list use it otherwise
- * use default */
- plist = s->tlsext_ecpointformatlist;
- if (plist)
- plistlen = s->tlsext_ecpointformatlist_length;
- else
- {
- plist = ecformats_default;
- plistlen = sizeof(ecformats_default);
- }
+
+ tls1_get_formatlist(s, &plist, &plistlen);
if ((lenmax = limit - ret - 5) < 0) return NULL;
if (plistlen > (size_t)lenmax) return NULL;
if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
{
- if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6)
+ size_t salglen;
+ const unsigned char *salg;
+ salglen = tls12_get_psigalgs(s, &salg);
+ if ((size_t)(limit - ret) < salglen + 6)
return NULL;
s2n(TLSEXT_TYPE_signature_algorithms,ret);
- s2n(sizeof(tls12_sigalgs) + 2, ret);
- s2n(sizeof(tls12_sigalgs), ret);
- memcpy(ret, tls12_sigalgs, sizeof(tls12_sigalgs));
- ret += sizeof(tls12_sigalgs);
+ s2n(salglen + 2, ret);
+ s2n(salglen, ret);
+ memcpy(ret, salg, salglen);
+ ret += salglen;
}
#ifdef TLSEXT_TYPE_opaque_prf_input
ret += el;
}
- if ((extdatalen = ret-p-2)== 0)
+ /* Add TLS extension Server_Authz_DataFormats to the ClientHello */
+ /* 2 bytes for extension type */
+ /* 2 bytes for extension length */
+ /* 1 byte for the list length */
+ /* 1 byte for the list (we only support audit proofs) */
+ if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL)
+ {
+ const unsigned short ext_len = 2;
+ const unsigned char list_len = 1;
+
+ if (limit < ret + 6)
+ return NULL;
+
+ s2n(TLSEXT_TYPE_server_authz, ret);
+ /* Extension length: 2 bytes */
+ s2n(ext_len, ret);
+ *(ret++) = list_len;
+ *(ret++) = TLSEXT_AUTHZDATAFORMAT_audit_proof;
+ }
+
+ if ((extdatalen = ret-p-2) == 0)
return p;
s2n(extdatalen,p);
#ifndef OPENSSL_NO_NEXTPROTONEG
int next_proto_neg_seen;
#endif
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
+ using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
/* don't add extensions for SSLv3, unless doing secure renegotiation */
if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
}
#ifndef OPENSSL_NO_EC
- if (s->tlsext_ecpointformatlist != NULL &&
- s->version != DTLS1_VERSION)
+ if (using_ecc && s->version != DTLS1_VERSION)
{
+ const unsigned char *plist;
+ size_t plistlen;
/* Add TLS extension ECPointFormats to the ServerHello message */
long lenmax;
+ tls1_get_formatlist(s, &plist, &plistlen);
+
if ((lenmax = limit - ret - 5) < 0) return NULL;
- if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
- if (s->tlsext_ecpointformatlist_length > 255)
+ if (plistlen > (size_t)lenmax) return NULL;
+ if (plistlen > 255)
{
SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
return NULL;
}
s2n(TLSEXT_TYPE_ec_point_formats,ret);
- s2n(s->tlsext_ecpointformatlist_length + 1,ret);
- *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
- memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
- ret+=s->tlsext_ecpointformatlist_length;
+ s2n(plistlen + 1,ret);
+ *(ret++) = (unsigned char) plistlen;
+ memcpy(ret, plist, plistlen);
+ ret+=plistlen;
}
/* Currently the server should not respond with a SupportedCurves extension */
}
#endif
+ /* If the client supports authz then see whether we have any to offer
+ * to it. */
+ if (s->s3->tlsext_authz_client_types_len)
+ {
+ size_t authz_length;
+ /* By now we already know the new cipher, so we can look ahead
+ * to see whether the cert we are going to send
+ * has any authz data attached to it. */
+ const unsigned char* authz = ssl_get_authz_data(s, &authz_length);
+ const unsigned char* const orig_authz = authz;
+ size_t i;
+ unsigned authz_count = 0;
+
+ /* The authz data contains a number of the following structures:
+ * uint8_t authz_type
+ * uint16_t length
+ * uint8_t data[length]
+ *
+ * First we walk over it to find the number of authz elements. */
+ for (i = 0; i < authz_length; i++)
+ {
+ unsigned short length;
+ unsigned char type;
+
+ type = *(authz++);
+ if (memchr(s->s3->tlsext_authz_client_types,
+ type,
+ s->s3->tlsext_authz_client_types_len) != NULL)
+ authz_count++;
+
+ n2s(authz, length);
+ /* n2s increments authz by 2 */
+ i += 2;
+ authz += length;
+ i += length;
+ }
+
+ if (authz_count)
+ {
+ /* Add TLS extension server_authz to the ServerHello message
+ * 2 bytes for extension type
+ * 2 bytes for extension length
+ * 1 byte for the list length
+ * n bytes for the list */
+ const unsigned short ext_len = 1 + authz_count;
+
+ if ((long)(limit - ret - 4 - ext_len) < 0) return NULL;
+ s2n(TLSEXT_TYPE_server_authz, ret);
+ s2n(ext_len, ret);
+ *(ret++) = authz_count;
+ s->s3->tlsext_authz_promised_to_client = 1;
+ }
+
+ authz = orig_authz;
+ for (i = 0; i < authz_length; i++)
+ {
+ unsigned short length;
+ unsigned char type;
+
+ authz_count++;
+ type = *(authz++);
+ if (memchr(s->s3->tlsext_authz_client_types,
+ type,
+ s->s3->tlsext_authz_client_types_len) != NULL)
+ *(ret++) = type;
+ n2s(authz, length);
+ /* n2s increments authz by 2 */
+ i += 2;
+ authz += length;
+ i += length;
+ }
+ }
+
if ((extdatalen = ret-p-2)== 0)
return p;
return ret;
}
-int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
- {
+static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+ {
unsigned short type;
unsigned short size;
unsigned short len;
unsigned char *data = *p;
int renegotiate_seen = 0;
- int sigalg_seen = 0;
+ size_t i;
s->servername_done = 0;
s->tlsext_status_type = -1;
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
#endif
-
- if (data >= (d+n-2))
- goto ri_check;
+ /* Clear any signature algorithms extension received */
+ if (s->cert->peer_sigalgs)
+ {
+ OPENSSL_free(s->cert->peer_sigalgs);
+ s->cert->peer_sigalgs = NULL;
+ }
+ /* Clear any shared sigtnature algorithms */
+ if (s->cert->shared_sigalgs)
+ {
+ OPENSSL_free(s->cert->shared_sigalgs);
+ s->cert->shared_sigalgs = NULL;
+ }
+ /* Clear certificate digests and validity flags */
+ for (i = 0; i < SSL_PKEY_NUM; i++)
+ {
+ s->cert->pkeys[i].digest = NULL;
+ s->cert->pkeys[i].valid_flags = 0;
+ }
+
+ if (data >= (d+n-2))
+ goto ri_check;
n2s(data,len);
if (data > (d+n-len))
unsigned char *sdata = data;
int ecpointformatlist_length = *(sdata++);
- if (ecpointformatlist_length != size - 1)
+ if (ecpointformatlist_length != size - 1 ||
+ ecpointformatlist_length < 1)
{
*al = TLS1_AD_DECODE_ERROR;
return 0;
int ellipticcurvelist_length = (*(sdata++) << 8);
ellipticcurvelist_length += (*(sdata++));
- if (ellipticcurvelist_length != size - 2)
+ if (ellipticcurvelist_length != size - 2 ||
+ ellipticcurvelist_length < 1)
{
*al = TLS1_AD_DECODE_ERROR;
return 0;
else if (type == TLSEXT_TYPE_signature_algorithms)
{
int dsize;
- if (sigalg_seen || size < 2)
+ if (s->cert->peer_sigalgs || size < 2)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
}
- sigalg_seen = 1;
n2s(data,dsize);
size -= 2;
- if (dsize != size || dsize & 1)
+ if (dsize != size || dsize & 1 || !dsize)
{
*al = SSL_AD_DECODE_ERROR;
return 0;
*al = SSL_AD_DECODE_ERROR;
return 0;
}
+ /* If sigalgs received and no shared algorithms fatal
+ * error.
+ */
+ if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs)
+ {
+ SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
+ SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
+ *al = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
}
else if (type == TLSEXT_TYPE_status_request &&
s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
else if (type == TLSEXT_TYPE_next_proto_neg &&
- s->s3->tmp.finish_md_len == 0)
+ s->s3->tmp.finish_md_len == 0)
{
/* We shouldn't accept this extension on a
* renegotiation.
return 0;
}
+ else if (type == TLSEXT_TYPE_server_authz)
+ {
+ unsigned char *sdata = data;
+ unsigned char server_authz_dataformatlist_length;
+
+ if (size == 0)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ server_authz_dataformatlist_length = *(sdata++);
+
+ if (server_authz_dataformatlist_length != size - 1)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* Successful session resumption uses the same authz
+ * information as the original session so we ignore this
+ * in the case of a session resumption. */
+ if (!s->hit)
+ {
+ if (s->s3->tlsext_authz_client_types != NULL)
+ OPENSSL_free(s->s3->tlsext_authz_client_types);
+ s->s3->tlsext_authz_client_types =
+ OPENSSL_malloc(server_authz_dataformatlist_length);
+ if (!s->s3->tlsext_authz_client_types)
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ s->s3->tlsext_authz_client_types_len =
+ server_authz_dataformatlist_length;
+ memcpy(s->s3->tlsext_authz_client_types,
+ sdata,
+ server_authz_dataformatlist_length);
+
+ /* Sort the types in order to check for duplicates. */
+ qsort(s->s3->tlsext_authz_client_types,
+ server_authz_dataformatlist_length,
+ 1 /* element size */,
+ byte_compare);
+
+ for (i = 0; i < server_authz_dataformatlist_length; i++)
+ {
+ if (i > 0 &&
+ s->s3->tlsext_authz_client_types[i] ==
+ s->s3->tlsext_authz_client_types[i-1])
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+ }
+ }
+
data+=size;
}
-
+
*p = data;
ri_check:
!(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
{
*al = SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,
+ SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
return 0;
}
+ /* If no signature algorithms extension set default values */
+ if (!s->cert->peer_sigalgs)
+ ssl_cert_set_default_md(s->cert);
return 1;
}
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n)
+ {
+ int al = -1;
+ if (ssl_scan_clienthello_tlsext(s, p, d, n, &al) <= 0)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return 0;
+ }
+
+ if (ssl_check_clienthello_tlsext_early(s) <= 0)
+ {
+ SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,SSL_R_CLIENTHELLO_TLSEXT);
+ return 0;
+ }
+ return 1;
+}
+
#ifndef OPENSSL_NO_NEXTPROTONEG
/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
* elements of zero length are allowed and the set of elements must exactly fill
* the length of the block. */
-static int ssl_next_proto_validate(unsigned char *d, unsigned len)
+static char ssl_next_proto_validate(unsigned char *d, unsigned len)
{
unsigned int off = 0;
}
#endif
-int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
{
unsigned short length;
unsigned short type;
unsigned char selected_len;
/* We must have requested it. */
- if ((s->ctx->next_proto_select_cb == NULL))
+ if (s->ctx->next_proto_select_cb == NULL)
{
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
return 0;
return 0;
}
- data+=size;
+ else if (type == TLSEXT_TYPE_server_authz)
+ {
+ /* We only support audit proofs. It's an error to send
+ * an authz hello extension if the client
+ * didn't request a proof. */
+ unsigned char *sdata = data;
+ unsigned char server_authz_dataformatlist_length;
+
+ if (!s->ctx->tlsext_authz_server_audit_proof_cb)
+ {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+
+ if (!size)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ server_authz_dataformatlist_length = *(sdata++);
+ if (server_authz_dataformatlist_length != size - 1)
+ {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* We only support audit proofs, so a legal ServerHello
+ * authz list contains exactly one entry. */
+ if (server_authz_dataformatlist_length != 1 ||
+ sdata[0] != TLSEXT_AUTHZDATAFORMAT_audit_proof)
+ {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+
+ s->s3->tlsext_authz_server_promised = 1;
+ }
+
+ data += size;
}
if (data != d+n)
&& !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
{
*al = SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,
+ SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
return 0;
}
int ssl_prepare_serverhello_tlsext(SSL *s)
{
-#ifndef OPENSSL_NO_EC
- /* If we are server and using an ECC cipher suite, send the point formats we support
- * if the client sent us an ECPointsFormat extension. Note that the server is not
- * supposed to send an EllipticCurves extension.
- */
-
- unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
- using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
-
- if (using_ecc)
- {
- if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
- if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
- {
- SSLerr(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
- return -1;
- }
- s->tlsext_ecpointformatlist_length = 3;
- s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
- s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
- s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
- }
-#endif /* OPENSSL_NO_EC */
-
return 1;
}
-int ssl_check_clienthello_tlsext(SSL *s)
+static int ssl_check_clienthello_tlsext_early(SSL *s)
{
int ret=SSL_TLSEXT_ERR_NOACK;
int al = SSL_AD_UNRECOGNIZED_NAME;
else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
- /* If status request then ask callback what to do.
- * Note: this must be called after servername callbacks in case
- * the certificate has changed.
- */
- if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
- {
- int r;
- r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
- switch (r)
- {
- /* We don't want to send a status request response */
- case SSL_TLSEXT_ERR_NOACK:
- s->tlsext_status_expected = 0;
- break;
- /* status request response should be sent */
- case SSL_TLSEXT_ERR_OK:
- if (s->tlsext_ocsp_resp)
- s->tlsext_status_expected = 1;
- else
- s->tlsext_status_expected = 0;
- break;
- /* something bad happened */
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_INTERNAL_ERROR;
- goto err;
- }
- }
- else
- s->tlsext_status_expected = 0;
-
#ifdef TLSEXT_TYPE_opaque_prf_input
{
/* This sort of belongs into ssl_prepare_serverhello_tlsext(),
* but we might be sending an alert in response to the client hello,
- * so this has to happen here in ssl_check_clienthello_tlsext(). */
+ * so this has to happen here in
+ * ssl_check_clienthello_tlsext_early(). */
int r = 1;
}
}
-#endif
err:
+#endif
switch (ret)
{
case SSL_TLSEXT_ERR_ALERT_FATAL:
}
}
+int ssl_check_clienthello_tlsext_late(SSL *s)
+ {
+ int ret = SSL_TLSEXT_ERR_OK;
+ int al;
+
+ /* If status request then ask callback what to do.
+ * Note: this must be called after servername callbacks in case
+ * the certificate has changed, and must be called after the cipher
+ * has been chosen because this may influence which certificate is sent
+ */
+ if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ CERT_PKEY *certpkey;
+ certpkey = ssl_get_server_send_pkey(s);
+ /* If no certificate can't return certificate status */
+ if (certpkey == NULL)
+ {
+ s->tlsext_status_expected = 0;
+ return 1;
+ }
+ /* Set current certificate to one we will use so
+ * SSL_get_certificate et al can pick it up.
+ */
+ s->cert->key = certpkey;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ switch (r)
+ {
+ /* We don't want to send a status request response */
+ case SSL_TLSEXT_ERR_NOACK:
+ s->tlsext_status_expected = 0;
+ break;
+ /* status request response should be sent */
+ case SSL_TLSEXT_ERR_OK:
+ if (s->tlsext_ocsp_resp)
+ s->tlsext_status_expected = 1;
+ else
+ s->tlsext_status_expected = 0;
+ break;
+ /* something bad happened */
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+ else
+ s->tlsext_status_expected = 0;
+
+ err:
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s, SSL3_AL_WARNING, al);
+ return 1;
+
+ default:
+ return 1;
+ }
+ }
+
int ssl_check_serverhello_tlsext(SSL *s)
{
int ret=SSL_TLSEXT_ERR_NOACK;
}
}
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n)
+ {
+ int al = -1;
+ if (s->version < SSL3_VERSION)
+ return 1;
+ if (ssl_scan_serverhello_tlsext(s, p, d, n, &al) <= 0)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return 0;
+ }
+
+ if (ssl_check_serverhello_tlsext(s) <= 0)
+ {
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,SSL_R_SERVERHELLO_TLSEXT);
+ return 0;
+ }
+ return 1;
+}
+
/* Since the server cache lookup is done early on in the processing of the
* ClientHello, and other operations depend on the result, we need to handle
* any TLS session ticket extension at the same time.
HMAC_Update(&hctx, etick, eticklen);
HMAC_Final(&hctx, tick_hmac, NULL);
HMAC_CTX_cleanup(&hctx);
- if (memcmp(tick_hmac, etick + eticklen, mlen))
+ if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
return 2;
/* Attempt to decrypt session data */
/* Move p after IV to start of encrypted ticket, update length */
}
}
+static int tls12_get_pkey_idx(unsigned char sig_alg)
+ {
+ switch(sig_alg)
+ {
+#ifndef OPENSSL_NO_RSA
+ case TLSEXT_signature_rsa:
+ return SSL_PKEY_RSA_SIGN;
+#endif
+#ifndef OPENSSL_NO_DSA
+ case TLSEXT_signature_dsa:
+ return SSL_PKEY_DSA_SIGN;
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ case TLSEXT_signature_ecdsa:
+ return SSL_PKEY_ECC;
+#endif
+ }
+ return -1;
+ }
+
+/* Convert TLS 1.2 signature algorithm extension values into NIDs */
+static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid,
+ int *psignhash_nid, const unsigned char *data)
+ {
+ int sign_nid = 0, hash_nid = 0;
+ if (!phash_nid && !psign_nid && !psignhash_nid)
+ return;
+ if (phash_nid || psignhash_nid)
+ {
+ hash_nid = tls12_find_nid(data[0], tls12_md,
+ sizeof(tls12_md)/sizeof(tls12_lookup));
+ if (phash_nid)
+ *phash_nid = hash_nid;
+ }
+ if (psign_nid || psignhash_nid)
+ {
+ sign_nid = tls12_find_nid(data[1], tls12_sig,
+ sizeof(tls12_sig)/sizeof(tls12_lookup));
+ if (psign_nid)
+ *psign_nid = sign_nid;
+ }
+ if (psignhash_nid)
+ {
+ if (sign_nid && hash_nid)
+ OBJ_find_sigid_by_algs(psignhash_nid,
+ hash_nid, sign_nid);
+ else
+ *psignhash_nid = NID_undef;
+ }
+ }
+/* Given preference and allowed sigalgs set shared sigalgs */
+static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig,
+ const unsigned char *pref, size_t preflen,
+ const unsigned char *allow, size_t allowlen)
+ {
+ const unsigned char *ptmp, *atmp;
+ size_t i, j, nmatch = 0;
+ for (i = 0, ptmp = pref; i < preflen; i+=2, ptmp+=2)
+ {
+ /* Skip disabled hashes or signature algorithms */
+ if (tls12_get_hash(ptmp[0]) == NULL)
+ continue;
+ if (tls12_get_pkey_idx(ptmp[1]) == -1)
+ continue;
+ for (j = 0, atmp = allow; j < allowlen; j+=2, atmp+=2)
+ {
+ if (ptmp[0] == atmp[0] && ptmp[1] == atmp[1])
+ {
+ nmatch++;
+ if (shsig)
+ {
+ shsig->rhash = ptmp[0];
+ shsig->rsign = ptmp[1];
+ tls1_lookup_sigalg(&shsig->hash_nid,
+ &shsig->sign_nid,
+ &shsig->signandhash_nid,
+ ptmp);
+ shsig++;
+ }
+ break;
+ }
+ }
+ }
+ return nmatch;
+ }
+
+/* Set shared signature algorithms for SSL structures */
+static int tls1_set_shared_sigalgs(SSL *s)
+ {
+ const unsigned char *pref, *allow, *conf;
+ size_t preflen, allowlen, conflen;
+ size_t nmatch;
+ TLS_SIGALGS *salgs = NULL;
+ CERT *c = s->cert;
+ unsigned int is_suiteb = tls1_suiteb(s);
+ /* If client use client signature algorithms if not NULL */
+ if (!s->server && c->client_sigalgs && !is_suiteb)
+ {
+ conf = c->client_sigalgs;
+ conflen = c->client_sigalgslen;
+ }
+ else if (c->conf_sigalgs && !is_suiteb)
+ {
+ conf = c->conf_sigalgs;
+ conflen = c->conf_sigalgslen;
+ }
+ else
+ conflen = tls12_get_psigalgs(s, &conf);
+ if(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || is_suiteb)
+ {
+ pref = conf;
+ preflen = conflen;
+ allow = c->peer_sigalgs;
+ allowlen = c->peer_sigalgslen;
+ }
+ else
+ {
+ allow = conf;
+ allowlen = conflen;
+ pref = c->peer_sigalgs;
+ preflen = c->peer_sigalgslen;
+ }
+ nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen);
+ if (!nmatch)
+ return 1;
+ salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
+ if (!salgs)
+ return 0;
+ nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen);
+ c->shared_sigalgs = salgs;
+ c->shared_sigalgslen = nmatch;
+ return 1;
+ }
+
+
/* Set preferred digest for each key type */
int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
{
- int i, idx;
+ int idx;
+ size_t i;
const EVP_MD *md;
CERT *c = s->cert;
TLS_SIGALGS *sigptr;
if (!c)
return 0;
- c->pkeys[SSL_PKEY_DSA_SIGN].digest = NULL;
- c->pkeys[SSL_PKEY_RSA_SIGN].digest = NULL;
- c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL;
- c->pkeys[SSL_PKEY_ECC].digest = NULL;
-
- if (c->sigalgs)
- OPENSSL_free(c->sigalgs);
- c->sigalgs = OPENSSL_malloc((dsize/2) * sizeof(TLS_SIGALGS));
- if (!c->sigalgs)
+ c->peer_sigalgs = OPENSSL_malloc(dsize);
+ if (!c->peer_sigalgs)
return 0;
- c->sigalgslen = dsize/2;
+ c->peer_sigalgslen = dsize;
+ memcpy(c->peer_sigalgs, data, dsize);
+
+ tls1_set_shared_sigalgs(s);
- for (i = 0, sigptr = c->sigalgs; i < dsize; i += 2, sigptr++)
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+ if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
{
- sigptr->rhash = data[i];
- sigptr->rsign = data[i + 1];
- sigptr->hash_nid = tls12_find_nid(sigptr->rhash, tls12_md,
- sizeof(tls12_md)/sizeof(tls12_lookup));
- sigptr->sign_nid = tls12_find_nid(sigptr->rsign, tls12_sig,
- sizeof(tls12_sig)/sizeof(tls12_lookup));
- if (!OBJ_find_sigid_by_algs(&sigptr->signandhash_nid,
- sigptr->hash_nid,
- sigptr->sign_nid))
- sigptr->signandhash_nid = NID_undef;
- switch(sigptr->rsign)
+ /* Use first set signature preference to force message
+ * digest, ignoring any peer preferences.
+ */
+ const unsigned char *sigs = NULL;
+ if (s->server)
+ sigs = c->conf_sigalgs;
+ else
+ sigs = c->client_sigalgs;
+ if (sigs)
{
-#ifndef OPENSSL_NO_RSA
- case TLSEXT_signature_rsa:
- idx = SSL_PKEY_RSA_SIGN;
- break;
-#endif
-#ifndef OPENSSL_NO_DSA
- case TLSEXT_signature_dsa:
- idx = SSL_PKEY_DSA_SIGN;
- break;
-#endif
-#ifndef OPENSSL_NO_ECDSA
- case TLSEXT_signature_ecdsa:
- idx = SSL_PKEY_ECC;
- break;
-#endif
- default:
- continue;
+ idx = tls12_get_pkey_idx(sigs[1]);
+ md = tls12_get_hash(sigs[0]);
+ c->pkeys[idx].digest = md;
+ c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ if (idx == SSL_PKEY_RSA_SIGN)
+ {
+ c->pkeys[SSL_PKEY_RSA_ENC].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+ }
}
+ }
+#endif
- if (c->pkeys[idx].digest == NULL)
+ for (i = 0, sigptr = c->shared_sigalgs;
+ i < c->shared_sigalgslen; i++, sigptr++)
+ {
+ idx = tls12_get_pkey_idx(sigptr->rsign);
+ if (idx > 0 && c->pkeys[idx].digest == NULL)
{
md = tls12_get_hash(sigptr->rhash);
- if (md)
+ c->pkeys[idx].digest = md;
+ c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ if (idx == SSL_PKEY_RSA_SIGN)
{
- c->pkeys[idx].digest = md;
- if (idx == SSL_PKEY_RSA_SIGN)
- c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+ c->pkeys[SSL_PKEY_RSA_ENC].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
}
}
}
-
-
- /* Set any remaining keys to default values. NOTE: if alg is not
- * supported it stays as NULL.
+ /* In strict mode leave unset digests as NULL to indicate we can't
+ * use the certificate for signing.
*/
+ if (!(s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT))
+ {
+ /* Set any remaining keys to default values. NOTE: if alg is
+ * not supported it stays as NULL.
+ */
#ifndef OPENSSL_NO_DSA
- if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
- c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_dss1();
+ if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
+ c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
#endif
#ifndef OPENSSL_NO_RSA
- if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
- {
- c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
- c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
- }
+ if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
+ {
+ c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
+ }
#endif
#ifndef OPENSSL_NO_ECDSA
- if (!c->pkeys[SSL_PKEY_ECC].digest)
- c->pkeys[SSL_PKEY_ECC].digest = EVP_ecdsa();
+ if (!c->pkeys[SSL_PKEY_ECC].digest)
+ c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
#endif
+ }
return 1;
}
-#endif
int SSL_get_sigalgs(SSL *s, int idx,
- int *psign, int *phash, int *psignandhash,
+ int *psign, int *phash, int *psignhash,
unsigned char *rsig, unsigned char *rhash)
{
- if (s->cert->sigalgs == NULL)
+ const unsigned char *psig = s->cert->peer_sigalgs;
+ if (psig == NULL)
return 0;
if (idx >= 0)
{
- TLS_SIGALGS *psig;
- if (idx >= (int)s->cert->sigalgslen)
+ idx <<= 1;
+ if (idx >= (int)s->cert->peer_sigalgslen)
return 0;
- psig = s->cert->sigalgs + idx;
- if (psign)
- *psign = psig->sign_nid;
- if (phash)
- *phash = psig->hash_nid;
- if (psignandhash)
- *psignandhash = psig->signandhash_nid;
- if (rsig)
- *rsig = psig->rsign;
+ psig += idx;
if (rhash)
- *rhash = psig->rhash;
+ *rhash = psig[0];
+ if (rsig)
+ *rsig = psig[1];
+ tls1_lookup_sigalg(phash, psign, psignhash, psig);
}
- return s->cert->sigalgslen;
+ return s->cert->peer_sigalgslen / 2;
+ }
+
+int SSL_get_shared_sigalgs(SSL *s, int idx,
+ int *psign, int *phash, int *psignhash,
+ unsigned char *rsig, unsigned char *rhash)
+ {
+ TLS_SIGALGS *shsigalgs = s->cert->shared_sigalgs;
+ if (!shsigalgs || idx >= (int)s->cert->shared_sigalgslen)
+ return 0;
+ shsigalgs += idx;
+ if (phash)
+ *phash = shsigalgs->hash_nid;
+ if (psign)
+ *psign = shsigalgs->sign_nid;
+ if (psignhash)
+ *psignhash = shsigalgs->signandhash_nid;
+ if (rsig)
+ *rsig = shsigalgs->rsign;
+ if (rhash)
+ *rhash = shsigalgs->rhash;
+ return s->cert->shared_sigalgslen;
}
return ret;
}
#endif
+
+#define MAX_SIGALGLEN (TLSEXT_hash_num * TLSEXT_signature_num * 2)
+
+typedef struct
+ {
+ size_t sigalgcnt;
+ int sigalgs[MAX_SIGALGLEN];
+ } sig_cb_st;
+
+static int sig_cb(const char *elem, int len, void *arg)
+ {
+ sig_cb_st *sarg = arg;
+ size_t i;
+ char etmp[20], *p;
+ int sig_alg, hash_alg;
+ if (sarg->sigalgcnt == MAX_SIGALGLEN)
+ return 0;
+ if (len > (int)(sizeof(etmp) - 1))
+ return 0;
+ memcpy(etmp, elem, len);
+ etmp[len] = 0;
+ p = strchr(etmp, '+');
+ if (!p)
+ return 0;
+ *p = 0;
+ p++;
+ if (!*p)
+ return 0;
+
+ if (!strcmp(etmp, "RSA"))
+ sig_alg = EVP_PKEY_RSA;
+ else if (!strcmp(etmp, "DSA"))
+ sig_alg = EVP_PKEY_DSA;
+ else if (!strcmp(etmp, "ECDSA"))
+ sig_alg = EVP_PKEY_EC;
+ else return 0;
+
+ hash_alg = OBJ_sn2nid(p);
+ if (hash_alg == NID_undef)
+ hash_alg = OBJ_ln2nid(p);
+ if (hash_alg == NID_undef)
+ return 0;
+
+ for (i = 0; i < sarg->sigalgcnt; i+=2)
+ {
+ if (sarg->sigalgs[i] == sig_alg
+ && sarg->sigalgs[i + 1] == hash_alg)
+ return 0;
+ }
+ sarg->sigalgs[sarg->sigalgcnt++] = hash_alg;
+ sarg->sigalgs[sarg->sigalgcnt++] = sig_alg;
+ return 1;
+ }
+
+/* Set suppored signature algorithms based on a colon separated list
+ * of the form sig+hash e.g. RSA+SHA512:DSA+SHA512 */
+int tls1_set_sigalgs_list(CERT *c, const char *str, int client)
+ {
+ sig_cb_st sig;
+ sig.sigalgcnt = 0;
+ if (!CONF_parse_list(str, ':', 1, sig_cb, &sig))
+ return 0;
+ if (c == NULL)
+ return 1;
+ return tls1_set_sigalgs(c, sig.sigalgs, sig.sigalgcnt, client);
+ }
+
+int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, int client)
+ {
+ unsigned char *sigalgs, *sptr;
+ int rhash, rsign;
+ size_t i;
+ if (salglen & 1)
+ return 0;
+ sigalgs = OPENSSL_malloc(salglen);
+ if (sigalgs == NULL)
+ return 0;
+ for (i = 0, sptr = sigalgs; i < salglen; i+=2)
+ {
+ rhash = tls12_find_id(*psig_nids++, tls12_md,
+ sizeof(tls12_md)/sizeof(tls12_lookup));
+ rsign = tls12_find_id(*psig_nids++, tls12_sig,
+ sizeof(tls12_sig)/sizeof(tls12_lookup));
+
+ if (rhash == -1 || rsign == -1)
+ goto err;
+ *sptr++ = rhash;
+ *sptr++ = rsign;
+ }
+
+ if (client)
+ {
+ if (c->client_sigalgs)
+ OPENSSL_free(c->client_sigalgs);
+ c->client_sigalgs = sigalgs;
+ c->client_sigalgslen = salglen;
+ }
+ else
+ {
+ if (c->conf_sigalgs)
+ OPENSSL_free(c->conf_sigalgs);
+ c->conf_sigalgs = sigalgs;
+ c->conf_sigalgslen = salglen;
+ }
+
+ return 1;
+
+ err:
+ OPENSSL_free(sigalgs);
+ return 0;
+ }
+
+static int tls1_check_sig_alg(CERT *c, X509 *x, int default_nid)
+ {
+ int sig_nid;
+ size_t i;
+ if (default_nid == -1)
+ return 1;
+ sig_nid = X509_get_signature_nid(x);
+ if (default_nid)
+ return sig_nid == default_nid ? 1 : 0;
+ for (i = 0; i < c->shared_sigalgslen; i++)
+ if (sig_nid == c->shared_sigalgs[i].signandhash_nid)
+ return 1;
+ return 0;
+ }
+/* Check to see if a certificate issuer name matches list of CA names */
+static int ssl_check_ca_name(STACK_OF(X509_NAME) *names, X509 *x)
+ {
+ X509_NAME *nm;
+ int i;
+ nm = X509_get_issuer_name(x);
+ for (i = 0; i < sk_X509_NAME_num(names); i++)
+ {
+ if(!X509_NAME_cmp(nm, sk_X509_NAME_value(names, i)))
+ return 1;
+ }
+ return 0;
+ }
+
+/* Check certificate chain is consistent with TLS extensions and is
+ * usable by server. This servers two purposes: it allows users to
+ * check chains before passing them to the server and it allows the
+ * server to check chains before attempting to use them.
+ */
+
+/* Flags which need to be set for a certificate when stict mode not set */
+
+#define CERT_PKEY_VALID_FLAGS \
+ (CERT_PKEY_EE_SIGNATURE|CERT_PKEY_EE_PARAM)
+/* Strict mode flags */
+#define CERT_PKEY_STRICT_FLAGS \
+ (CERT_PKEY_VALID_FLAGS|CERT_PKEY_CA_SIGNATURE|CERT_PKEY_CA_PARAM \
+ | CERT_PKEY_ISSUER_NAME|CERT_PKEY_CERT_TYPE)
+
+int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
+ int idx)
+ {
+ int i;
+ int rv = 0;
+ int check_flags = 0, strict_mode;
+ CERT_PKEY *cpk = NULL;
+ CERT *c = s->cert;
+ unsigned int suiteb_flags = tls1_suiteb(s);
+ /* idx == -1 means checking server chains */
+ if (idx != -1)
+ {
+ /* idx == -2 means checking client certificate chains */
+ if (idx == -2)
+ {
+ cpk = c->key;
+ idx = cpk - c->pkeys;
+ }
+ else
+ cpk = c->pkeys + idx;
+ x = cpk->x509;
+ pk = cpk->privatekey;
+ chain = cpk->chain;
+ strict_mode = c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT;
+ /* If no cert or key, forget it */
+ if (!x || !pk)
+ goto end;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+ /* Allow any certificate to pass test */
+ if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
+ {
+ rv = CERT_PKEY_STRICT_FLAGS|CERT_PKEY_EXPLICIT_SIGN|CERT_PKEY_VALID|CERT_PKEY_SIGN;
+ cpk->valid_flags = rv;
+ return rv;
+ }
+#endif
+ }
+ else
+ {
+ if (!x || !pk)
+ goto end;
+ idx = ssl_cert_type(x, pk);
+ if (idx == -1)
+ goto end;
+ cpk = c->pkeys + idx;
+ if (c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)
+ check_flags = CERT_PKEY_STRICT_FLAGS;
+ else
+ check_flags = CERT_PKEY_VALID_FLAGS;
+ strict_mode = 1;
+ }
+
+ if (suiteb_flags)
+ {
+ int ok;
+ if (check_flags)
+ check_flags |= CERT_PKEY_SUITEB;
+ ok = X509_chain_check_suiteb(NULL, x, chain, suiteb_flags);
+ if (ok != X509_V_OK)
+ {
+ if (check_flags)
+ rv |= CERT_PKEY_SUITEB;
+ else
+ goto end;
+ }
+ }
+
+ /* Check all signature algorithms are consistent with
+ * signature algorithms extension if TLS 1.2 or later
+ * and strict mode.
+ */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION && strict_mode)
+ {
+ int default_nid;
+ unsigned char rsign = 0;
+ if (c->peer_sigalgs)
+ default_nid = 0;
+ /* If no sigalgs extension use defaults from RFC5246 */
+ else
+ {
+ switch(idx)
+ {
+ case SSL_PKEY_RSA_ENC:
+ case SSL_PKEY_RSA_SIGN:
+ case SSL_PKEY_DH_RSA:
+ rsign = TLSEXT_signature_rsa;
+ default_nid = NID_sha1WithRSAEncryption;
+ break;
+
+ case SSL_PKEY_DSA_SIGN:
+ case SSL_PKEY_DH_DSA:
+ rsign = TLSEXT_signature_dsa;
+ default_nid = NID_dsaWithSHA1;
+ break;
+
+ case SSL_PKEY_ECC:
+ rsign = TLSEXT_signature_ecdsa;
+ default_nid = NID_ecdsa_with_SHA1;
+ break;
+
+ default:
+ default_nid = -1;
+ break;
+ }
+ }
+ /* If peer sent no signature algorithms extension and we
+ * have set preferred signature algorithms check we support
+ * sha1.
+ */
+ if (default_nid > 0 && c->conf_sigalgs)
+ {
+ size_t j;
+ const unsigned char *p = c->conf_sigalgs;
+ for (j = 0; j < c->conf_sigalgslen; j += 2, p += 2)
+ {
+ if (p[0] == TLSEXT_hash_sha1 && p[1] == rsign)
+ break;
+ }
+ if (j == c->conf_sigalgslen)
+ {
+ if (check_flags)
+ goto skip_sigs;
+ else
+ goto end;
+ }
+ }
+ /* Check signature algorithm of each cert in chain */
+ if (!tls1_check_sig_alg(c, x, default_nid))
+ {
+ if (!check_flags) goto end;
+ }
+ else
+ rv |= CERT_PKEY_EE_SIGNATURE;
+ rv |= CERT_PKEY_CA_SIGNATURE;
+ for (i = 0; i < sk_X509_num(chain); i++)
+ {
+ if (!tls1_check_sig_alg(c, sk_X509_value(chain, i),
+ default_nid))
+ {
+ if (check_flags)
+ {
+ rv &= ~CERT_PKEY_CA_SIGNATURE;
+ break;
+ }
+ else
+ goto end;
+ }
+ }
+ }
+ /* Else not TLS 1.2, so mark EE and CA signing algorithms OK */
+ else if(check_flags)
+ rv |= CERT_PKEY_EE_SIGNATURE|CERT_PKEY_CA_SIGNATURE;
+ skip_sigs:
+ /* Check cert parameters are consistent */
+ if (tls1_check_cert_param(s, x, check_flags ? 1 : 2))
+ rv |= CERT_PKEY_EE_PARAM;
+ else if (!check_flags)
+ goto end;
+ if (!s->server)
+ rv |= CERT_PKEY_CA_PARAM;
+ /* In strict mode check rest of chain too */
+ else if (strict_mode)
+ {
+ rv |= CERT_PKEY_CA_PARAM;
+ for (i = 0; i < sk_X509_num(chain); i++)
+ {
+ X509 *ca = sk_X509_value(chain, i);
+ if (!tls1_check_cert_param(s, ca, 0))
+ {
+ if (check_flags)
+ {
+ rv &= ~CERT_PKEY_CA_PARAM;
+ break;
+ }
+ else
+ goto end;
+ }
+ }
+ }
+ if (!s->server && strict_mode)
+ {
+ STACK_OF(X509_NAME) *ca_dn;
+ int check_type = 0;
+ switch (pk->type)
+ {
+ case EVP_PKEY_RSA:
+ check_type = TLS_CT_RSA_SIGN;
+ break;
+ case EVP_PKEY_DSA:
+ check_type = TLS_CT_DSS_SIGN;
+ break;
+ case EVP_PKEY_EC:
+ check_type = TLS_CT_ECDSA_SIGN;
+ break;
+ case EVP_PKEY_DH:
+ case EVP_PKEY_DHX:
+ {
+ int cert_type = X509_certificate_type(x, pk);
+ if (cert_type & EVP_PKS_RSA)
+ check_type = TLS_CT_RSA_FIXED_DH;
+ if (cert_type & EVP_PKS_DSA)
+ check_type = TLS_CT_DSS_FIXED_DH;
+ }
+ }
+ if (check_type)
+ {
+ const unsigned char *ctypes;
+ int ctypelen;
+ if (c->ctypes)
+ {
+ ctypes = c->ctypes;
+ ctypelen = (int)c->ctype_num;
+ }
+ else
+ {
+ ctypes = (unsigned char *)s->s3->tmp.ctype;
+ ctypelen = s->s3->tmp.ctype_num;
+ }
+ for (i = 0; i < ctypelen; i++)
+ {
+ if (ctypes[i] == check_type)
+ {
+ rv |= CERT_PKEY_CERT_TYPE;
+ break;
+ }
+ }
+ if (!(rv & CERT_PKEY_CERT_TYPE) && !check_flags)
+ goto end;
+ }
+ else
+ rv |= CERT_PKEY_CERT_TYPE;
+
+
+ ca_dn = s->s3->tmp.ca_names;
+
+ if (!sk_X509_NAME_num(ca_dn))
+ rv |= CERT_PKEY_ISSUER_NAME;
+
+ if (!(rv & CERT_PKEY_ISSUER_NAME))
+ {
+ if (ssl_check_ca_name(ca_dn, x))
+ rv |= CERT_PKEY_ISSUER_NAME;
+ }
+ if (!(rv & CERT_PKEY_ISSUER_NAME))
+ {
+ for (i = 0; i < sk_X509_num(chain); i++)
+ {
+ X509 *xtmp = sk_X509_value(chain, i);
+ if (ssl_check_ca_name(ca_dn, xtmp))
+ {
+ rv |= CERT_PKEY_ISSUER_NAME;
+ break;
+ }
+ }
+ }
+ if (!check_flags && !(rv & CERT_PKEY_ISSUER_NAME))
+ goto end;
+ }
+ else
+ rv |= CERT_PKEY_ISSUER_NAME|CERT_PKEY_CERT_TYPE;
+
+ if (!check_flags || (rv & check_flags) == check_flags)
+ rv |= CERT_PKEY_VALID;
+
+ end:
+
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ if (cpk->valid_flags & CERT_PKEY_EXPLICIT_SIGN)
+ rv |= CERT_PKEY_EXPLICIT_SIGN|CERT_PKEY_SIGN;
+ else if (cpk->digest)
+ rv |= CERT_PKEY_SIGN;
+ }
+ else
+ rv |= CERT_PKEY_SIGN|CERT_PKEY_EXPLICIT_SIGN;
+
+ /* When checking a CERT_PKEY structure all flags are irrelevant
+ * if the chain is invalid.
+ */
+ if (!check_flags)
+ {
+ if (rv & CERT_PKEY_VALID)
+ cpk->valid_flags = rv;
+ else
+ {
+ /* Preserve explicit sign flag, clear rest */
+ cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN;
+ return 0;
+ }
+ }
+ return rv;
+ }
+
+/* Set validity of certificates in an SSL structure */
+void tls1_set_cert_validity(SSL *s)
+ {
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_ENC);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_SIGN);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DSA_SIGN);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_RSA);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_DSA);
+ tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ECC);
+ }
+/* User level utiity function to check a chain is suitable */
+int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
+ {
+ return tls1_check_chain(s, x, pk, chain, -1);
+ }
+
+#endif