Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/src/tls/   (Postfix Mailserver Version 3.11©)  Datei vom 7.7.2023 mit Größe 13 kB image not shown  

Quelle  tls_fprint.c

  Sprache: C
 

/*++
/* NAME
/* tls_fprint 3
/* SUMMARY
/* Digests fingerprints and all that.
/* SYNOPSIS
/* #include <tls.h>
/*
/* EVP_MD *tls_digest_byname(const char *mdalg, EVP_MD_CTX **mdctxPtr)
/* const char *mdalg;
/* EVP_MD_CTX **mdctxPtr;
/*
/* char *tls_serverid_digest(TLScontext, props, ciphers)
/* TLS_SESS_STATE *TLScontext;
/* const TLS_CLIENT_START_PROPS *props;
/* const char *ciphers;
/*
/* char *tls_digest_encode(md_buf, md_len)
/* const unsigned char *md_buf;
/* const char *md_len;
/*
/* char *tls_cert_fprint(peercert, mdalg)
/* X509 *peercert;
/* const char *mdalg;
/*
/* char *tls_pkey_fprint(peercert, mdalg)
/* EVP_PKEY *peerpkey;
/* const char *mdalg;
/* DESCRIPTION
/* tls_digest_byname() constructs, and optionally returns, an EVP_MD_CTX
/* handle for performing digest operations with the algorithm named by the
/* mdalg parameter.  The return value is non-null on success, and holds a
/* digest algorithm handle.  If the mdctxPtr argument is non-null the
/* created context is returned to the caller, who is then responsible for
/* deleting it by calling EVP_MD_ctx_free() once it is no longer needed.
/*
/* tls_digest_encode() converts a binary message digest to a hex ASCII
/* format with ':' separators between each pair of hex digits.
/* The return value is dynamically allocated with mymalloc(),
/* and the caller must eventually free it with myfree().
/*
/* tls_cert_fprint() returns a fingerprint of the given
/* certificate using the requested message digest, formatted
/* with tls_digest_encode(). Panics if the
/* (previously verified) digest algorithm is not found. The return
/* value is dynamically allocated with mymalloc(), and the caller
/* must eventually free it with myfree().
/*
/* tls_pkey_fprint() returns a public-key fingerprint; in all
/* other respects the function behaves as tls_cert_fprint().
/* The return value is dynamically allocated with mymalloc(),
/* and the caller must eventually free it with myfree().
/*
/* tls_serverid_digest() suffixes props->serverid computed by the SMTP
/* client with "&" plus a digest of additional parameters needed to ensure
/* that re-used sessions are more likely to be reused and that they will
/* satisfy all protocol and security requirements.  The return value is
/* dynamically allocated with mymalloc(), and the caller must eventually
/* free it with myfree().
/*
/* Arguments:
/* .IP mdalg
/* A digest algorithm name, such as "sha256".
/* .IP peercert
/* Server or client X.509 certificate.
/* .IP md_buf
/* The raw binary digest.
/* .IP md_len
/* The digest length in bytes.
/* .IP mdalg
/* Name of a message digest algorithm suitable for computing secure
/* (1st pre-image resistant) message digests of certificates. For now,
/* md5, sha1, or member of SHA-2 family if supported by OpenSSL.
/* .IP mdctxPtr
/* Pointer to an (EVP_MD_CTX *) handle, or NULL if only probing for
/* algorithm support without immediate use in mind.
/* .IP buf
/* Input data for the message digest algorithm mdalg.
/* .IP len
/* The length of the input data.
/* .IP props
/* The client start properties for the session, which contains the
/* initial serverid from the SMTP client and the DANE verification
/* parameters.
/* .IP protomask
/* The mask of protocol exclusions.
/* .IP ciphers
/* The SSL client cipherlist.
/* LICENSE
/* .ad
/* .fi
/* This software is free. You can do with it whatever you want.
/* The original author kindly requests that you acknowledge
/* the use of his software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Viktor Dukhovni
/*--*/


/* System library. */

#include <sys_defs.h>
#include <ctype.h>

#ifdef USE_TLS
#include <string.h>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>

/* Global library. */

#include <mail_params.h>

/* TLS library. */

#define TLS_INTERNAL
#include <tls.h>

/* Application-specific. */

static const char hexcodes[] = "0123456789ABCDEF";

#define CHECK_OK_AND(stillok) (ok = ok && (stillok))
#define CHECK_OK_AND_DIGEST_OBJECT(m, p) \
 CHECK_OK_AND_DIGEST_DATA((m), (unsigned char *)(p), sizeof(*(p)))
#define CHECK_OK_AND_DIGEST_DATA(m, p, l) CHECK_OK_AND(digest_bytes((m), (p), (l)))
#define CHECK_OK_AND_DIGEST_CHARS(m, s) CHECK_OK_AND(digest_chars((m), (s)))

/* digest_bytes - hash octet string of given length */

static int digest_bytes(EVP_MD_CTX *ctx, const unsigned char *buf, size_t len)
{
    return (EVP_DigestUpdate(ctx, buf, len));
}

/* digest_chars - hash string including trailing NUL */

static int digest_chars(EVP_MD_CTX *ctx, const char *s)
{
    return (EVP_DigestUpdate(ctx, s, strlen(s) + 1));
}

/* tlsa_cmp - compare TLSA RRs for sorting to canonical order */

static int tlsa_cmp(const void *a, const void *b)
{
    TLS_TLSA *p = *(TLS_TLSA **) a;
    TLS_TLSA *q = *(TLS_TLSA **) b;
    int     d;

    if ((d = (int) p->usage - (int) q->usage) != 0)
 return d;
    if ((d = (int) p->selector - (int) q->selector) != 0)
 return d;
    if ((d = (int) p->mtype - (int) q->mtype) != 0)
 return d;
    if ((d = (int) p->length - (int) q->length) != 0)
 return d;
    return (memcmp(p->data, q->data, p->length));
}

/* tls_digest_tlsa - fold in digest of TLSA records */

static int tls_digest_tlsa(EVP_MD_CTX *mdctx, TLS_TLSA *tlsa)
{
    TLS_TLSA *p;
    TLS_TLSA **arr;
    int     ok = 1;
    int     n;
    int     i;

    for (n = 0, p = tlsa; p != 0; p = p->next)
 ++n;
    arr = (TLS_TLSA **) mymalloc(n * sizeof(*arr));
    for (i = 0, p = tlsa; p; p = p->next)
 arr[i++] = (void *) p;
    qsort(arr, n, sizeof(arr[0]), tlsa_cmp);

    CHECK_OK_AND_DIGEST_OBJECT(mdctx, &n);
    for (i = 0; i < n; ++i) {
 CHECK_OK_AND_DIGEST_OBJECT(mdctx, &arr[i]->usage);
 CHECK_OK_AND_DIGEST_OBJECT(mdctx, &arr[i]->selector);
 CHECK_OK_AND_DIGEST_OBJECT(mdctx, &arr[i]->mtype);
 CHECK_OK_AND_DIGEST_OBJECT(mdctx, &arr[i]->length);
 CHECK_OK_AND_DIGEST_DATA(mdctx, arr[i]->data, arr[i]->length);
    }
    myfree((void *) arr);
    return (ok);
}

/* tls_digest_byname - test availability or prepare to use digest */

const EVP_MD *tls_digest_byname(const char *mdalg, EVP_MD_CTX **mdctxPtr)
{
    const EVP_MD *md;
    EVP_MD_CTX *mdctx = NULL;
    int     ok = 1;

    /*
     * In OpenSSL 3.0, because of dynamically variable algorithm providers,
     * there is a time-of-check/time-of-use issue that means that abstract
     * algorithm handles returned by EVP_get_digestbyname() can (and not
     * infrequently do) return ultimately unusable algorithms, to check for
     * actual availability, one needs to use the new EVP_MD_fetch() API, or
     * indirectly check usability by creating a concrete context. We take the
     * latter approach here (works for 1.1.1 without #ifdef).
     * 
     * Note that EVP_MD_CTX_{create,destroy} were renamed to, respectively,
     * EVP_MD_CTX_{new,free} in OpenSSL 1.1.0.
     */

    CHECK_OK_AND(md = EVP_get_digestbyname(mdalg));

    /*
     * Sanity check: Newer shared libraries could (hypothetical ABI break)
     * allow larger digests, we avoid such poison algorithms.
     */

    CHECK_OK_AND(EVP_MD_size(md) <= EVP_MAX_MD_SIZE);
    CHECK_OK_AND(mdctx = EVP_MD_CTX_new());
    CHECK_OK_AND(EVP_DigestInit_ex(mdctx, md, NULL));


    if (ok && mdctxPtr != 0)
 *mdctxPtr = mdctx;
    else
 EVP_MD_CTX_free(mdctx);
    return (ok ? md : 0);
}

/* tls_serverid_digest - suffix props->serverid with parameter digest */

char   *tls_serverid_digest(TLS_SESS_STATE *TLScontext,
               const TLS_CLIENT_START_PROPS *props,
               const char *ciphers)
{
    EVP_MD_CTX *mdctx;
    const char *mdalg;
    unsigned char md_buf[EVP_MAX_MD_SIZE];
    unsigned int md_len;
    int     ok = 1;
    int     i;
    long    sslversion;
    VSTRING *result;

    /*
     * Try to use sha256: our serverid choice should be strong enough to
     * resist 2nd-preimage attacks with a difficulty comparable to that of
     * DANE TLSA digests.  Failing that, we compute serverid digests with the
     * default digest, but DANE requires sha256 and sha512, so if we must
     * fall back to our default digest, DANE support won't be available.  We
     * panic if the fallback algorithm is not available, as it was verified
     * available in tls_client_init() and must not simply vanish.  Our
     * provider set is not expected to change once the OpenSSL library is
     * initialized.
     */

    if (tls_digest_byname(mdalg = LN_sha256, &mdctx) == 0
 && tls_digest_byname(mdalg = props->mdalg, &mdctx) == 0)
 msg_panic("digest algorithm \"%s\" not found", props->mdalg);

    /* Salt the session lookup key with the OpenSSL runtime version. */
    sslversion = OpenSSL_version_num();

    CHECK_OK_AND_DIGEST_CHARS(mdctx, props->helo ? props->helo : "");
    CHECK_OK_AND_DIGEST_OBJECT(mdctx, &sslversion);
    CHECK_OK_AND_DIGEST_CHARS(mdctx, props->protocols);
    CHECK_OK_AND_DIGEST_CHARS(mdctx, ciphers);

    /* Just in case we make this destination-policy specific */
    CHECK_OK_AND_DIGEST_OBJECT(mdctx, &props->enable_rpk);

    /*
     * Ensure separation of caches for sessions where DANE trust
     * configuration succeeded from those where it did not.  The latter
     * should always see a certificate validation failure, both on initial
     * handshake and on resumption.
     */

    CHECK_OK_AND_DIGEST_OBJECT(mdctx, &TLScontext->must_fail);

    /*
     * DNS-based or synthetic DANE trust settings are potentially used at all
     * levels above "encrypt".
     */

    if (TLScontext->level > TLS_LEV_ENCRYPT
 && props->dane && props->dane->tlsa) {
 CHECK_OK_AND(tls_digest_tlsa(mdctx, props->dane->tlsa));
    } else {
 int     none = 0;  /* Record a TLSA RR count of zero */

 CHECK_OK_AND_DIGEST_OBJECT(mdctx, &none);
    }

    /*
     * Include the chosen SNI name, which can affect server certificate
     * selection.
     */

    if (TLScontext->level > TLS_LEV_ENCRYPT && TLScontext->peer_sni)
 CHECK_OK_AND_DIGEST_CHARS(mdctx, TLScontext->peer_sni);
    else
 CHECK_OK_AND_DIGEST_CHARS(mdctx, "");

    CHECK_OK_AND(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
    EVP_MD_CTX_destroy(mdctx);
    if (!ok)
 msg_fatal("error computing %s message digest", mdalg);

    /* Check for OpenSSL contract violation */
    if (md_len > EVP_MAX_MD_SIZE)
 msg_panic("unexpectedly large %s digest size: %u", mdalg, md_len);

    /*
     * Append the digest to the serverid.  We don't compare this digest to
     * any user-specified fingerprints.  Therefore, we don't need to use a
     * colon-separated format, which saves space in the TLS session cache and
     * makes logging of session cache lookup keys more readable.
     * 
     * This does however duplicate a few lines of code from the digest encoder
     * for colon-separated cert and pkey fingerprints. If that is a
     * compelling reason to consolidate, we could use that and append the
     * result.
     */

    result = vstring_alloc(strlen(props->serverid) + 1 + 2 * md_len);
    vstring_strcpy(result, props->serverid);
    VSTRING_ADDCH(result, '&');
    for (i = 0; i < md_len; i++) {
 VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0xf0) >> 4U]);
 VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0x0f)]);
    }
    VSTRING_TERMINATE(result);
    return (vstring_export(result));
}

/* tls_digest_encode - encode message digest binary blob as xx:xx:... */

char   *tls_digest_encode(const unsigned char *md_buf, int md_len)
{
    int     i;
    char   *result = mymalloc(md_len * 3);

    /* Check for contract violation */
    if (md_len > EVP_MAX_MD_SIZE || md_len >= INT_MAX / 3)
 msg_panic("unexpectedly large message digest size: %u", md_len);

    /* No risk of overruns, len is bounded by OpenSSL digest length */
    for (i = 0; i < md_len; i++) {
 result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U];
 result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)];
 result[(i * 3) + 2] = (i + 1 != md_len) ? ':' : '\0';
    }
    return (result);
}

/* tls_data_fprint - compute and encode digest of binary object */

static char *tls_data_fprint(const unsigned char *buf, int len, const char *mdalg)
{
    EVP_MD_CTX *mdctx = NULL;
    unsigned char md_buf[EVP_MAX_MD_SIZE];
    unsigned int md_len;
    int     ok = 1;

    /* Previously available in "init" routine. */
    if (tls_digest_byname(mdalg, &mdctx) == 0)
 msg_panic("digest algorithm \"%s\" not found", mdalg);

    CHECK_OK_AND_DIGEST_DATA(mdctx, buf, len);
    CHECK_OK_AND(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
    EVP_MD_CTX_destroy(mdctx);
    if (!ok)
 msg_fatal("error computing %s message digest", mdalg);

    return (tls_digest_encode(md_buf, md_len));
}

/* tls_cert_fprint - extract certificate fingerprint */

char   *tls_cert_fprint(X509 *peercert, const char *mdalg)
{
    int     len;
    unsigned char *buf;
    unsigned char *buf2;
    char   *result;

    len = i2d_X509(peercert, NULL);
    buf2 = buf = mymalloc(len);
    i2d_X509(peercert, &buf2);
    if (buf2 - buf != len)
 msg_panic("i2d_X509 invalid result length");

    result = tls_data_fprint(buf, len, mdalg);
    myfree(buf);

    return (result);
}

/* tls_pkey_fprint - extract public key fingerprint */

char   *tls_pkey_fprint(EVP_PKEY *peerpkey, const char *mdalg)
{
    int     len;
    unsigned char *buf;
    unsigned char *buf2;
    char   *result;

    len = i2d_PUBKEY(peerpkey, NULL);
    buf2 = buf = mymalloc(len);
    i2d_PUBKEY(peerpkey, &buf2);
    if (buf2 - buf != len)
 msg_panic("i2d_PUBKEY invalid result length");

    result = tls_data_fprint(buf, len, mdalg);
    myfree(buf);
    return (result);
}

#endif

Messung V0.5 in Prozent
C=70 H=93 G=82

¤ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet am  2026-08-09) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.