LCOV - code coverage report
Current view: top level - ballet/x509 - fd_x509.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 17 17 100.0 %
Date: 2026-09-17 04:28:31 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_ballet_x509_fd_x509_h
       2             : #define HEADER_fd_src_ballet_x509_fd_x509_h
       3             : 
       4             : /* fd_x509.h provides a minimal ASN.1 DER parser for X.509 certificates.
       5             : 
       6             :    Supported key / signature algorithms:
       7             :    - Ed25519 (OID 1.3.101.112)
       8             :    - ECDSA P-256 with SHA-256
       9             :    - ECDSA P-384 with SHA-384
      10             :    - RSA with PKCS#1 v1.5 and SHA-{256,384,512} */
      11             : 
      12             : #include "../rsa/fd_rsa.h"
      13             : 
      14             : /* Key type identifiers */
      15             : 
      16      637686 : #define FD_X509_KEY_ED25519    ((uchar)0)
      17        4878 : #define FD_X509_KEY_ECDSA_P256 ((uchar)1)
      18          66 : #define FD_X509_KEY_ECDSA_P384 ((uchar)2)
      19        1644 : #define FD_X509_KEY_RSA        ((uchar)3)
      20      646848 : #define FD_X509_KEY_UNKNOWN    ((uchar)0xFF)
      21             : 
      22             : /* FD_X509_PUBKEY_MAX is the max size of the subjectPublicKey content
      23             :    of a supported key type.  The largest is the DER RSAPublicKey of an
      24             :    RSA-4096 key with a 64 bit exponent: SEQUENCE header (4), modulus
      25             :    INTEGER (5+512), exponent INTEGER (2+9). */
      26             : 
      27             : #define FD_X509_PUBKEY_MAX (532UL)
      28             : 
      29             : /* Signature algorithm identifiers */
      30             : 
      31      320958 : #define FD_X509_SIG_ED25519            ((uchar)0)
      32        2739 : #define FD_X509_SIG_ECDSA_SHA256       ((uchar)1)
      33         366 : #define FD_X509_SIG_ECDSA_SHA384       ((uchar)2)
      34         120 : #define FD_X509_SIG_RSA_SHA256         ((uchar)3)  /* RSASSA-PKCS1-v1_5 */
      35          63 : #define FD_X509_SIG_RSA_SHA384         ((uchar)4)
      36          60 : #define FD_X509_SIG_RSA_SHA512         ((uchar)5)
      37      322974 : #define FD_X509_SIG_UNKNOWN            ((uchar)0xFF)
      38             : 
      39             : /* keyUsage bits (RFC 5280 Section 4.2.1.3), big endian */
      40             : 
      41             : #define FD_X509_KU_DIGITAL_SIGNATURE ((ushort)0x8000)  /* bit 0 */
      42             : #define FD_X509_KU_NON_REPUDIATION   ((ushort)0x4000)  /* bit 1 */
      43             : #define FD_X509_KU_KEY_ENCIPHERMENT  ((ushort)0x2000)  /* bit 2 */
      44             : #define FD_X509_KU_DATA_ENCIPHERMENT ((ushort)0x1000)  /* bit 3 */
      45             : #define FD_X509_KU_KEY_AGREEMENT     ((ushort)0x0800)  /* bit 4 */
      46         330 : #define FD_X509_KU_KEY_CERT_SIGN     ((ushort)0x0400)  /* bit 5 */
      47             : #define FD_X509_KU_CRL_SIGN          ((ushort)0x0200)  /* bit 6 */
      48             : #define FD_X509_KU_ENCIPHER_ONLY     ((ushort)0x0100)  /* bit 7 */
      49             : #define FD_X509_KU_DECIPHER_ONLY     ((ushort)0x0080)  /* bit 8 */
      50             : 
      51             : /* extKeyUsage purposes (RFC 5280 Section 4.2.1.12) */
      52             : 
      53        1596 : #define FD_X509_EKU_SERVER_AUTH      ((ushort)0x0001)  /* 1.3.6.1.5.5.7.3.1 */
      54          24 : #define FD_X509_EKU_ANY              ((ushort)0x0002)  /* 2.5.29.37.0 */
      55             : 
      56             : /* FD_X509_TIME_INVALID marks a validity timestamp that could not be
      57             :    parsed. */
      58             : 
      59          96 : #define FD_X509_TIME_INVALID (LONG_MIN)
      60             : 
      61         198 : #define FD_X509_EXT_MAX (64UL)
      62             : 
      63             : struct fd_x509_cert_info {
      64             :   /* TBSCertificate version: 0=v1, 1=v2, 2=v3 */
      65             :   uchar         version;
      66             : 
      67             :   /* Subject Public Key Info.  pubkey is the subjectPublicKey BIT
      68             :      STRING content: a raw Ed25519 key, an uncompressed EC point, or a
      69             :      DER RSAPublicKey (see fd_x509_decode_rsa_pubkey) for the supported
      70             :      key types, opaque for FD_X509_KEY_UNKNOWN. */
      71             :   uchar const * pubkey;
      72             :   ulong         pubkey_len;
      73             :   uchar         key_type;     /* FD_X509_KEY_{...} */
      74             : 
      75             :   /* TBS (to-be-signed) region */
      76             :   uchar const * tbs;
      77             :   ulong         tbs_len;
      78             : 
      79             :   /* Issuer and Subject  */
      80             :   uchar const * issuer;
      81             :   ulong         issuer_len;
      82             :   uchar const * subject;
      83             :   ulong         subject_len;
      84             : 
      85             :   /* Validity period */
      86             :   uchar const * not_before;
      87             :   ulong         not_before_len;
      88             :   uchar         not_before_tag;  /* FD_DER_TAG_{UTC,GENERALIZED}_TIME */
      89             :   long          not_before_unix; /* seconds since the Unix epoch (or FD_X509_TIME_INVALID) */
      90             :   uchar const * not_after;
      91             :   ulong         not_after_len;
      92             :   uchar         not_after_tag;
      93             :   long          not_after_unix; /* seconds since the Unix epoch (or FD_X509_TIME_INVALID) */
      94             : 
      95             :   /* Certificate signature */
      96             :   uchar const * sig;
      97             :   ulong         sig_len;
      98             :   uchar         sig_alg;   /* FD_X509_SIG_{...} */
      99             : 
     100             :   /* Basic Constraints (RFC 5280 Section 4.2.1.9) */
     101             :   ulong         path_len_constraint;     /* valid if has_path_len_constraint */
     102             :   int           is_ca;                    /* 1 if basicConstraints cA=TRUE */
     103             :   uchar         has_basic_constraints;
     104             :   uchar         has_path_len_constraint;
     105             : 
     106             :   /* Key Usage (RFC 5280 Section 4.2.1.3) */
     107             :   ushort        key_usage;          /* FD_X509_KU_* bits, 0 if absent */
     108             :   uchar         has_key_usage;
     109             : 
     110             :   /* Extended Key Usage (RFC 5280 Section 4.2.1.12) */
     111             :   ushort        ext_key_usage;      /* FD_X509_EKU_* bits, 0 if absent */
     112             :   uchar         has_ext_key_usage;
     113             : 
     114             :   /* Subject Alternative Name GeneralNames content */
     115             :   uchar const * san_general_names;
     116             :   ulong         san_general_names_len;
     117             :   uchar         has_subject_alt_name;
     118             : 
     119             :   /* Name Constraints (RFC 5280 Section 4.2.1.10).  Each pointer is the
     120             :      content of an IMPLICIT GeneralSubtrees field.  The verifier
     121             :      enforces dNSName, iPAddress and directoryName subtrees; a subtree
     122             :      of any other form rejects certs carrying a SAN of that form. */
     123             :   uchar const * name_constraints_permitted;
     124             :   ulong         name_constraints_permitted_len;
     125             :   uchar const * name_constraints_excluded;
     126             :   ulong         name_constraints_excluded_len;
     127             :   uchar         has_name_constraints;
     128             : };
     129             : 
     130             : typedef struct fd_x509_cert_info fd_x509_cert_info_t;
     131             : 
     132             : FD_PROTOTYPES_BEGIN
     133             : 
     134             : /* fd_x509_extract_pubkey parses cert and returns its subject public key and
     135             :    FD_X509_KEY_* type.  Supported key types are Ed25519, ECDSA P-256,
     136             :    ECDSA P-384, and RSA.  *out_pubkey aliases cert and remains valid only
     137             :    while cert remains valid.  cert and all output arguments must be
     138             :    non-NULL.
     139             : 
     140             :    Returns 0 on success and -1 if cert is malformed or its key type is
     141             :    unsupported. */
     142             : 
     143             : int
     144             : fd_x509_extract_pubkey( uchar const *  cert,
     145             :                         ulong          cert_sz,
     146             :                         uchar const ** out_pubkey,
     147             :                         ulong *        out_pubkey_len,
     148             :                         uchar *        out_key_type );
     149             : 
     150             : 
     151             : /* fd_x509_decode_ecdsa_sig decodes a DER-encoded ECDSA signature
     152             :    SEQUENCE { INTEGER r, INTEGER s } into raw_sig
     153             :    raw_sig must have room for 2*scalar_sz bytes, where scalar_sz is
     154             :    32 for P256 and 48 for P384.
     155             :    Returns 0 on success, -1 on failure. */
     156             : 
     157             : int
     158             : fd_x509_decode_ecdsa_sig( uchar const * der,
     159             :                           ulong         der_len,
     160             :                           uchar *       raw_sig,
     161             :                           ulong         scalar_sz );
     162             : 
     163             : /* fd_x509_decode_rsa_pubkey decodes the subjectPublicKey content of
     164             :    an FD_X509_KEY_RSA key, a DER RSAPublicKey ::= SEQUENCE { modulus
     165             :    INTEGER, publicExponent INTEGER }, into key.  Returns 0 on success
     166             :    and -1 if pubkey is malformed or the key is outside the range fd_rsa
     167             :    supports (never the case for pubkey taken from a cert that parsed
     168             :    with key_type FD_X509_KEY_RSA). */
     169             : 
     170             : int
     171             : fd_x509_decode_rsa_pubkey( uchar const *     pubkey,
     172             :                            ulong             pubkey_len,
     173             :                            fd_rsa_pubkey_t * key );
     174             : 
     175             : /* fd_x509_ec_point_compress compresses a supported
     176             :    uncompressed EC point (04 || x || y) into compressed form (02/03 || x).
     177             :    coord_sz must be 32 for P-256 or 48 for P-384.  uncompressed must be
     178             :    at least 1+2*coord_sz bytes.  Coordinates must be canonical and the
     179             :    exact supplied point must satisfy the curve equation.  compressed
     180             :    must be at least 1+coord_sz bytes. Both pointers must be non-NULL.
     181             :    Returns 0 on success, -1 on failure. */
     182             : 
     183             : int
     184             : fd_x509_ec_point_compress( uchar const * uncompressed,
     185             :                            ulong         coord_sz,
     186             :                            uchar *       compressed );
     187             : 
     188             : /* fd_x509_cert_parse fully parses a DER-encoded X.509 cert.
     189             : 
     190             :    Returns 0 on success and -1 if cert is malformed.  An unsupported
     191             :    public key or signature algorithm is not malformed: out->key_type is
     192             :    then FD_X509_KEY_UNKNOWN or out->sig_alg is FD_X509_SIG_UNKNOWN, and
     193             :    the cert can be inspected but not used to verify anything.
     194             : 
     195             :    All pointers in *out refer into the [cert, cert+cert_sz) buffer. */
     196             : 
     197             : int
     198             : fd_x509_cert_parse( uchar const *         cert,
     199             :                     ulong                 cert_sz,
     200             :                     fd_x509_cert_info_t * out );
     201             : 
     202             : /* fd_x509_name_equal compares two DER-encoded X.509 Names according to
     203             :    the RFC 5280 distinguished-name matching rules supported by this
     204             :    verifier.  Returns 1 if equal and 0 otherwise. */
     205             : 
     206             : int
     207             : fd_x509_name_equal( uchar const * a,
     208             :                     ulong         a_len,
     209             :                     uchar const * b,
     210             :                     ulong         b_len );
     211             : 
     212             : /* fd_x509_name_prefix returns 1 if the RDNs of the DER-encoded Name
     213             :    prefix, compared with the same rules as fd_x509_name_equal, form a
     214             :    leading subsequence of the RDNs of name (RFC 5280 Section 4.2.1.10
     215             :    directoryName subtree matching).  An empty prefix matches every
     216             :    name.  Returns 0 otherwise, including on malformed input; Names
     217             :    taken from fd_x509_cert_parse output are never malformed. */
     218             : 
     219             : int
     220             : fd_x509_name_prefix( uchar const * prefix,
     221             :                      ulong         prefix_len,
     222             :                      uchar const * name,
     223             :                      ulong         name_len );
     224             : 
     225             : /* fd_x509_time_parse converts an ASN.1 time value to seconds since the
     226             :    Unix epoch.  tag is FD_DER_TAG_UTC_TIME (YYMMDDHHMMSSZ, 13 bytes) or
     227             :    FD_DER_TAG_GENERALIZED_TIME (YYYYMMDDHHMMSSZ, 15 bytes).  [s,s+s_len)
     228             :    is the DER content, without tag and length.
     229             : 
     230             :    Returns seconds since the Unix epoch, or FD_X509_TIME_INVALID if the
     231             :    value is malformed or outside the accepted profile. */
     232             : 
     233             : long
     234             : fd_x509_time_parse( uchar         tag,
     235             :                     uchar const * s,
     236             :                     ulong         s_len );
     237             : 
     238             : /* fd_x509_dns_name_valid returns 1 if [name,name+len) is a
     239             :    syntactically valid DNS hostname (RFC 1123 preferred syntax, plus
     240             :    '_').  Rejects empty labels, so a leading dot, a trailing dot, and
     241             :    ".." are all invalid.  fd_x509_dns_eq_ci compares two DNS names of
     242             :    equal length, folding ASCII case. */
     243             : 
     244             : FD_FN_PURE int
     245             : fd_x509_dns_name_valid( char const * name,
     246             :                         ulong        len );
     247             : 
     248             : FD_FN_PURE int
     249             : fd_x509_dns_eq_ci( char const * a,
     250             :                    char const * b,
     251             :                    ulong        len );
     252             : 
     253             : /* fd_x509_san_matches tests hostname against info's subjectAltName
     254             :    extension.  Supports dNSName and IPv4 iPAddress.  Returns 1 for a
     255             :    match and 0 for no match, an absent SAN, malformed input, or a NULL
     256             :    argument. */
     257             : 
     258             : int
     259             : fd_x509_san_matches( fd_x509_cert_info_t const * info,
     260             :                      char const *                hostname,
     261             :                      ulong                       hostname_len );
     262             : 
     263             : FD_PROTOTYPES_END
     264             : 
     265             : #endif /* HEADER_fd_src_ballet_x509_fd_x509_h */

Generated by: LCOV version 1.14