Kawe Mazidjatari b3a68ed095 Add EABase, EAThread and DirtySDK to R5sdk
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
2024-04-05 18:29:03 +02:00

278 lines
12 KiB
C

/*H*************************************************************************************************/
/*!
\File protossl.h
\Description
This module is a from-scratch TLS implementation. It does not use any
third-party code of any kind and was developed entirely by EA.
\Notes
References:
TLS1.0 RFC: https://tools.ietf.org/html/rfc2246
TLS1.1 RFC: https://tools.ietf.org/html/rfc4346
TLS1.2 RFC: https://tools.ietf.org/html/rfc5246
TLS1.3 RFC: https://tools.ietf.org/html/rfc8446
ASN.1 encoding rules: https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
\Copyright
Copyright (c) Electronic Arts 2002-2018
\Version 03/08/2002 (gschaefer) Initial SSL 2.0 implementation
\Version 03/03/2004 (sbevan) Added certificate validation
\Version 11/05/2005 (gschaefer) Rewritten to follow SSL 3.0 specification
\Version 10/12/2012 (jbrookes) Added support for TLS1.0 & TLS1.1
\Version 10/20/2013 (jbrookes) Added server handshake, client cert support
\Version 11/06/2013 (jbrookes) Added support for TLS1.2
\Version 03/31/2017 (eesponda) Added support for EC ciphers
\Version 03/28/2018 (jbrookes) Added support for TLS1.3
\Version 08/15/2018 (jbrookes) Removed SSLv3 & RC4 ciphers
*/
/*************************************************************************************************H*/
#ifndef _protossl_h
#define _protossl_h
/*!
\Moduledef ProtoSSL ProtoSSL
\Modulemember Proto
*/
//@{
/*** Include files *********************************************************************/
#include "DirtySDK/platform.h"
#include "DirtySDK/crypt/cryptdef.h"
#include "DirtySDK/crypt/cryptrsa.h"
/*** Defines ***************************************************************************/
// supported TLS versions
#define PROTOSSL_VERSION_TLS1_0 (0x0301)
#define PROTOSSL_VERSION_TLS1_1 (0x0302)
#define PROTOSSL_VERSION_TLS1_2 (0x0303)
#define PROTOSSL_VERSION_TLS1_3 (0x0304)
// protossl failure codes (retrieve with ProtoSSLStat('fail')
#define PROTOSSL_ERROR_NONE ( 0) //!< no error
#define PROTOSSL_ERROR_DNS (-1) //!< DNS failure
#define PROTOSSL_ERROR_CONN (-10) //!< TCP connection failure
#define PROTOSSL_ERROR_CONN_SSL2 (-11) //!< connection attempt was using unsupported SSLv2 record format
#define PROTOSSL_ERROR_CONN_NOTSSL (-12) //!< connection attempt was not recognized as SSL
#define PROTOSSL_ERROR_CONN_MINVERS (-13) //!< request failed minimum protocol version restriction
#define PROTOSSL_ERROR_CONN_MAXVERS (-14) //!< request failed maximum protocol version restriction
#define PROTOSSL_ERROR_CONN_NOCIPHER (-15) //!< no supported cipher
#define PROTOSSL_ERROR_CONN_NOCURVE (-16) //!< no supported curve
#define PROTOSSL_ERROR_CERT_INVALID (-20) //!< certificate invalid
#define PROTOSSL_ERROR_CERT_HOST (-21) //!< certificate not issued to this host
#define PROTOSSL_ERROR_CERT_NOTRUST (-22) //!< certificate is not trusted (recognized)
#define PROTOSSL_ERROR_CERT_MISSING (-23) //!< certificate not provided in certificate message
#define PROTOSSL_ERROR_CERT_BADDATE (-24) //!< certificate date range validity check failed
#define PROTOSSL_ERROR_CERT_REQUEST (-25) //!< CA fetch request failed
#define PROTOSSL_ERROR_SETUP (-30) //!< failure in secure setup
#define PROTOSSL_ERROR_SECURE (-31) //!< failure in secure connection after setup
#define PROTOSSL_ERROR_UNKNOWN (-32) //!< unknown failure
// SSLv3 cipher suites (available for TLS1.0+ although SSLv3 is no longer supported)
#define PROTOSSL_CIPHER_RSA_WITH_AES_128_CBC_SHA (1<<0)
#define PROTOSSL_CIPHER_RSA_WITH_AES_256_CBC_SHA (1<<1)
// TLS1.0 cipher suites
#define PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA (1<<2)
#define PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA (1<<3)
#define PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (1<<4)
#define PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (1<<5)
// TLS1.2 cipher suites
#define PROTOSSL_CIPHER_RSA_WITH_AES_128_CBC_SHA256 (1<<6)
#define PROTOSSL_CIPHER_RSA_WITH_AES_256_CBC_SHA256 (1<<7)
#define PROTOSSL_CIPHER_RSA_WITH_AES_128_GCM_SHA256 (1<<8)
#define PROTOSSL_CIPHER_RSA_WITH_AES_256_GCM_SHA384 (1<<9)
#define PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (1<<10)
#define PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (1<<11)
#define PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (1<<12)
#define PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (1<<13)
#define PROTOSSL_CIPHER_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (1<<14)
#define PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (1<<15)
#define PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (1<<16)
#define PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (1<<17)
#define PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (1<<18)
#define PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (1<<19)
// TLS1.3 cipher suites
#define PROTOSSL_CIPHER_AES_128_GCM_SHA256 (1<<20)
#define PROTOSSL_CIPHER_AES_256_GCM_SHA384 (1<<21)
#define PROTOSSL_CIPHER_CHACHA20_POLY1305_SHA256 (1<<22)
//! all rsa cipher suites (minus disabled rc4-md5)
#define PROTOSSL_CIPHER_RSA (\
PROTOSSL_CIPHER_RSA_WITH_AES_128_CBC_SHA|PROTOSSL_CIPHER_RSA_WITH_AES_256_CBC_SHA|\
PROTOSSL_CIPHER_RSA_WITH_AES_128_CBC_SHA256|PROTOSSL_CIPHER_RSA_WITH_AES_128_GCM_SHA256|\
PROTOSSL_CIPHER_RSA_WITH_AES_256_CBC_SHA256|PROTOSSL_CIPHER_RSA_WITH_AES_256_GCM_SHA384)
//! all ecc cipher suites
#define PROTOSSL_CIPHER_ECC (\
PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA|PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256|\
PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA|PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA384|\
PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_128_GCM_SHA256|PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA|\
PROTOSSL_CIPHER_ECDHE_RSA_WITH_AES_256_GCM_SHA384|PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_256_CBC_SHA|\
PROTOSSL_CIPHER_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256|\
PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256|PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256|\
PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384|PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384|\
PROTOSSL_CIPHER_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256)
//! all tls1.3 cipher suites
#define PROTOSSL_CIPHER_ALL_13 (PROTOSSL_CIPHER_AES_128_GCM_SHA256|PROTOSSL_CIPHER_AES_256_GCM_SHA384|PROTOSSL_CIPHER_CHACHA20_POLY1305_SHA256)
//! default cipher suites
#define PROTOSSL_CIPHER_ALL (PROTOSSL_CIPHER_RSA|PROTOSSL_CIPHER_ECC|PROTOSSL_CIPHER_ALL_13)
// client cert flags (ProtoSSLControl() 'ccrt' selector)
#define PROTOSSL_CLIENTCERT_NONE (0)
#define PROTOSSL_CLIENTCERT_OPTIONAL (1)
#define PROTOSSL_CLIENTCERT_REQUIRED (2)
// clienthello extensions
#define PROTOSSL_HELLOEXTN_NONE (0)
#define PROTOSSL_HELLOEXTN_SERVERNAME (1)
#define PROTOSSL_HELLOEXTN_SIGALGS (2)
#define PROTOSSL_HELLOEXTN_ALPN (4)
#define PROTOSSL_HELLOEXTN_ELLIPTIC_CURVES (8)
// all extensions
#define PROTOSSL_HELLOEXTN_ALL (\
PROTOSSL_HELLOEXTN_SERVERNAME|PROTOSSL_HELLOEXTN_SIGALGS|PROTOSSL_HELLOEXTN_ALPN)
// default extensions
#define PROTOSSL_HELLOEXTN_DEFAULT (PROTOSSL_HELLOEXTN_ALL)
//! elliptic curves
#define PROTOSSL_CURVE_SECP256R1 (1 << 0)
#define PROTOSSL_CURVE_SECP384R1 (1 << 1)
#define PROTOSSL_CURVE_X25519 (1 << 2)
#define PROTOSSL_CURVE_X448 (1 << 3)
//! all curves
#define PROTOSSL_CURVE_ALL (\
PROTOSSL_CURVE_SECP256R1|PROTOSSL_CURVE_SECP384R1|PROTOSSL_CURVE_X25519|PROTOSSL_CURVE_X448)
//! default curves
#define PROTOSSL_CURVE_DEFAULT (PROTOSSL_CURVE_ALL)
/*** Macros ****************************************************************************/
/*** Type Definitions ******************************************************************/
//! identity fields for X509 issuer/subject
typedef struct ProtoSSLCertIdentT
{
char strCountry[32];
char strState[32];
char strCity[32];
char strOrg[32];
char strUnit[256];
char strCommon[64];
} ProtoSSLCertIdentT;
//! alert info, returned by ProtoSSLStat() 'alrt' selector after an SSL alert has been received
typedef struct ProtoSSLAlertDescT
{
int32_t iAlertType;
const char *pAlertDesc;
} ProtoSSLAlertDescT;
//! cert info, returned by ProtoSSLStat() 'cert' selector after certificate failure
typedef struct ProtoSSLCertInfoT
{
ProtoSSLCertIdentT Ident;
int32_t iKeyModSize;
} ProtoSSLCertInfoT;
//! state for pkcs1 operations
typedef struct ProtoSSLPkcs1T
{
CryptRSAT RSAContext; //!< context used for rsa operations
} ProtoSSLPkcs1T;
// opaque module state ref
typedef struct ProtoSSLRefT ProtoSSLRefT;
// forward declaration of sockaddr
struct sockaddr;
/*** Variables *************************************************************************/
/*** Functions *************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
// protossl startup
DIRTYCODE_API int32_t ProtoSSLStartup(void);
// protossl shutdown
DIRTYCODE_API void ProtoSSLShutdown(void);
// allocate an SSL connection and prepare for use
DIRTYCODE_API ProtoSSLRefT *ProtoSSLCreate(void);
// reset connection back to base state.
DIRTYCODE_API void ProtoSSLReset(ProtoSSLRefT *pState);
// destroy the module and release its state
DIRTYCODE_API void ProtoSSLDestroy(ProtoSSLRefT *pState);
// give time to module to do its thing (should be called periodically to allow module to perform work)
DIRTYCODE_API void ProtoSSLUpdate(ProtoSSLRefT *pState);
// Accept an incoming connection.
DIRTYCODE_API ProtoSSLRefT* ProtoSSLAccept(ProtoSSLRefT *pState, int32_t iSecure, struct sockaddr *pAddr, int32_t *pAddrlen);
// Create a socket bound to the given address.
DIRTYCODE_API int32_t ProtoSSLBind(ProtoSSLRefT *pState, const struct sockaddr *pAddr, int32_t pAddrlen);
// make a secure connection to a server.
DIRTYCODE_API int32_t ProtoSSLConnect(ProtoSSLRefT *pState, int32_t iSecure, const char *pAddr, uint32_t uAddr, int32_t iPort);
// disconnect from the server.
DIRTYCODE_API int32_t ProtoSSLDisconnect(ProtoSSLRefT *pState);
// Start listening for an incoming connection.
DIRTYCODE_API int32_t ProtoSSLListen(ProtoSSLRefT *pState, int32_t iBacklog);
// send secure data to the server.
DIRTYCODE_API int32_t ProtoSSLSend(ProtoSSLRefT *pState, const char *pBuffer, int32_t iLength);
// receive secure data from the server.
DIRTYCODE_API int32_t ProtoSSLRecv(ProtoSSLRefT *pState, char *pBuffer, int32_t iLength);
// return the current module status (according to selector)
DIRTYCODE_API int32_t ProtoSSLStat(ProtoSSLRefT *pState, int32_t iSelect, void *pBuffer, int32_t iLength);
// control module behavior
DIRTYCODE_API int32_t ProtoSSLControl(ProtoSSLRefT *pState, int32_t iSelect, int32_t iValue, int32_t iValue2, void *pValue);
// add an X.509 CA certificate that will be recognized in future transactions
DIRTYCODE_API int32_t ProtoSSLSetCACert(const uint8_t *pCACert, int32_t iCertSize);
// same as ProtoSSLSetCACert(), but certs are not validated at load time
DIRTYCODE_API int32_t ProtoSSLSetCACert2(const uint8_t *pCACert, int32_t iCertSize);
// validate all CAs that have not already been validated
DIRTYCODE_API int32_t ProtoSSLValidateAllCA(void);
// clear all CA certs
DIRTYCODE_API void ProtoSSLClrCACerts(void);
// generate a pkcs1.5 rsa signature - init
DIRTYCODE_API int32_t ProtoSSLPkcs1GenerateInit(ProtoSSLPkcs1T *pPkcs1, const uint8_t *pHashData, int32_t iHashLen, int32_t iHashType, int32_t iModSize, const CryptBinaryObjT *pPrimeP, const CryptBinaryObjT *pPrimeQ, const CryptBinaryObjT *pExponentP, const CryptBinaryObjT *pExponentQ, const CryptBinaryObjT *pCoefficient);
// generate a pkcs1.5 rsa signature
DIRTYCODE_API int32_t ProtoSSLPkcs1GenerateUpdate(ProtoSSLPkcs1T *pPkcs1, int32_t iNumIterations, uint8_t *pSigData, int32_t iSigSize);
// verify the pkcs1.5 rsa signature
DIRTYCODE_API int32_t ProtoSSLPkcs1Verify(const uint8_t *pSignature, int32_t iSigLen, const uint8_t *pHashData, int32_t iHashLen, int32_t iHashType, const uint8_t *pMod, int32_t iModSize, const uint8_t *pExp, int32_t iExpSize);
#ifdef __cplusplus
}
#endif
//@}
#endif // _protossl_h