Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/security/nss/lib/ssl/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

Quelle  tls13hashstate.c   Sprache: C

 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is PRIVATE to SSL.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "pk11func.h"
#include "ssl.h"
#include "sslt.h"
#include "sslimpl.h"
#include "selfencrypt.h"
#include "tls13con.h"
#include "tls13ech.h"
#include "tls13err.h"
#include "tls13hashstate.h"

/*
 * The cookie is structured as a self-encrypted structure with the
 * inner value being.
 *
 * struct {
 *     uint8 indicator = 0xff;            // To disambiguate from tickets.
 *     uint16 cipherSuite;                // Selected cipher suite.
 *     uint16 keyShare;                   // Requested key share group (0=none)
 *     PRUint8 echConfigId;               // ECH config_id
 *     HpkeKdfId kdfId;                   // ECH KDF (uint16)
 *     HpkeAeadId aeadId;                 // ECH AEAD (uint16)
 *     opaque echHpkeCtx<0..65535>;       // ECH serialized HPKE context
 *     opaque applicationToken<0..65535>; // Application token
 *     opaque ch_hash[rest_of_buffer];    // H(ClientHello)
 * } CookieInner;
 *
 * An empty echConfigId means that ECH was not offered in the first ClientHello.
 * An empty echHrrPsk means that ECH was not accepted in CH1.
 */

SECStatus
tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
                    const PRUint8 *appToken, unsigned int appTokenLen,
                    PRUint8 *buf, unsigned int *len, unsigned int maxlen)
{
    SECStatus rv;
    SSL3Hashes hashes;
    PRUint8 cookie[1024];
    sslBuffer cookieBuf = SSL_BUFFER(cookie);
    static const PRUint8 indicator = 0xff;
    SECItem *echHpkeCtx = NULL;

    /* Encode header. */
    rv = sslBuffer_Append(&cookieBuf, &indicator, 1);
    if (rv != SECSuccess) {
        return SECFailure;
    }
    rv = sslBuffer_AppendNumber(&cookieBuf, ss->ssl3.hs.cipher_suite, 2);
    if (rv != SECSuccess) {
        return SECFailure;
    }
    rv = sslBuffer_AppendNumber(&cookieBuf,
                                selectedGroup ? selectedGroup->name : 0, 2);
    if (rv != SECSuccess) {
        return SECFailure;
    }

    if (ss->xtnData.ech) {
        /* Record that we received ECH. See sslEchCookieData */
        rv = sslBuffer_AppendNumber(&cookieBuf, PR_TRUE, 1);
        if (rv != SECSuccess) {
            return SECFailure;
        }

        rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->configId,
                                    1);
        if (rv != SECSuccess) {
            return SECFailure;
        }

        rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->kdfId, 2);
        if (rv != SECSuccess) {
            return SECFailure;
        }
        rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->aeadId, 2);
        if (rv != SECSuccess) {
            return SECFailure;
        }
        /* We need to send a ECH HRR Extension containing a signal for the client,
         * we must store the signal in the cookie so we can reconstruct the transcript
         * later. To avoid leaking whether ECH was accepted in the length of the cookie
         * we include the empty signal in the cookie regardless.
         */

        PR_ASSERT(SSL_BUFFER_LEN(&ss->ssl3.hs.greaseEchBuf) == TLS13_ECH_SIGNAL_LEN);
        rv = sslBuffer_AppendBuffer(&cookieBuf, &ss->ssl3.hs.greaseEchBuf);
        if (rv != SECSuccess) {
            return SECFailure;
        }

        /* There might be no HPKE Context, e.g. when we lack a matching ECHConfig. */
        if (ss->ssl3.hs.echHpkeCtx) {
            rv = PK11_HPKE_ExportContext(ss->ssl3.hs.echHpkeCtx, NULL, &echHpkeCtx);
            if (rv != SECSuccess) {
                return SECFailure;
            }
            rv = sslBuffer_AppendVariable(&cookieBuf, echHpkeCtx->data, echHpkeCtx->len, 2);
            SECITEM_ZfreeItem(echHpkeCtx, PR_TRUE);
        } else {
            /* Zero length HPKE context. */
            rv = sslBuffer_AppendNumber(&cookieBuf, 0, 2);
        }
        if (rv != SECSuccess) {
            return SECFailure;
        }
    } else {
        rv = sslBuffer_AppendNumber(&cookieBuf, PR_FALSE, 1);
        if (rv != SECSuccess) {
            return SECFailure;
        }
    }

    /* Application token. */
    rv = sslBuffer_AppendVariable(&cookieBuf, appToken, appTokenLen, 2);
    if (rv != SECSuccess) {
        return SECFailure;
    }

    /* Compute and encode hashes. */
    rv = tls13_ComputeHandshakeHashes(ss, &hashes);
    if (rv != SECSuccess) {
        return SECFailure;
    }
    rv = sslBuffer_Append(&cookieBuf, hashes.u.raw, hashes.len);
    if (rv != SECSuccess) {
        return SECFailure;
    }

    /* Encrypt right into the buffer. */
    rv = ssl_SelfEncryptProtect(ss, cookieBuf.buf, cookieBuf.len,
                                buf, len, maxlen);
    if (rv != SECSuccess) {
        return SECFailure;
    }

    return SECSuccess;
}

/* Given a cookie and cookieLen, decrypt and parse, returning
 * any values that were requested via the "previous_" params. If
 * recoverState is true, the transcript state and application
 * token are restored. Note that previousEchKdfId, previousEchAeadId,
 * previousEchConfigId, and previousEchHpkeCtx are not modified if ECH was not
 * previously negotiated (i.e., previousEchOffered is PR_FALSE). */

SECStatus
tls13_HandleHrrCookie(sslSocket *ss,
                      unsigned char *cookie, unsigned int cookieLen,
                      ssl3CipherSuite *previousCipherSuite,
                      const sslNamedGroupDef **previousGroup,
                      PRBool *previousOfferedEch,
                      sslEchCookieData *echData,
                      PRBool recoverState)
{
    SECStatus rv;
    unsigned char plaintext[1024];
    unsigned int plaintextLen = 0;
    sslBuffer messageBuf = SSL_BUFFER_EMPTY;
    sslReadBuffer echHpkeBuf = { 0 };
    PRBool receivedEch;
    PRUint64 sentinel;
    PRUint64 cipherSuite;
    sslEchCookieData parsedEchData = { 0 };
    sslReadBuffer greaseReadBuf = { 0 };
    PRUint64 group;
    PRUint64 tmp64;
    const sslNamedGroupDef *selectedGroup;
    PRUint64 appTokenLen;

    rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen,
                                  plaintext, &plaintextLen, sizeof(plaintext));
    if (rv != SECSuccess) {
        SSL_TRC(100, ("Error decrypting cookie."));
        return SECFailure;
    }

    sslReader reader = SSL_READER(plaintext, plaintextLen);

    /* Should start with the sentinel value. */
    rv = sslRead_ReadNumber(&reader, 1, &sentinel);
    if ((rv != SECSuccess) || (sentinel != TLS13_COOKIE_SENTINEL)) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
        return SECFailure;
    }
    /* The cipher suite should be the same or there are some shenanigans. */
    rv = sslRead_ReadNumber(&reader, 2, &cipherSuite);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
        return SECFailure;
    }

    /* The named group, if any. */
    rv = sslRead_ReadNumber(&reader, 2, &group);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
        return SECFailure;
    }
    selectedGroup = ssl_LookupNamedGroup(group);

    /* Was ECH received. */
    rv = sslRead_ReadNumber(&reader, 1, &tmp64);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
        return SECFailure;
    }
    receivedEch = tmp64 == PR_TRUE;
    *previousOfferedEch = receivedEch;
    if (receivedEch) {
        /* ECH config ID */
        rv = sslRead_ReadNumber(&reader, 1, &tmp64);
        if (rv != SECSuccess) {
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
            return SECFailure;
        }
        parsedEchData.configId = (PRUint8)tmp64;

        /* ECH Ciphersuite */
        rv = sslRead_ReadNumber(&reader, 2, &tmp64);
        if (rv != SECSuccess) {
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
            return SECFailure;
        }
        parsedEchData.kdfId = (HpkeKdfId)tmp64;

        rv = sslRead_ReadNumber(&reader, 2, &tmp64);
        if (rv != SECSuccess) {
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
            return SECFailure;
        }
        parsedEchData.aeadId = (HpkeAeadId)tmp64;

        /* ECH accept_confirmation signal. */
        rv = sslRead_Read(&reader, TLS13_ECH_SIGNAL_LEN, &greaseReadBuf);
        if (rv != SECSuccess) {
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
            return SECFailure;
        }
        PORT_Memcpy(parsedEchData.signal, greaseReadBuf.buf, TLS13_ECH_SIGNAL_LEN);

        /* ECH HPKE context may be empty. */
        rv = sslRead_ReadVariable(&reader, 2, &echHpkeBuf);
        if (rv != SECSuccess) {
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
            return SECFailure;
        }
        if (echData && echHpkeBuf.len) {
            const SECItem hpkeItem = { siBuffer, CONST_CAST(unsigned char, echHpkeBuf.buf),
                                       echHpkeBuf.len };
            parsedEchData.hpkeCtx = PK11_HPKE_ImportContext(&hpkeItem, NULL);
            if (!parsedEchData.hpkeCtx) {
                FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
                return SECFailure;
            }
        }
    }

    /* Application token. */
    rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
        return SECFailure;
    }
    sslReadBuffer appTokenReader = { 0 };
    rv = sslRead_Read(&reader, appTokenLen, &appTokenReader);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
        return SECFailure;
    }
    PORT_Assert(appTokenReader.len == appTokenLen);

    if (recoverState) {
        PORT_Assert(ss->xtnData.applicationToken.len == 0);
        if (SECITEM_AllocItem(NULL, &ss->xtnData.applicationToken,
                              appTokenLen) == NULL) {
            FATAL_ERROR(ss, PORT_GetError(), internal_error);
            return SECFailure;
        }
        PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
        ss->xtnData.applicationToken.len = appTokenLen;

        /* The remainder is the hash. */
        unsigned int hashLen = SSL_READER_REMAINING(&reader);
        if (hashLen != tls13_GetHashSize(ss)) {
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
            return SECFailure;
        }

        /* Now reinject the message. */
        SSL_ASSERT_HASHES_EMPTY(ss);
        rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
                                         SSL_READER_CURRENT(&reader), hashLen,
                                         ssl3_UpdateHandshakeHashes);
        if (rv != SECSuccess) {
            return SECFailure;
        }

        /* And finally reinject the HRR. */
        rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite,
                                              selectedGroup,
                                              cookie, cookieLen,
                                              parsedEchData.signal,
                                              &messageBuf);
        if (rv != SECSuccess) {
            return SECFailure;
        }

        rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0,
                                         SSL_BUFFER_BASE(&messageBuf),
                                         SSL_BUFFER_LEN(&messageBuf),
                                         ssl3_UpdateHandshakeHashes);
        sslBuffer_Clear(&messageBuf);
        if (rv != SECSuccess) {
            return SECFailure;
        }
    }

    if (previousCipherSuite) {
        *previousCipherSuite = cipherSuite;
    }
    if (previousGroup) {
        *previousGroup = selectedGroup;
    }
    if (echData) {
        PORT_Memcpy(echData, &parsedEchData, sizeof(parsedEchData));
    }
    return SECSuccess;
}

Messung V0.5
C=93 H=100 G=96

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

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.