* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#ifndef TLS_H
#define TLS_H
#include <stdint.h>
#include <stdbool.h>
#include "hitls_build.h"
#include "cipher_suite.h"
#include "tls_config.h"
#include "hitls_error.h"
#include "hitls.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_DIGEST_SIZE 64UL
#define DTLS_DEFAULT_PMTU 1500uL
The supported maximum length of SCTP user messages MUST be at least
2^14 + 2048 + 13 = 18445 bytes (2^14 + 2048 is the maximum length of
the DTLSCiphertext.fragment, and 13 is the size of the DTLS record
header). */
#define DTLS_SCTP_PMTU 18445uL
#define IS_DTLS_VERSION(version) (((version) & 0x8u) == 0x8u)
#define IS_TLS13_FAMILY_VERSION(version) ((version) == HITLS_VERSION_TLS13 || (version) == HITLS_VERSION_DTLS13)
#define IS_SUPPORT_STREAM(versionBits) (((versionBits) & STREAM_VERSION_BITS) != 0x0u)
#define IS_SUPPORT_DATAGRAM(versionBits) (((versionBits) & DATAGRAM_VERSION_BITS) != 0x0u)
#define IS_SUPPORT_TLCP(versionBits) (((versionBits) & TLCP_VERSION_BITS) != 0x0u)
#define IS_SUPPORT_TLS(versionBits) (((versionBits) & TLS_VERSION_MASK) != 0x0u)
#define IS_SUPPORT_DTLS(versionBits) (((versionBits) & DTLS_VERSION_MASK) != 0x0u)
#define IS_SUPPORT_DTLS12(versionBits) (((versionBits) & DTLS12_VERSION_BIT) != 0x0u)
#define IS_SUPPORT_DTLS13(versionBits) (((versionBits) & DTLS13_VERSION_BIT) != 0x0u)
#define IS_TLS13_FAMILY_CTX(ctx) ((ctx) != NULL && IS_TLS13_FAMILY_VERSION((ctx)->negotiatedInfo.version))
#define IS_DTLS13_CTX(ctx) \
((ctx) != NULL && ((ctx)->negotiatedInfo.version == HITLS_VERSION_DTLS13 || \
((ctx)->negotiatedInfo.version == 0 && (ctx)->config.tlsConfig.maxVersion == HITLS_VERSION_DTLS13)))
#define MAC_KEY_LEN 32u
#define UNPROCESSED_APP_MSG_COUNT_MAX 50
#define RANDOM_SIZE 32u
typedef struct TlsCtx TLS_Ctx;
typedef struct HsCtx HS_Ctx;
typedef struct HsReassQueue HS_ReassQueue;
typedef struct CcsCtx CCS_Ctx;
typedef struct AlertCtx ALERT_Ctx;
typedef struct RecCtx REC_Ctx;
typedef enum {
CCS_CMD_RECV_READY,
CCS_CMD_RECV_EXIT_READY,
CCS_CMD_RECV_ACTIVE_CIPHER_SPEC,
} CCS_Cmd;
typedef bool (*IsRecvCcsCallback)(const TLS_Ctx *ctx);
typedef int32_t (*SendCcsCallback)(TLS_Ctx *ctx);
typedef int32_t (*CtrlCcsCallback)(TLS_Ctx *ctx, CCS_Cmd cmd);
typedef enum {
ALERT_LEVEL_WARNING = 1,
ALERT_LEVEL_FATAL = 2,
ALERT_LEVEL_UNKNOWN = 255,
} ALERT_Level;
typedef enum {
ALERT_CLOSE_NOTIFY = 0,
ALERT_UNEXPECTED_MESSAGE = 10,
ALERT_BAD_RECORD_MAC = 20,
ALERT_DECRYPTION_FAILED = 21,
ALERT_RECORD_OVERFLOW = 22,
ALERT_DECOMPRESSION_FAILURE = 30,
ALERT_HANDSHAKE_FAILURE = 40,
ALERT_NO_CERTIFICATE_RESERVED = 41,
ALERT_BAD_CERTIFICATE = 42,
ALERT_UNSUPPORTED_CERTIFICATE = 43,
ALERT_CERTIFICATE_REVOKED = 44,
ALERT_CERTIFICATE_EXPIRED = 45,
ALERT_CERTIFICATE_UNKNOWN = 46,
ALERT_ILLEGAL_PARAMETER = 47,
ALERT_UNKNOWN_CA = 48,
ALERT_ACCESS_DENIED = 49,
ALERT_DECODE_ERROR = 50,
ALERT_DECRYPT_ERROR = 51,
ALERT_EXPORT_RESTRICTION_RESERVED = 60,
ALERT_PROTOCOL_VERSION = 70,
ALERT_INSUFFICIENT_SECURITY = 71,
ALERT_INTERNAL_ERROR = 80,
ALERT_INAPPROPRIATE_FALLBACK = 86,
ALERT_USER_CANCELED = 90,
ALERT_NO_RENEGOTIATION = 100,
ALERT_MISSING_EXTENSION = 109,
ALERT_UNSUPPORTED_EXTENSION = 110,
ALERT_CERTIFICATE_UNOBTAINABLE = 111,
ALERT_UNRECOGNIZED_NAME = 112,
ALERT_BAD_CERTIFICATE_STATUS_RESPONSE = 113,
ALERT_BAD_CERTIFICATE_HASH_VALUE = 114,
ALERT_UNKNOWN_PSK_IDENTITY = 115,
ALERT_CERTIFICATE_REQUIRED = 116,
ALERT_NO_APPLICATION_PROTOCOL = 120,
ALERT_UNKNOWN = 255
} ALERT_Description;
typedef enum {
CM_STATE_IDLE,
CM_STATE_HANDSHAKING,
CM_STATE_TRANSPORTING,
CM_STATE_RENEGOTIATION,
CM_STATE_ALERTING,
CM_STATE_ALERTED,
#ifdef HITLS_TLS_PROTO_CLOSE_STATE
CM_STATE_CLOSED,
#endif
CM_STATE_END
} CM_State;
typedef enum {
PHA_NONE,
PHA_EXTENSION,
PHA_PENDING,
PHA_REQUESTED
} PHA_State;
typedef enum {
TLS_IDLE,
TLS_CONNECTED,
TRY_SEND_HELLO_REQUEST,
TRY_SEND_CLIENT_HELLO,
TRY_SEND_HELLO_VERIFY_REQUEST,
TRY_SEND_HELLO_RETRY_REQUEST,
TRY_SEND_SERVER_HELLO,
TRY_SEND_ENCRYPTED_EXTENSIONS,
TRY_SEND_CERTIFICATE,
TRY_SEND_SERVER_KEY_EXCHANGE,
TRY_SEND_CERTIFICATE_REQUEST,
TRY_SEND_SERVER_HELLO_DONE,
TRY_SEND_CLIENT_KEY_EXCHANGE,
TRY_SEND_CERTIFICATE_VERIFY,
TRY_SEND_NEW_SESSION_TICKET,
TRY_SEND_CHANGE_CIPHER_SPEC,
TRY_SEND_END_OF_EARLY_DATA,
TRY_SEND_FINISH,
TRY_SEND_KEY_UPDATE,
TRY_SEND_ACK,
TRY_RECV_CLIENT_HELLO,
TRY_RECV_HELLO_VERIFY_REQUEST,
TRY_RECV_SERVER_HELLO,
TRY_RECV_ENCRYPTED_EXTENSIONS,
TRY_RECV_CERTIFICATE,
TRY_RECV_SERVER_KEY_EXCHANGE,
TRY_RECV_CERTIFICATE_REQUEST,
TRY_RECV_SERVER_HELLO_DONE,
TRY_RECV_CLIENT_KEY_EXCHANGE,
TRY_RECV_CERTIFICATE_VERIFY,
TRY_RECV_NEW_SESSION_TICKET,
TRY_RECV_END_OF_EARLY_DATA,
TRY_RECV_FINISH,
TRY_RECV_KEY_UPDATE,
TRY_RECV_HELLO_REQUEST,
#ifdef HITLS_TLS_FEATURE_DTLS_CID
TRY_SEND_NEW_CONNECTION_ID,
TRY_SEND_REQUEST_CONNECTION_ID,
TRY_RECV_NEW_CONNECTION_ID,
TRY_RECV_REQUEST_CONNECTION_ID,
#endif
#ifdef HITLS_TLS_PROTO_DTLS13
TRY_RECV_MSG,
#endif
HS_STATE_BUTT = 255
} HITLS_HandshakeState;
typedef enum {
TLS_PROCESS_STATE_A,
TLS_PROCESS_STATE_B
} HitlsProcessState;
typedef void (*SendAlertCallback)(const TLS_Ctx *ctx, ALERT_Level level, ALERT_Description description);
typedef void (*ClearAlertCallBack)(TLS_Ctx *ctx, uint32_t recordType);
typedef bool (*GetAlertFlagCallback)(const TLS_Ctx *ctx);
typedef int32_t (*UnexpectMsgHandleCallback)(TLS_Ctx *ctx, uint32_t msgType, const uint8_t *data, uint32_t dataLen,
bool isPlain);
typedef struct TLSCtxConfig {
void *userData;
uint16_t linkMtu;
including IP header and udp/tcp header */
uint16_t pmtu;
uint8_t reserved[1];
TLS_Config tlsConfig;
} TLS_CtxConfig;
typedef struct {
uint32_t algRemainTime;
uint8_t preMacKey[MAC_KEY_LEN];
uint8_t macKey[MAC_KEY_LEN];
} CookieInfo;
typedef enum {
DTLS_CID_RECV_SLOT_FREE = 0,
DTLS_CID_RECV_SLOT_ACTIVE = 1,
DTLS_CID_RECV_SLOT_DEPRECATING = 2,
} DTLS_CidRecvSlotState;
* encodes eviction preference for spare placement (smaller = preferred). */
typedef enum {
DTLS_CID_SEND_SLOT_FREE = 0,
DTLS_CID_SEND_SLOT_USED = 1,
DTLS_CID_SEND_SLOT_UNUSED = 2,
DTLS_CID_SEND_SLOT_INUSE = 3,
} DTLS_CidSendSlotState;
typedef enum {
DTLS_CID_MSG_STATE_IDLE = 0,
DTLS_CID_MSG_STATE_PENDING = 1,
DTLS_CID_MSG_STATE_SENT = 2,
} DTLS_CidMsgState;
typedef struct {
uint8_t cidVal[HITLS_DTLS_CID_LOCAL_MAX_LEN];
uint8_t cidLen;
} DTLS_CidRecvEntry;
typedef HITLS_DtlsCidEntry DTLS_CidSendEntry;
typedef struct {
uint8_t state;
DTLS_CidRecvEntry entry;
} DTLS_CidRecvSlot;
typedef struct {
uint8_t state;
DTLS_CidSendEntry entry;
} DTLS_CidSendSlot;
* Heap-allocated 16-slot CID table. Held as a pointer in TLS_NegotiatedInfo and
* materialized lazily on the first post-handshake CID operation. Connections
* that negotiate CID but never update keep only the inline single-CID fields,
* avoiding the ~4.7 KB slot table for the common case.
*/
typedef struct {
DTLS_CidRecvSlot recvSlots[HITLS_DTLS_CID_LIST_MAX];
DTLS_CidSendSlot sendSlots[HITLS_DTLS_CID_LIST_MAX];
uint8_t currentSendIdx;
uint16_t cidWrittenMask;
uint8_t cidUsage;
} DTLS_CidCtx;
typedef struct {
uint16_t version;
uint16_t clientVersion;
uint32_t cookieSize;
uint8_t *cookie;
CookieInfo cookieInfo;
CipherSuiteInfo cipherSuiteInfo;
HITLS_SignHashAlgo signScheme;
uint8_t *alpnSelected;
uint32_t alpnSelectedSize;
uint8_t clientVerifyData[MAX_DIGEST_SIZE];
uint8_t serverVerifyData[MAX_DIGEST_SIZE];
uint8_t clientRandom[RANDOM_SIZE];
uint8_t serverRandom[RANDOM_SIZE];
uint32_t clientVerifyDataSize;
uint32_t serverVerifyDataSize;
uint32_t renegotiationNum;
uint32_t certReqSendTime;
uint32_t tls13BasicKeyExMode;
TLS13_CERT_AUTH_WITH_DHE */
uint16_t negotiatedGroup;
uint16_t recordSizeLimit;
uint16_t renegoRecordSizeLimit;
uint16_t peerRecordSizeLimit;
bool isResume;
bool isRenegotiation;
bool isSecureRenegotiation;
bool isExtendedMasterSecret;
bool isEncryptThenMac;
bool isTicket;
bool isSniStateOK;
#ifdef HITLS_TLS_FEATURE_SNI
uint8_t *serverName;
uint32_t serverNameSize;
#endif
#ifdef HITLS_TLS_FEATURE_DTLS_CID
bool isCidNegotiated;
DTLS_CidRecvEntry localCidEntry;
DTLS_CidSendEntry peerCidEntry;
with the INUSE send slot. cidLen > 0 means the record layer packs it */
DTLS_CidCtx *cidCtx;
#endif
} TLS_NegotiatedInfo;
typedef struct {
uint16_t *groups;
uint32_t groupsSize;
uint16_t *cipherSuites;
uint16_t cipherSuitesSize;
HITLS_SignHashAlgo peerSignHashAlg;
uint16_t *signatureAlgorithms;
uint16_t signatureAlgorithmsSize;
HITLS_ERROR verifyResult;
HITLS_TrustedCAList *caList;
} PeerInfo;
struct TlsCtx {
bool isClient;
bool userShutDown;
bool userRenego;
uint8_t rwstate;
CM_State preState;
CM_State state;
uint32_t shutdownState;
void *rUio;
void *uio;
void *bUio;
HS_Ctx *hsCtx;
CCS_Ctx *ccsCtx;
ALERT_Ctx *alertCtx;
REC_Ctx *recCtx;
struct {
IsRecvCcsCallback isRecvCCS;
SendCcsCallback sendCCS;
CtrlCcsCallback ctrlCCS;
SendAlertCallback sendAlert;
ClearAlertCallBack clearAlert;
GetAlertFlagCallback getAlertFlag;
UnexpectMsgHandleCallback unexpectedMsgProcessCb;
} method;
PeerInfo peerInfo;
TLS_CtxConfig config;
TLS_Config *globalConfig;
TLS_NegotiatedInfo negotiatedInfo;
HITLS_Session *session;
uint8_t clientAppTrafficSecret[MAX_DIGEST_SIZE];
uint8_t serverAppTrafficSecret[MAX_DIGEST_SIZE];
uint8_t resumptionMasterSecret[MAX_DIGEST_SIZE];
uint8_t exporterMasterSecret[MAX_DIGEST_SIZE];
uint32_t bytesLeftToRead;
uint32_t keyUpdateType;
bool isKeyUpdateRequest;
bool isWaitKeyUpdate;
#ifdef HITLS_TLS_PROTO_DTLS13
uint16_t dtls13NextSendSeq;
uint16_t dtls13ExpectRecvSeq;
#endif
#ifdef HITLS_TLS_FEATURE_DTLS_CID
uint8_t newCidState;
uint8_t reqCidState;
uint8_t reqCidNum;
HITLS_RecvRequestConnectionIdCb onRecvRequestCidCb;
void *onRecvRequestCidUserData;
#endif
#if defined(HITLS_TLS_PROTO_DATAGRAM)
HS_ReassQueue *reassMsg;
#endif
bool haveClientPointFormats;
uint8_t peekFlag;
bool hasParsedHsMsgHeader;
int32_t errorCode;
HITLS_HASH_Ctx *phaHash;
HITLS_HASH_Ctx *phaCurHash;
PHA_State phaState;
uint8_t *certificateReqCtx;
uint32_t certificateReqCtxSize;
bool isDtlsListen;
bool plainAlertForbid;
bool allowAppOut;
bool noQueryMtu;
bool needQueryMtu;
bool mtuModified;
* time is exceeded, the receiving times out. */
BSL_TIME deadline;
HITLS_REC_ReadCb recReadCb;
void *recReadCbArg;
#if defined(HITLS_TLS_PROTO_DATAGRAM) && defined(HITLS_BSL_UIO_UDP)
uint32_t timeoutValue;
uint32_t timeoutNum;
BSL_TIME dtls2MslDeadline;
bool isDtls2MslTimerActive;
#endif
};
typedef struct {
uint8_t **buf;
uint32_t *bufLen;
uint32_t *bufOffset;
} PackPacket;
#define LIBCTX_FROM_CTX(ctx) (((ctx) == NULL) ? NULL : (ctx)->config.tlsConfig.libCtx)
#define ATTRIBUTE_FROM_CTX(ctx) (((ctx) == NULL) ? NULL : (ctx)->config.tlsConfig.attrName)
#define CUSTOM_EXT_FROM_CTX(ctx) (((ctx) == NULL) ? NULL : (ctx)->config.tlsConfig.customExts)
#define GET_VERSION_FROM_CTX(ctx) \
((ctx)->negotiatedInfo.version > 0 ? (ctx)->negotiatedInfo.version : (ctx)->config.tlsConfig.maxVersion)
#ifdef __cplusplus
}
#endif
#endif