+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, hash_nid;
+ 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;
+ conf = c->conf_sigalgs;
+ if (conf)
+ conflen = c->conf_sigalgslen;
+ else
+ {
+ conf = tls12_sigalgs;
+ conflen = sizeof(tls12_sigalgs);
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode())
+ conflen -= 2;
+#endif
+ }
+ if(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+ {
+ 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;
+ }
+
+