LCOV - code coverage report
Current view: top level - waltz/tls - fd_tls.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 25 66 37.9 %
Date: 2024-11-13 11:58:15 Functions: 3 114 2.6 %

          Line data    Source code
       1             : #ifndef HEADER_src_ballet_tls_fd_tls_h
       2             : #define HEADER_src_ballet_tls_fd_tls_h
       3             : 
       4             : #include "fd_tls_estate.h"
       5             : 
       6             : /* fd_tls implements a subset of the TLS v1.3 (RFC 8446) handshake
       7             :    protocol.
       8             : 
       9             :    fd_tls is not a general purpose TLS library.  It only provides the
      10             :    TLS components required to secure peer-to-peer QUIC connections as
      11             :    they appear in Solana network protocol.  Specifics are listed below.
      12             : 
      13             :    Older TLS versions, such as TLS v1.2, are not supported.
      14             : 
      15             :    ### Peer Authentication
      16             : 
      17             :    Peers are authenticated via Ed25519 using the TLS v1.3 raw public key
      18             :    (RPK) extension.  Minimal support for X.509 is included.  Client
      19             :    cert authentication is optional for fd_tls_client_t and mandatory
      20             :    for fd_tls_server_t.
      21             : 
      22             :    ### Key Exchange
      23             : 
      24             :    Peers exchange symmetric keys using X25519, an Elliptic Curve Diffie-
      25             :    Hellman key exchange scheme using Curve25519.  Pre-shared keys and
      26             :    other key exchange schemes are currently not supported.
      27             : 
      28             :    ### Data Confidentiality and Integratity
      29             : 
      30             :    fd_tls provides an API for the TLS_AES_128_GCM_SHA256 cipher suite.
      31             :    Other cipher suites are currently not supported.
      32             : 
      33             :    ### References
      34             : 
      35             :    This library implements parts of protocols specified in the following
      36             :    IETF RFCs:
      37             : 
      38             :      RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
      39             :      https://datatracker.ietf.org/doc/html/rfc8446
      40             : 
      41             :      RFC 6066: Transport Layer Security (TLS) Extensions:
      42             :                Extension Definitions
      43             :      https://datatracker.ietf.org/doc/html/rfc6066
      44             : 
      45             :      RFC 9001: Using TLS to Secure QUIC
      46             :      https://datatracker.ietf.org/doc/html/rfc9001
      47             : 
      48             :      RFC 7919: Negotiated Finite Field Diffie-Hellman Ephemeral
      49             :                Parameters for Transport Layer Security (TLS)
      50             :      RFC 4492: Elliptic Curve Cryptography (ECC) Cipher Suites for
      51             :                Transport Layer Security (TLS)
      52             :      https://datatracker.ietf.org/doc/html/rfc7919
      53             :      https://datatracker.ietf.org/doc/html/rfc4492
      54             : 
      55             :      RFC 7250: Using Raw Public Keys in Transport Layer Security (TLS)
      56             :      https://datatracker.ietf.org/doc/html/rfc7250
      57             : 
      58             :      RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA)
      59             :      https://datatracker.ietf.org/doc/html/rfc8032
      60             :      Note: fd_ed25519 uses stricter signature malleability checks!
      61             : 
      62             :      RFC 7748: Elliptic Curves for Security
      63             :      https://datatracker.ietf.org/doc/html/rfc7748
      64             : 
      65             :      RFC 5288: AES Galois Counter Mode (GCM) Cipher Suites for TLS
      66             :      https://datatracker.ietf.org/doc/html/rfc5288 */
      67             : 
      68             : /* Callbacks **********************************************************/
      69             : 
      70             : /* fd_tls_secrets_fn_t is called by fd_tls when new encryption secrets
      71             :    have been generated.  {recv/send}_secret are used for incoming/out-
      72             :    going data respectively and point to a 32-byte buffer valid for the
      73             :    lifetime of the function call.  This function is invoked for each
      74             :    new encryption_level, which is FD_TLS_LEVEL_{HANDSHAKE,APPLICATION}.
      75             :    It is safe to discard handshake-level decryption secrets after the
      76             :    handshake has been completed. */
      77             : 
      78             : typedef void
      79             : (* fd_tls_secrets_fn_t)( void const * handshake,
      80             :                          void const * recv_secret,
      81             :                          void const * send_secret,
      82             :                          uint         encryption_level );
      83             : 
      84             : /* fd_tls_sendmsg_fn_t is called by fd_tls to request transmission of a
      85             :    TLS message to the peer.  msg points to a buffer containing msg_sz
      86             :    message bytes.  The smallest message size is 4 bytes (the size of a
      87             :    message header).  encryption_level indicates which key to use.
      88             :    flush==0 when another message for the same conn will follow
      89             :    immediately on return.  flush==1 hints that no more sendmsg callbacks
      90             :    are issued until the next call to fd_tls_server_handshake.  It is
      91             :    safe to "flush" (i.e. transmit data out through the NIC) even when
      92             :    flush==0.  Returns 1 on success and 0 on failure. */
      93             : 
      94             : typedef int
      95             : (* fd_tls_sendmsg_fn_t)( void const * handshake,
      96             :                          void const * msg,
      97             :                          ulong        msg_sz,
      98             :                          uint         encryption_level,
      99             :                          int          flush );
     100             : 
     101             : /* fd_tls_quic_tp_self_fn_t is called by fd_tls to request QUIC
     102             :    transport params to be sent to the peer.  quic_tp points to the
     103             :    buffer that may hold serialized QUIC transport parameters (RFC
     104             :    Section 18). quic_tp_bufsz is the size of the buffer at quic_tp.
     105             :    Return value is actual serialized (<=quic_tp_bufsz) on success.
     106             :    On failure, returns (>quic_tp_bufsz) to indicate insufficient bufsz.
     107             :    (Zero implies success, however!) */
     108             : 
     109             : typedef ulong __attribute__((warn_unused_result))
     110             : (* fd_tls_quic_tp_self_fn_t)( void *  handshake,
     111             :                               uchar * quic_tp,
     112             :                               ulong   quic_tp_bufsz );
     113             : 
     114             : /* fd_tls_quic_tp_peer_fn_t is called by fd_tls to inform the user of
     115             :    the peer's QUIC transport params.  quic_tp points to the serialized
     116             :    QUIC transport parameters (RFC 9000 Section 18). quic_tp_sz is the
     117             :    serialized size.  Lifetime of quic_tp buffer ends at return. fd_tls
     118             :    does not do any validation on the peer's QUIC TP -- Please ensure
     119             :    your deserializer is robust given arbitrary data. */
     120             : 
     121             : typedef void
     122             : (* fd_tls_quic_tp_peer_fn_t)( void  *       handshake,
     123             :                               uchar const * quic_tp,
     124             :                               ulong         quic_tp_sz );
     125             : 
     126             : /* fd_tls_rand_vt_t is an abstraction for retrieving secure pseudorandom
     127             :    values.  When fd_tls needs random values, it calls fd_tls_rand_fn_t.
     128             : 
     129             :    ctx is an arbitrary pointer that is provided as a callback argument.
     130             :    buf points to a buffer of bufsz bytes that is to be filled with
     131             :    cryptographically secure randomness.  bufsz is usually 32 bytes.
     132             :    Assume buf is unaligned.  Returns buf on success and NULL on failure.
     133             : 
     134             :    Function must not block, but may synchronously pre-calculate a
     135             :    reasonable amount of data ahead of time.  NULL return value implies
     136             :    inability to keep up with demand for random values.  In this case,
     137             :    function should return NULL.  Function should minimize side effects
     138             :    (notably, should not log).
     139             : 
     140             :    TODO API considerations:
     141             :    - read() style error codes?
     142             :    - Buffering to reduce amount of virtual function calls? */
     143             : 
     144             : typedef void *
     145             : (* fd_tls_rand_fn_t)( void * ctx,
     146             :                       void * buf,
     147             :                       ulong  bufsz );
     148             : 
     149             : struct fd_tls_rand_vt {
     150             :   void *           ctx;
     151             :   fd_tls_rand_fn_t rand_fn;
     152             : };
     153             : 
     154             : typedef struct fd_tls_rand_vt fd_tls_rand_t;
     155             : 
     156             : static inline void *
     157             : fd_tls_rand( fd_tls_rand_t const * rand,
     158             :              void *                buf,
     159       12039 :              ulong                 bufsz ) {
     160       12039 :   return rand->rand_fn( rand->ctx, buf, bufsz );
     161       12039 : }
     162             : 
     163             : /* fd_tls_sign_fn_t is called by by fd_tls to request signing of a
     164             :    TLS 1.3 certificate verify payload.
     165             : 
     166             :    ctx is an arbitrary pointer that is provided as a callback argument.
     167             :    sig points to a 64 byte buffer where the implementor should store the
     168             :    ed25519 signature of the payload.  Payload will point to a 130 byte
     169             :    buffer containing the TLS 1.3 CertificateVerify payload.
     170             : 
     171             :    This function must not fail.  Lifetime of the payload buffer ends at
     172             :    return. */
     173             : 
     174             : typedef void
     175             : (* fd_tls_sign_fn_t)( void *        ctx,
     176             :                       uchar         sig[ static 64 ],
     177             :                       uchar const   payload[ static 130 ] );
     178             : 
     179             : struct fd_tls_sign_vt {
     180             :   void *           ctx;
     181             :   fd_tls_sign_fn_t sign_fn;
     182             : };
     183             : 
     184             : typedef struct fd_tls_sign_vt fd_tls_sign_t;
     185             : 
     186             : static inline void
     187             : fd_tls_sign( fd_tls_sign_t const * sign,
     188             :              uchar                 sig[ static 64 ],
     189        6018 :              uchar const           payload[ static 130 ] ) {
     190        6018 :   sign->sign_fn( sign->ctx, sig, payload );
     191        6018 : }
     192             : 
     193             : /* Public API *********************************************************/
     194             : 
     195             : /* Handshake state identifiers */
     196             : 
     197           0 : #define FD_TLS_HS_FAIL          ( 0) /* client, server */
     198       24066 : #define FD_TLS_HS_CONNECTED     ( 1) /* client, server */
     199       72576 : #define FD_TLS_HS_START         ( 2) /* client, server */
     200           0 : #define FD_TLS_HS_WAIT_CERT     ( 3) /* client, server */
     201       12036 : #define FD_TLS_HS_WAIT_CV       ( 4) /* client, server */
     202       24072 : #define FD_TLS_HS_WAIT_FINISHED ( 5) /* client, server */
     203       12042 : #define FD_TLS_HS_WAIT_SH       ( 6) /* client */
     204       12036 : #define FD_TLS_HS_WAIT_EE       ( 7) /* client */
     205       12036 : #define FD_TLS_HS_WAIT_CERT_CR  ( 8) /* client */
     206             : 
     207             : /* TLS encryption levels */
     208             : 
     209        6027 : #define FD_TLS_LEVEL_INITIAL     (0)
     210             : #define FD_TLS_LEVEL_EARLY       (1)
     211       24060 : #define FD_TLS_LEVEL_HANDSHAKE   (2)
     212       24060 : #define FD_TLS_LEVEL_APPLICATION (3)
     213             : 
     214             : /* FD_TLS_SERVER_CERT_SZ_MAX is the max permitted size of the DER-
     215             :    serialized X.509 server certificate. */
     216             : 
     217             : #define FD_TLS_SERVER_CERT_SZ_MAX (1011UL)
     218             : 
     219             : /* FD_TLS_SERVER_CERT_MSG_SZ_MAX is the max permitted size of the pre-
     220             :    buffered X.509 server certificate message. */
     221             : 
     222             : #define FD_TLS_SERVER_CERT_MSG_SZ_MAX (FD_TLS_SERVER_CERT_SZ_MAX+13UL)
     223             : 
     224             : /* FD_TLS_EXT_QUIC_PARAMS_SZ is the max permitted byte size of encoded
     225             :    QUIC transport parameters */
     226             : 
     227       12030 : # define FD_TLS_EXT_QUIC_PARAMS_SZ_MAX (510UL)
     228             : 
     229             : /* fd_tls_t contains the local TLS config.  It is typically shared
     230             :    across multiple TLS handshakes. */
     231             : 
     232             : struct fd_tls {
     233             :   fd_tls_rand_t       rand;
     234             :   fd_tls_secrets_fn_t secrets_fn;
     235             :   fd_tls_sendmsg_fn_t sendmsg_fn;
     236             : 
     237             :   /* QUIC specific callbacks -- Only called if quic flag is set.
     238             :      TODO: Will optional function pointers stall the pipeline? */
     239             :   fd_tls_quic_tp_self_fn_t quic_tp_self_fn;
     240             :   fd_tls_quic_tp_peer_fn_t quic_tp_peer_fn;
     241             : 
     242             :   /* key_{private,public}_key is an X25519 key pair.  During the TLS
     243             :      handshake, it is used to establish symmetric encryption keys.
     244             :      kex_private_key is an arbitrary 32 byte vector.  It is recommended
     245             :      to generate a new X25519 key on startup from cryptographically
     246             :      secure randomness. kex_public_key is the corresponding public key
     247             :      curve point derived via fd_x25519_public.
     248             : 
     249             :      Security notes:
     250             :      - May not be changed while conns are active. */
     251             :   uchar kex_private_key[ 32 ];
     252             :   uchar kex_public_key [ 32 ];
     253             : 
     254             :    /* Signing function holding the Ed25519 key pair that identifies the
     255             :       server.  During TLS handshakes, used to sign a transcript of the
     256             :       handshake to prove to the peer that we are in possession of this
     257             :       key.  This function should sign with the Solana node identity key.
     258             : 
     259             :      Security notes:
     260             :      - May not be changed while conns are active.
     261             :      - Using a public key that is not derived from the private key may
     262             :        reveal the private key (!!!) */
     263             :   fd_tls_sign_t sign;
     264             : 
     265             :   /* cert_public_key is the Ed25519 public key that identifies the
     266             :      server.  Must be the public key corresponding to the Solana node
     267             :      identity key used by the signer function above. */
     268             :   uchar cert_public_key [ 32 ];
     269             : 
     270             :   /* X.509 certificate to present to peer (optional).
     271             :      SubjectPublicKeyInfo must be Ed25519 and match cert_public_key. */
     272             :   uchar cert_x509[ FD_TLS_SERVER_CERT_MSG_SZ_MAX ];
     273             :   ulong cert_x509_sz;
     274             : 
     275             :   /* ALPN protocol identifier.  Written by fd_tls_server_set_alpn.
     276             :      Format: <1 byte length prefix> <ASCII chars>.
     277             :      Is not NUL delimited. */
     278             :   uchar alpn[ 32 ];
     279             :   ulong alpn_sz;
     280             : 
     281             :   /* Flags */
     282             :   ulong quic            :  1;
     283             :   ulong _flags_reserved : 63;
     284             : };
     285             : 
     286             : typedef struct fd_tls fd_tls_t;
     287             : 
     288             : /* Extended Alert Reasons *********************************************/
     289             : 
     290             : /* fd_tls-specific error codes to identify reasons for alerts.  These
     291             :    can help with debugging when the error cause is not evident by the
     292             :    alert itself. */
     293             : 
     294           0 : #define FD_TLS_REASON_NULL            ( 0)
     295             : 
     296           0 : #define FD_TLS_REASON_ILLEGAL_STATE   ( 1)  /* illegal hs state */
     297           0 : #define FD_TLS_REASON_SENDMSG_FAIL    ( 2)  /* sendmsg callback failed */
     298           0 : #define FD_TLS_REASON_WRONG_ENC_LVL   ( 3)  /* wrong encryption level */
     299           0 : #define FD_TLS_REASON_RAND_FAIL       ( 4)  /* rand fn failed */
     300             : 
     301           0 : #define FD_TLS_REASON_X25519_FAIL     ( 9)  /* fd_x25519_exchange failed */
     302           0 : #define FD_TLS_REASON_NO_X509         (10)  /* no X.509 cert installed */
     303           0 : #define FD_TLS_REASON_WRONG_PUBKEY    (11)  /* peer cert has different pubkey than expected */
     304           0 : #define FD_TLS_REASON_ED25519_FAIL    (12)  /* Ed25519 signature validation failed */
     305             : 
     306           0 : #define FD_TLS_REASON_CH_EXPECTED    (101)  /* wanted ClientHello, got another msg type */
     307           0 : #define FD_TLS_REASON_CH_PARSE       (103)  /* failed to parse ClientHello */
     308           0 : #define FD_TLS_REASON_CH_ENCODE      (104)  /* failed to encode ClientHello */
     309           3 : #define FD_TLS_REASON_CH_CRYPTO_NEG  (105)  /* ClientHello crypto negotiation failed */
     310           0 : #define FD_TLS_REASON_CH_NO_QUIC     (106)  /* Missing QUIC transport params in ClientHello */
     311             : 
     312           0 : #define FD_TLS_REASON_SH_EXPECTED    (201)  /* wanted ServerHello, got another msg type */
     313           3 : #define FD_TLS_REASON_SH_PARSE       (203)  /* failed to parse ServerHello */
     314           0 : #define FD_TLS_REASON_SH_ENCODE      (204)  /* failed to encode ServerHello */
     315             : 
     316           0 : #define FD_TLS_REASON_EE_NO_QUIC     (301)  /* Missing QUIC transport params in EncryptedExtensions */
     317           0 : #define FD_TLS_REASON_EE_EXPECTED    (302)  /* wanted EncryptedExtensions, got another msg type */
     318           0 : #define FD_TLS_REASON_EE_PARSE       (304)  /* failed to parse EncryptedExtensions */
     319           0 : #define FD_TLS_REASON_EE_ENCODE      (305)  /* failed to encode EncryptedExtensions */
     320           0 : #define FD_TLS_REASON_QUIC_TP_OVERSZ (306)  /* Buffer overflow in QUIC transport params callback */
     321             : 
     322           0 : #define FD_TLS_REASON_CV_EXPECTED    (401)  /* wanted CertificateVerify, got another msg type */
     323           0 : #define FD_TLS_REASON_CV_SIGALG      (402)  /* CertificateVerify sig is not Ed25519 */
     324           0 : #define FD_TLS_REASON_CV_PARSE       (404)  /* failed to parse CertificateVerify */
     325           0 : #define FD_TLS_REASON_CV_ENCODE      (405)  /* failed to encode CertificateVerify */
     326             : 
     327           0 : #define FD_TLS_REASON_CERT_CR_EXPECTED (501)  /* wanted Certificate or CertificateRequest, got another msg type */
     328           0 : #define FD_TLS_REASON_CERT_CR_PARSE    (503)  /* failed to parse Certificate or CertificateRequest */
     329             : 
     330           0 : #define FD_TLS_REASON_CERT_TYPE      (601)  /* unsupported certificate type */
     331           0 : #define FD_TLS_REASON_CERT_EXPECTED  (602)  /* wanted Certificate, got another msg type */
     332           0 : #define FD_TLS_REASON_CERT_PARSE     (604)  /* failed to parse Certificate */
     333           0 : #define FD_TLS_REASON_X509_PARSE     (605)  /* X.509 DER parse failed */
     334           0 : #define FD_TLS_REASON_SPKI_PARSE     (606)  /* Subject public key info parse failed */
     335             : 
     336           0 : #define FD_TLS_REASON_CERT_CHAIN_EMPTY    (701)  /* cert chain contains no certs */
     337           0 : #define FD_TLS_REASON_CERT_CHAIN_PARSE    (702)  /* failed to parse cert chain */
     338             : 
     339           0 : #define FD_TLS_REASON_FINI_PARSE     (901)  /* invalid Finished message */
     340           0 : #define FD_TLS_REASON_FINI_EXPECTED  (902)  /* wanted Finished, got another msg type */
     341           0 : #define FD_TLS_REASON_FINI_FAIL      (904)  /* Finished data mismatch */
     342             : 
     343           0 : #define FD_TLS_REASON_ALPN_PARSE     (1001)  /* failed to parse ALPN */
     344           0 : #define FD_TLS_REASON_ALPN_NEG       (1002)  /* ALPN negotiation failed */
     345           0 : #define FD_TLS_REASON_NO_ALPN        (1003)  /* no ALPN extension */
     346             : 
     347             : FD_PROTOTYPES_BEGIN
     348             : 
     349             : FD_FN_CONST ulong
     350             : fd_tls_align( void );
     351             : 
     352             : FD_FN_CONST ulong
     353             : fd_tls_footprint( void );
     354             : 
     355             : /* TODO document new/join/leave/delete */
     356             : 
     357             : void *
     358             : fd_tls_new( void * mem );
     359             : 
     360             : fd_tls_t *
     361             : fd_tls_join( void * );
     362             : 
     363             : void *
     364             : fd_tls_leave( fd_tls_t * );
     365             : 
     366             : void *
     367             : fd_tls_delete( void * );
     368             : 
     369             : FD_FN_PURE char const *
     370             : fd_tls_alert_cstr( uint alert );
     371             : 
     372             : FD_FN_PURE char const *
     373             : fd_tls_reason_cstr( uint reason );
     374             : 
     375             : /* fd_tls_server_handshake ingests a TLS message from the client.
     376             :    Synchronously processes the message (API may become async in the
     377             :    future).  Record must be complete (does not defragment).  Returns
     378             :    number of bytes read on success.  On failure, returns negated TLS
     379             :    alert code. */
     380             : 
     381             : long
     382             : fd_tls_server_handshake( fd_tls_t const *      tls,
     383             :                          fd_tls_estate_srv_t * handshake,
     384             :                          void const *          record,
     385             :                          ulong                 record_sz,
     386             :                          uint                  encryption_level );
     387             : 
     388             : /* fd_tls_client_handshake is the client-side equivalent of
     389             :    fd_tls_server_handshake.  Must not be called with messages sent after
     390             :    the handshake was completed (such as NewSessionTicket). */
     391             : 
     392             : long
     393             : fd_tls_client_handshake( fd_tls_t const *      client,
     394             :                          fd_tls_estate_cli_t * handshake,
     395             :                          void const *          record,
     396             :                          ulong                 record_sz,
     397             :                          uint                  encryption_level );
     398             : 
     399             : static inline long
     400             : fd_tls_handshake( fd_tls_t const *  tls,
     401             :                   fd_tls_estate_t * handshake,
     402             :                   void const *      record,
     403             :                   ulong             record_sz,
     404       42105 :                   uint              encryption_level ) {
     405       42105 :   if( handshake->base.server )
     406       12030 :     return fd_tls_server_handshake( tls, &handshake->srv, record, record_sz, encryption_level );
     407       30075 :   else
     408       30075 :     return fd_tls_client_handshake( tls, &handshake->cli, record, record_sz, encryption_level );
     409       42105 : }
     410             : 
     411             : /* fd_tls_hkdf_expand_label implements the TLS 1.3 HKDF-Expand function
     412             :    with SHA-256.  Writes the resulting hash to out.  secret is a 32 byte
     413             :    secret value.  label points to the label string.  label_sz is the
     414             :    number of chars in label (not including terminating NUL).  context
     415             :    points to the context byte array.  context_sz is the number of bytes
     416             :    in context.
     417             : 
     418             :    Constraints:
     419             : 
     420             :      out   !=NULL
     421             :      secret!=NULL
     422             :      label_sz  ==0 || label  !=NULL
     423             :      context_sz==0 || context!=NULL
     424             :      1<=out_sz    <=32
     425             :      0<=label_sz  <=64
     426             :      0<=context_sz<=64 */
     427             : 
     428             : void *
     429             : fd_tls_hkdf_expand_label( uchar *       out,
     430             :                           ulong         out_sz,
     431             :                           uchar const   secret[ static 32 ],
     432             :                           char const *  label,
     433             :                           ulong         label_sz,
     434             :                           uchar const * context,
     435             :                           ulong         context_sz );
     436             : 
     437             : FD_PROTOTYPES_END
     438             : 
     439             : #endif /* HEADER_src_ballet_tls_fd_tls_h */

Generated by: LCOV version 1.14