LCOV - code coverage report
Current view: top level - ballet/x509 - fd_x509.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 17 0.0 %
Date: 2026-11-11 12:40:43 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           0 : #define FD_X509_KEY_ED25519    ((uchar)0)
      17           0 : #define FD_X509_KEY_ECDSA_P256 ((uchar)1)
      18           0 : #define FD_X509_KEY_ECDSA_P384 ((uchar)2)
      19           0 : #define FD_X509_KEY_RSA        ((uchar)3)
      20           0 : #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           0 : #define FD_X509_SIG_ED25519            ((uchar)0)
      32           0 : #define FD_X509_SIG_ECDSA_SHA256       ((uchar)1)
      33           0 : #define FD_X509_SIG_ECDSA_SHA384       ((uchar)2)
      34           0 : #define FD_X509_SIG_RSA_SHA256         ((uchar)3)  /* RSASSA-PKCS1-v1_5 */
      35           0 : #define FD_X509_SIG_RSA_SHA384         ((uchar)4)
      36           0 : #define FD_X509_SIG_RSA_SHA512         ((uchar)5)
      37           0 : #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           0 : #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           0 : #define FD_X509_EKU_SERVER_AUTH      ((ushort)0x0001)  /* 1.3.6.1.5.5.7.3.1 */
      54           0 : #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           0 : #define FD_X509_TIME_INVALID (LONG_MIN)
      60             : 
      61           0 : #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             :   uchar         basic_constraints_noncritical; /* 1 if cA=TRUE but extension is not critical */
     106             : 
     107             :   /* Key Usage (RFC 5280 Section 4.2.1.3) */
     108             :   ushort        key_usage;          /* FD_X509_KU_* bits, 0 if absent */
     109             :   uchar         has_key_usage;
     110             : 
     111             :   /* Extended Key Usage (RFC 5280 Section 4.2.1.12) */
     112             :   ushort        ext_key_usage;      /* FD_X509_EKU_* bits, 0 if absent */
     113             :   uchar         has_ext_key_usage;
     114             : 
     115             :   /* Subject Alternative Name GeneralNames content */
     116             :   uchar const * san_general_names;
     117             :   ulong         san_general_names_len;
     118             :   uchar         has_subject_alt_name;
     119             : 
     120             :   /* Name Constraints (RFC 5280 Section 4.2.1.10).  Each pointer is the
     121             :      content of an IMPLICIT GeneralSubtrees field.  The verifier
     122             :      enforces dNSName, iPAddress and directoryName subtrees; a subtree
     123             :      of any other form rejects certs carrying a SAN of that form. */
     124             :   uchar const * name_constraints_permitted;
     125             :   ulong         name_constraints_permitted_len;
     126             :   uchar const * name_constraints_excluded;
     127             :   ulong         name_constraints_excluded_len;
     128             :   uchar         has_name_constraints;
     129             : };
     130             : 
     131             : typedef struct fd_x509_cert_info fd_x509_cert_info_t;
     132             : 
     133             : FD_PROTOTYPES_BEGIN
     134             : 
     135             : /* fd_x509_extract_pubkey parses cert and returns its subject public key and
     136             :    FD_X509_KEY_* type.  Supported key types are Ed25519, ECDSA P-256,
     137             :    ECDSA P-384, and RSA.  *out_pubkey aliases cert and remains valid only
     138             :    while cert remains valid.  cert and all output arguments must be
     139             :    non-NULL.
     140             : 
     141             :    Returns 0 on success and -1 if cert is malformed or its key type is
     142             :    unsupported. */
     143             : 
     144             : int
     145             : fd_x509_extract_pubkey( uchar const *  cert,
     146             :                         ulong          cert_sz,
     147             :                         uchar const ** out_pubkey,
     148             :                         ulong *        out_pubkey_len,
     149             :                         uchar *        out_key_type );
     150             : 
     151             : 
     152             : /* fd_x509_decode_ecdsa_sig decodes a DER-encoded ECDSA signature
     153             :    SEQUENCE { INTEGER r, INTEGER s } into raw_sig
     154             :    raw_sig must have room for 2*scalar_sz bytes, where scalar_sz is
     155             :    32 for P256 and 48 for P384.
     156             :    Returns 0 on success, -1 on failure. */
     157             : 
     158             : int
     159             : fd_x509_decode_ecdsa_sig( uchar const * der,
     160             :                           ulong         der_len,
     161             :                           uchar *       raw_sig,
     162             :                           ulong         scalar_sz );
     163             : 
     164             : /* fd_x509_decode_rsa_pubkey decodes the subjectPublicKey content of
     165             :    an FD_X509_KEY_RSA key, a DER RSAPublicKey ::= SEQUENCE { modulus
     166             :    INTEGER, publicExponent INTEGER }, into key.  Returns 0 on success
     167             :    and -1 if pubkey is malformed or the key is outside the range fd_rsa
     168             :    supports (never the case for pubkey taken from a cert that parsed
     169             :    with key_type FD_X509_KEY_RSA). */
     170             : 
     171             : int
     172             : fd_x509_decode_rsa_pubkey( uchar const *     pubkey,
     173             :                            ulong             pubkey_len,
     174             :                            fd_rsa_pubkey_t * key );
     175             : 
     176             : /* fd_x509_ec_point_compress compresses a supported
     177             :    uncompressed EC point (04 || x || y) into compressed form (02/03 || x).
     178             :    coord_sz must be 32 for P-256 or 48 for P-384.  uncompressed must be
     179             :    at least 1+2*coord_sz bytes.  Coordinates must be canonical and the
     180             :    exact supplied point must satisfy the curve equation.  compressed
     181             :    must be at least 1+coord_sz bytes. Both pointers must be non-NULL.
     182             :    Returns 0 on success, -1 on failure. */
     183             : 
     184             : int
     185             : fd_x509_ec_point_compress( uchar const * uncompressed,
     186             :                            ulong         coord_sz,
     187             :                            uchar *       compressed );
     188             : 
     189             : /* fd_x509_cert_parse fully parses a DER-encoded X.509 cert.
     190             : 
     191             :    Returns 0 on success and -1 if cert is malformed.  An unsupported
     192             :    public key or signature algorithm is not malformed: out->key_type is
     193             :    then FD_X509_KEY_UNKNOWN or out->sig_alg is FD_X509_SIG_UNKNOWN, and
     194             :    the cert can be inspected but not used to verify anything.
     195             : 
     196             :    All pointers in *out refer into the [cert, cert+cert_sz) buffer. */
     197             : 
     198             : int
     199             : fd_x509_cert_parse( uchar const *         cert,
     200             :                     ulong                 cert_sz,
     201             :                     fd_x509_cert_info_t * out );
     202             : 
     203             : /* fd_x509_name_equal compares two DER-encoded X.509 Names according to
     204             :    the RFC 5280 distinguished-name matching rules supported by this
     205             :    verifier.  Returns 1 if equal and 0 otherwise. */
     206             : 
     207             : int
     208             : fd_x509_name_equal( uchar const * a,
     209             :                     ulong         a_len,
     210             :                     uchar const * b,
     211             :                     ulong         b_len );
     212             : 
     213             : /* fd_x509_name_prefix returns 1 if the RDNs of the DER-encoded Name
     214             :    prefix, compared with the same rules as fd_x509_name_equal, form a
     215             :    leading subsequence of the RDNs of name (RFC 5280 Section 4.2.1.10
     216             :    directoryName subtree matching).  An empty prefix matches every
     217             :    name.  Returns 0 otherwise, including on malformed input; Names
     218             :    taken from fd_x509_cert_parse output are never malformed. */
     219             : 
     220             : int
     221             : fd_x509_name_prefix( uchar const * prefix,
     222             :                      ulong         prefix_len,
     223             :                      uchar const * name,
     224             :                      ulong         name_len );
     225             : 
     226             : /* fd_x509_time_parse converts an ASN.1 time value to seconds since the
     227             :    Unix epoch.  tag is FD_DER_TAG_UTC_TIME (YYMMDDHHMMSSZ, 13 bytes) or
     228             :    FD_DER_TAG_GENERALIZED_TIME (YYYYMMDDHHMMSSZ, 15 bytes).  [s,s+s_len)
     229             :    is the DER content, without tag and length.
     230             : 
     231             :    Returns seconds since the Unix epoch, or FD_X509_TIME_INVALID if the
     232             :    value is malformed or outside the accepted profile. */
     233             : 
     234             : long
     235             : fd_x509_time_parse( uchar         tag,
     236             :                     uchar const * s,
     237             :                     ulong         s_len );
     238             : 
     239             : /* fd_x509_dns_name_valid returns 1 if [name,name+len) is a
     240             :    syntactically valid DNS hostname (RFC 1123 preferred syntax, plus
     241             :    '_').  Rejects empty labels, so a leading dot, a trailing dot, and
     242             :    ".." are all invalid.  fd_x509_dns_eq_ci compares two DNS names of
     243             :    equal length, folding ASCII case. */
     244             : 
     245             : FD_FN_PURE int
     246             : fd_x509_dns_name_valid( char const * name,
     247             :                         ulong        len );
     248             : 
     249             : FD_FN_PURE int
     250             : fd_x509_dns_eq_ci( char const * a,
     251             :                    char const * b,
     252             :                    ulong        len );
     253             : 
     254             : /* fd_x509_san_matches tests hostname against info's subjectAltName
     255             :    extension.  Supports dNSName and IPv4 iPAddress.  Returns 1 for a
     256             :    match and 0 for no match, an absent SAN, malformed input, or a NULL
     257             :    argument. */
     258             : 
     259             : int
     260             : fd_x509_san_matches( fd_x509_cert_info_t const * info,
     261             :                      char const *                hostname,
     262             :                      ulong                       hostname_len );
     263             : 
     264             : FD_PROTOTYPES_END
     265             : 
     266             : #endif /* HEADER_fd_src_ballet_x509_fd_x509_h */

Generated by: LCOV version 1.14