/* -*- 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/. */

#ifndef __sslspec_h_
#define __sslspec_h_

#include "sslexp.h"
#include "prclist.h"

typedef enum {
    TrafficKeyClearText = 0,
    TrafficKeyEarlyApplicationData = 1,
    TrafficKeyHandshake = 2,
    TrafficKeyApplicationData = 3
} TrafficKeyType;

typedef enum {
    CipherSpecRead,
    CipherSpecWrite,
} CipherSpecDirection;

#define SPEC_DIR(spec) \
    ((spec->direction == CipherSpecRead) ? "read" : "write")

typedef struct ssl3CipherSpecStr ssl3CipherSpec;
typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef;
typedef struct ssl3MACDefStr ssl3MACDef;
typedef struct ssl3CipherSuiteDefStr ssl3CipherSuiteDef;
typedef PRUint64 sslSequenceNumber;
typedef PRUint16 DTLSEpoch;

/* The SSL bulk cipher definition */
typedef enum {
    cipher_null,
    cipher_rc4,
    cipher_des,
    cipher_3des,
    cipher_aes_128,
    cipher_aes_256,
    cipher_camellia_128,
    cipher_camellia_256,
    cipher_seed,
    cipher_aes_128_gcm,
    cipher_aes_256_gcm,
    cipher_chacha20,
    cipher_missing /* reserved for no such supported cipher */
    /* This enum must match ssl3_cipherName[] in ssl3con.c.  */
} SSL3BulkCipher;

typedef enum {
    type_stream,
    type_block,
    type_aead
} CipherType;

/*
** There are tables of these, all const.
*/
struct ssl3BulkCipherDefStr {
    SSL3BulkCipher cipher;
    SSLCipherAlgorithm calg;
    unsigned int key_size;
    unsigned int secret_key_size;
    CipherType type;
    unsigned int iv_size;
    unsigned int block_size;
    unsigned int tag_size;            /* for AEAD ciphers. */
    unsigned int explicit_nonce_size; /* for AEAD ciphers. */
    SECOidTag oid;
    const char *short_name;
    /* The maximum number of records that can be sent/received with the same
      * symmetric key before the connection will be terminated. */
    PRUint64 max_records;
};

/* to make some of these old enums public without namespace pollution,
** it was necessary to prepend ssl_ to the names.
** These #defines preserve compatibility with the old code here in libssl.
*/
typedef SSLMACAlgorithm SSL3MACAlgorithm;

/*
 * There are tables of these, all const.
 */
struct ssl3MACDefStr {
    SSL3MACAlgorithm mac;
    CK_MECHANISM_TYPE mmech;
    int pad_size;
    int mac_size;
    SECOidTag oid;
};

#define MAX_IV_LENGTH 24

typedef struct {
    PK11SymKey *key;
    PK11SymKey *macKey;
    PK11Context *macContext;
    PRUint8 iv[MAX_IV_LENGTH];
} ssl3KeyMaterial;

typedef SECStatus (*SSLCipher)(void *context,
                               unsigned char *out,
                               int *outlen,
                               int maxout,
                               const unsigned char *in,
                               int inlen);
typedef SECStatus (*SSLAEADCipher)(
    ssl3KeyMaterial *keys,
    PRBool doDecrypt,
    unsigned char *out,
    int *outlen,
    int maxout,
    const unsigned char *in,
    int inlen,
    const unsigned char *additionalData,
    int additionalDataLen);

/* The DTLS anti-replay window in number of packets. Defined here because we
 * need it in the cipher spec. Note that this is a ring buffer but left and
 * right represent the true window, with modular arithmetic used to map them
 * onto the buffer.
 */
#define DTLS_RECVD_RECORDS_WINDOW 1024
#define RECORD_SEQ_MASK ((1ULL << 48) - 1)
#define RECORD_SEQ_MAX RECORD_SEQ_MASK
PR_STATIC_ASSERT(DTLS_RECVD_RECORDS_WINDOW % 8 == 0);

typedef struct DTLSRecvdRecordsStr {
    unsigned char data[DTLS_RECVD_RECORDS_WINDOW / 8];
    sslSequenceNumber left;
    sslSequenceNumber right;
} DTLSRecvdRecords;

/*
 * These are the "specs" used for reading and writing records.  Access to the
 * pointers to these specs, and all the specs' contents (direct and indirect) is
 * protected by the reader/writer lock ss->specLock.
 */
struct ssl3CipherSpecStr {
    PRCList link;
    PRUint8 refCt;

    CipherSpecDirection direction;
    SSL3ProtocolVersion version;
    SSL3ProtocolVersion recordVersion;

    const ssl3BulkCipherDef *cipherDef;
    const ssl3MACDef *macDef;

    SSLCipher cipher;
    SSLAEADCipher aead;
    void *cipherContext;

    PK11SymKey *masterSecret;
    ssl3KeyMaterial keyMaterial;

    DTLSEpoch epoch;
    const char *phase;

    /* The next sequence number to be sent or received. */
    sslSequenceNumber nextSeqNum;
    DTLSRecvdRecords recvdRecords;

    /* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This
     * will be zero for everything but 0-RTT. */
    PRUint32 earlyDataRemaining;
    /* The maximum plaintext length.  This differs from the configured or
     * negotiated value for TLS 1.3; it is reduced by one to account for the
     * content type octet. */
    PRUint16 recordSizeLimit;
};

typedef void (*sslCipherSpecChangedFunc)(void *arg,
                                         PRBool sending,
                                         ssl3CipherSpec *newSpec);

const ssl3BulkCipherDef *ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def);
const ssl3MACDef *ssl_GetMacDefByAlg(SSL3MACAlgorithm mac);
const ssl3MACDef *ssl_GetMacDef(const sslSocket *ss, const ssl3CipherSuiteDef *suiteDef);

ssl3CipherSpec *ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction);
void ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec);
void ssl_CipherSpecAddRef(ssl3CipherSpec *spec);
void ssl_CipherSpecRelease(ssl3CipherSpec *spec);
void ssl_DestroyCipherSpecs(PRCList *list);
SECStatus ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir);

ssl3CipherSpec *ssl_FindCipherSpecByEpoch(sslSocket *ss,
                                          CipherSpecDirection direction,
                                          DTLSEpoch epoch);
void ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection direction,
                                  DTLSEpoch epoch);

#endif /* __sslspec_h_ */