Commit 4d43ee28 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Replace TLS_SIGALGS with SIGALG_LOOKUP



Since every supported signature algorithm is now an entry in the
SIGALG_LOOKUP table we can replace shared signature algortihms with
pointers to constant table entries.

Reviewed-by: default avatarRichard Levitte <levitte@openssl.org>
Reviewed-by: default avatarMatt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2301)
parent 8a43a42a
Loading
Loading
Loading
Loading
+20 −13
Original line number Diff line number Diff line
@@ -1509,6 +1509,25 @@ typedef struct {
    size_t meths_count;
} custom_ext_methods;

/*
 * Structure containing table entry of values associated with the signature
 * algorithms (signature scheme) extension
*/
typedef struct sigalg_lookup_st {
    /* TLS 1.3 signature scheme name */
    const char *name;
    /* Raw value used in extension */
    uint16_t sigalg;
    /* NID of hash algorithm */
    int hash;
    /* NID of signature algorithm */
    int sig;
    /* Combined hash and signature NID, if any */
    int sigandhash;
    /* Required public key curve (ECDSA only) */
    int curve;
} SIGALG_LOOKUP;

typedef struct cert_st {
    /* Current active set */
    /*
@@ -1554,7 +1573,7 @@ typedef struct cert_st {
     * Signature algorithms shared by client and server: cached because these
     * are used most often.
     */
    TLS_SIGALGS *shared_sigalgs;
    const SIGALG_LOOKUP **shared_sigalgs;
    size_t shared_sigalgslen;
    /*
     * Certificate setup callback: if set is called whenever a certificate
@@ -1588,18 +1607,6 @@ typedef struct cert_st {
    CRYPTO_RWLOCK *lock;
} CERT;

/* Structure containing decoded values of signature algorithms extension */
struct tls_sigalgs_st {
    /* NID of hash algorithm */
    int hash_nid;
    /* NID of signature algorithm */
    int sign_nid;
    /* Combined hash and signature NID */
    int signandhash_nid;
    /* Raw value used in extension */
    uint16_t rsigalg;
};

# define FP_ICC  (int (*)(const void *,const void *))

/*
+63 −88
Original line number Diff line number Diff line
@@ -607,7 +607,7 @@ static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
        else
            return 0;           /* Should never happen */
        for (i = 0; i < c->shared_sigalgslen; i++)
            if (check_md == c->shared_sigalgs[i].signandhash_nid)
            if (check_md == c->shared_sigalgs[i]->sigandhash)
                break;
        if (i == c->shared_sigalgslen)
            return 0;
@@ -705,15 +705,6 @@ static const uint16_t suiteb_sigalgs[] = {
};
#endif

typedef struct sigalg_lookup_st {
    const char *name;
    uint16_t sigalg;
    int hash;
    int sig;
    int sigandhash;
    int curve;
} SIGALG_LOOKUP;

static const SIGALG_LOOKUP sigalg_lookup_tbl[] = {
#ifndef OPENSSL_NO_EC
    {"ecdsa_secp256r1_sha256", TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
@@ -761,32 +752,32 @@ static const SIGALG_LOOKUP sigalg_lookup_tbl[] = {
#endif
};

static int tls_sigalg_get_hash(uint16_t sigalg)
/* Lookup TLS signature algorithm */
static const SIGALG_LOOKUP *tls1_lookup_sigalg(uint16_t sigalg)
{
    size_t i;
    const SIGALG_LOOKUP *curr;
    const SIGALG_LOOKUP *s;

    for (i = 0, curr = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
         i++, curr++) {
        if (curr->sigalg == sigalg)
            return curr->hash;
    for (i = 0, s = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
         i++, s++) {
        if (s->sigalg == sigalg)
            return s;
    }

    return 0;
    return NULL;
}

static int tls_sigalg_get_sig(uint16_t sigalg)
static int tls_sigalg_get_hash(uint16_t sigalg)
{
    size_t i;
    const SIGALG_LOOKUP *curr;
    const SIGALG_LOOKUP *r = tls1_lookup_sigalg(sigalg);

    for (i = 0, curr = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
         i++, curr++) {
        if (curr->sigalg == sigalg)
            return curr->sig;
    return r != NULL ? r->hash : 0;
}

    return 0;
static int tls_sigalg_get_sig(uint16_t sigalg)
{
    const SIGALG_LOOKUP *r = tls1_lookup_sigalg(sigalg);

    return r != NULL ? r->sig : 0;
}

size_t tls12_get_psigalgs(SSL *s, int sent, const uint16_t **psigs)
@@ -840,6 +831,7 @@ int tls12_check_peer_sigalg(SSL *s, unsigned int sig, EVP_PKEY *pkey)
    size_t sent_sigslen, i;
    int pkeyid = EVP_PKEY_id(pkey);
    int peer_sigtype;

    /* Should never happen */
    if (pkeyid == -1)
        return -1;
@@ -1286,7 +1278,6 @@ int tls12_get_sigandhash(SSL *s, WPACKET *pkt, const EVP_PKEY *pk,
{
    int md_id, sig_id;
    size_t i;
    const TLS_SIGALGS *curr;

    if (md == NULL)
        return 0;
@@ -1298,17 +1289,18 @@ int tls12_get_sigandhash(SSL *s, WPACKET *pkt, const EVP_PKEY *pk,
    if (SSL_IS_TLS13(s) && sig_id == EVP_PKEY_RSA)
        sig_id = EVP_PKEY_RSA_PSS;

    for (i = 0, curr = s->cert->shared_sigalgs; i < s->cert->shared_sigalgslen;
         i++, curr++) {
    for (i = 0; i < s->cert->shared_sigalgslen; i++) {
        const SIGALG_LOOKUP *curr = s->cert->shared_sigalgs[i];

        /*
         * Look for matching key and hash. If key type is RSA also match PSS
         * signature type.
         */
        if (curr->hash_nid == md_nid && (curr->sign_nid == sig_id
            || (sig_id == EVP_PKEY_RSA && curr->sign_nid == EVP_PKEY_RSA_PSS))){
            if (!WPACKET_put_bytes_u16(pkt, curr->rsigalg))
        if (curr->hash == md_id && (curr->sig == sig_id
            || (sig_id == EVP_PKEY_RSA && curr->sig == EVP_PKEY_RSA_PSS))){
            if (!WPACKET_put_bytes_u16(pkt, curr->sigalg))
                return 0;
            *ispss = curr->sign_nid == EVP_PKEY_RSA_PSS;
            *ispss = curr->sig == EVP_PKEY_RSA_PSS;
            return 1;
        }
    }
@@ -1393,30 +1385,6 @@ static int tls12_get_pkey_idx(int sig_nid)
    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, uint16_t data)
{
    int sign_nid = NID_undef, hash_nid = NID_undef;
    if (!phash_nid && !psign_nid && !psignhash_nid)
        return;
    if (phash_nid || psignhash_nid) {
        hash_nid = tls_sigalg_get_hash(data);
        if (phash_nid)
            *phash_nid = hash_nid;
    }
    if (psign_nid || psignhash_nid) {
        sign_nid = tls_sigalg_get_sig(data);
        if (psign_nid)
            *psign_nid = sign_nid;
    }
    if (psignhash_nid) {
        if (sign_nid == NID_undef || hash_nid == NID_undef
            || OBJ_find_sigid_by_algs(psignhash_nid, hash_nid, sign_nid) <= 0)
            *psignhash_nid = NID_undef;
    }
}

/* Check to see if a signature algorithm is allowed */
static int tls12_sigalg_allowed(SSL *s, int op, unsigned int ptmp)
{
@@ -1500,7 +1468,7 @@ int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
}

/* Given preference and allowed sigalgs set shared sigalgs */
static size_t tls12_shared_sigalgs(SSL *s, TLS_SIGALGS *shsig,
static size_t tls12_shared_sigalgs(SSL *s, const SIGALG_LOOKUP **shsig,
                                   const uint16_t *pref, size_t preflen,
                                   const uint16_t *allow, size_t allowlen)
{
@@ -1514,10 +1482,7 @@ static size_t tls12_shared_sigalgs(SSL *s, TLS_SIGALGS *shsig,
            if (*ptmp == *atmp) {
                nmatch++;
                if (shsig) {
                    shsig->rsigalg = *ptmp;
                    tls1_lookup_sigalg(&shsig->hash_nid,
                                       &shsig->sign_nid,
                                       &shsig->signandhash_nid, *ptmp);
                    *shsig = tls1_lookup_sigalg(*ptmp);
                    shsig++;
                }
                break;
@@ -1533,7 +1498,7 @@ static int tls1_set_shared_sigalgs(SSL *s)
    const uint16_t *pref, *allow, *conf;
    size_t preflen, allowlen, conflen;
    size_t nmatch;
    TLS_SIGALGS *salgs = NULL;
    const SIGALG_LOOKUP **salgs = NULL;
    CERT *c = s->cert;
    unsigned int is_suiteb = tls1_suiteb(s);

@@ -1562,7 +1527,7 @@ static int tls1_set_shared_sigalgs(SSL *s)
    }
    nmatch = tls12_shared_sigalgs(s, NULL, pref, preflen, allow, allowlen);
    if (nmatch) {
        salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
        salgs = OPENSSL_malloc(nmatch * sizeof(*salgs));
        if (salgs == NULL)
            return 0;
        nmatch = tls12_shared_sigalgs(s, salgs, pref, preflen, allow, allowlen);
@@ -1620,18 +1585,19 @@ int tls1_process_sigalgs(SSL *s)
    const EVP_MD **pmd = s->s3->tmp.md;
    uint32_t *pvalid = s->s3->tmp.valid_flags;
    CERT *c = s->cert;
    TLS_SIGALGS *sigptr;

    if (!tls1_set_shared_sigalgs(s))
        return 0;

    for (i = 0, sigptr = c->shared_sigalgs;
         i < c->shared_sigalgslen; i++, sigptr++) {
    for (i = 0; i < c->shared_sigalgslen; i++) {
        const SIGALG_LOOKUP *sigptr = c->shared_sigalgs[i];

        /* Ignore PKCS1 based sig algs in TLSv1.3 */
        if (SSL_IS_TLS13(s) && sigptr->sign_nid == EVP_PKEY_RSA)
        if (SSL_IS_TLS13(s) && sigptr->sig == EVP_PKEY_RSA)
            continue;
        idx = tls12_get_pkey_idx(sigptr->sign_nid);
        idx = tls12_get_pkey_idx(sigptr->sig);
        if (idx > 0 && pmd[idx] == NULL) {
            md = tls12_get_hash(sigptr->hash_nid);
            md = tls12_get_hash(sigptr->hash);
            pmd[idx] = md;
            pvalid[idx] = CERT_PKEY_EXPLICIT_SIGN;
            if (idx == SSL_PKEY_RSA_SIGN) {
@@ -1688,14 +1654,22 @@ int SSL_get_sigalgs(SSL *s, int idx,
    if (psig == NULL || numsigalgs > INT_MAX)
        return 0;
    if (idx >= 0) {
        const SIGALG_LOOKUP *lu;

        if (idx >= (int)numsigalgs)
            return 0;
        psig += idx;
        if (rhash)
        if (rhash != NULL)
            *rhash = (unsigned char)((*psig >> 8) & 0xff);
        if (rsig)
        if (rsig != NULL)
            *rsig = (unsigned char)(*psig & 0xff);
        tls1_lookup_sigalg(phash, psign, psignhash, *psig);
        lu = tls1_lookup_sigalg(*psig);
        if (psign != NULL)
            *psign = lu != NULL ? lu->sig : NID_undef;
        if (phash != NULL)
            *phash = lu != NULL ? lu->hash : NID_undef;
        if (psignhash != NULL)
            *psignhash = lu != NULL ? lu->sigandhash : NID_undef;
    }
    return (int)numsigalgs;
}
@@ -1704,21 +1678,22 @@ 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
    const SIGALG_LOOKUP *shsigalgs;
    if (s->cert->shared_sigalgs == NULL
        || idx >= (int)s->cert->shared_sigalgslen
        || s->cert->shared_sigalgslen > INT_MAX)
        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 = (unsigned char)(shsigalgs->rsigalg & 0xff);
    if (rhash)
        *rhash = (unsigned char)((shsigalgs->rsigalg >> 8) & 0xff);
    shsigalgs = s->cert->shared_sigalgs[idx];
    if (phash != NULL)
        *phash = shsigalgs->hash;
    if (psign != NULL)
        *psign = shsigalgs->sig;
    if (psignhash != NULL)
        *psignhash = shsigalgs->sigandhash;
    if (rsig != NULL)
        *rsig = (unsigned char)(shsigalgs->sigalg & 0xff);
    if (rhash != NULL)
        *rhash = (unsigned char)((shsigalgs->sigalg >> 8) & 0xff);
    return (int)s->cert->shared_sigalgslen;
}

@@ -1864,7 +1839,7 @@ static int tls1_check_sig_alg(CERT *c, X509 *x, int default_nid)
    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)
        if (sig_nid == c->shared_sigalgs[i]->sigandhash)
            return 1;
    return 0;
}