osiris data structures in c

1 minute read

OSiRIS Data Structures in C

Below are C implementations of the core data structures described in the OSiRIS Access Assertions document.

Header Files

osiris_types.h

#ifndef OSIRIS_TYPES_H
#define OSIRIS_TYPES_H

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <time.h>

#define OSIRIS_MAX_SUBJECTS      16
#define OSIRIS_MAX_AUDIENCES     16
#define OSIRIS_MAX_SESSION_KEYS  16
#define OSIRIS_MAX_ACCESS_ITEMS  32
#define OSIRIS_MAX_RESOURCES     16
#define OSIRIS_MAX_SLA_ITEMS     8
#define OSIRIS_MAX_GRANTS        8
#define OSIRIS_MAX_ASSERTIONS    8
#define OSIRIS_MAX_KINDS         8
#define OSIRIS_MAX_JWK_KEYS      4

#define OSIRIS_UUID_LEN          37
#define OSIRIS_URN_MAX_LEN       128
#define OSIRIS_URL_MAX_LEN       256
#define OSIRIS_KEY_THUMBPRINT_LEN 44
#define OSIRIS_SESSION_KEY_LEN   32
#define OSIRIS_NONCE_LEN         24

/* Token type identifiers */
typedef enum {
    OSIRIS_TOKEN_OAR = 0,  /* OSiRIS Access Request */
    OSIRIS_TOKEN_OAG,      /* OSiRIS Access Grant */
    OSIRIS_TOKEN_OAA,      /* OSiRIS Access Assertion */
    OSIRIS_TOKEN_OAT,      /* OSiRIS Access Token (JWT compatible) */
    OSIRIS_TOKEN_ORT       /* OSiRIS Refresh Token */
} osiris_token_type_t;

/* Algorithm identifiers */
typedef enum {
    OSIRIS_ALG_RS256 = 0,
    OSIRIS_ALG_RS384,
    OSIRIS_ALG_RS512,
    OSIRIS_ALG_ES256,
    OSIRIS_ALG_ES384,
    OSIRIS_ALG_ES512
} osiris_algorithm_t;

/* Access kind flags */
typedef enum {
    OSIRIS_ACCESS_NONE   = 0,
    OSIRIS_ACCESS_READ   = 1 << 0,
    OSIRIS_ACCESS_WRITE  = 1 << 1,
    OSIRIS_ACCESS_ADMIN  = 1 << 2,
    OSIRIS_ACCESS_LOGIN  = 1 << 3,
    OSIRIS_ACCESS_SUDO   = 1 << 4
} osiris_access_kind_t;

/* Resource types */
typedef enum {
    OSIRIS_RESOURCE_UNKNOWN = 0,
    OSIRIS_RESOURCE_CEPHFS_MOUNT,
    OSIRIS_RESOURCE_SHELL_ACCOUNT,
    OSIRIS_RESOURCE_S3_BUCKET,
    OSIRIS_RESOURCE_BLOCK_DEVICE
} osiris_resource_type_t;

/* JWK key use */
typedef enum {
    OSIRIS_JWK_USE_SIG = 0,
    OSIRIS_JWK_USE_ENC
} osiris_jwk_use_t;

/* JWK key type */
typedef enum {
    OSIRIS_JWK_KTY_RSA = 0,
    OSIRIS_JWK_KTY_EC,
    OSIRIS_JWK_KTY_OKP
} osiris_jwk_kty_t;

#endif /* OSIRIS_TYPES_H */

osiris_common.h

#ifndef OSIRIS_COMMON_H
#define OSIRIS_COMMON_H

#include "osiris_types.h"

/* Forward declarations */
typedef struct osiris_buffer osiris_buffer_t;
typedef struct osiris_string osiris_string_t;
typedef struct osiris_urn osiris_urn_t;

/* Dynamic buffer for binary data */
struct osiris_buffer {
    uint8_t *data;
    size_t   len;
    size_t   capacity;
};

/* Dynamic string */
struct osiris_string {
    char   *data;
    size_t  len;
    size_t  capacity;
};

/* URN representation */
struct osiris_urn {
    char    full[OSIRIS_URN_MAX_LEN];
    char   *scheme;     /* Points into full */
    char   *nid;        /* Namespace identifier */
    char   *nss;        /* Namespace specific string */
};

/* Buffer operations */
osiris_buffer_t *osiris_buffer_new(size_t initial_capacity);
void osiris_buffer_free(osiris_buffer_t *buf);
int osiris_buffer_append(osiris_buffer_t *buf, const uint8_t *data, size_t len);
int osiris_buffer_resize(osiris_buffer_t *buf, size_t new_capacity);

/* String operations */
osiris_string_t *osiris_string_new(const char *initial);
void osiris_string_free(osiris_string_t *str);
int osiris_string_append(osiris_string_t *str, const char *data);
int osiris_string_append_n(osiris_string_t *str, const char *data, size_t len);

/* URN operations */
int osiris_urn_parse(osiris_urn_t *urn, const char *urn_str);
int osiris_urn_format_uuid(osiris_urn_t *urn, const char *uuid);
int osiris_urn_format_oid(osiris_urn_t *urn, const char *oid, const char *value);
bool osiris_urn_is_uuid(const osiris_urn_t *urn);
bool osiris_urn_is_oid(const osiris_urn_t *urn);

/* Base64URL encoding/decoding */
int osiris_base64url_encode(const uint8_t *input, size_t input_len,
                            char *output, size_t *output_len);
int osiris_base64url_decode(const char *input, size_t input_len,
                            uint8_t *output, size_t *output_len);

/* Utility functions */
const char *osiris_token_type_str(osiris_token_type_t type);
const char *osiris_algorithm_str(osiris_algorithm_t alg);
const char *osiris_resource_type_str(osiris_resource_type_t type);

#endif /* OSIRIS_COMMON_H */

osiris_crypto.h

#ifndef OSIRIS_CRYPTO_H
#define OSIRIS_CRYPTO_H

#include "osiris_types.h"
#include "osiris_common.h"

/* JWK (JSON Web Key) structure */
typedef struct osiris_jwk {
    osiris_jwk_use_t use;
    osiris_jwk_kty_t kty;
    char            *kid;           /* Key ID (optional) */
    
    /* RSA parameters (base64url encoded) */
    char            *n;             /* Modulus */
    char            *e;             /* Exponent */
    
    /* Private key components (if present) */
    char            *d;             /* Private exponent */
    char            *p;             /* First prime factor */
    char            *q;             /* Second prime factor */
    char            *dp;            /* d mod (p-1) */
    char            *dq;            /* d mod (q-1) */
    char            *qi;            /* q^-1 mod p */
} osiris_jwk_t;

/* JWKS (JSON Web Key Set) structure */
typedef struct osiris_jwks {
    osiris_jwk_t    keys[OSIRIS_MAX_JWK_KEYS];
    size_t          num_keys;
} osiris_jwks_t;

/* Session key for symmetric encryption */
typedef struct osiris_session_key {
    uint8_t         key[OSIRIS_SESSION_KEY_LEN];
    bool            is_null;        /* If true, this audience excluded */
} osiris_session_key_t;

/* Encrypted session keys array */
typedef struct osiris_encrypted_session_keys {
    char           *encrypted[OSIRIS_MAX_AUDIENCES];
    size_t          count;
} osiris_encrypted_session_keys_t;

/* Opaque encrypted data */
typedef struct osiris_opaque {
    uint8_t         nonce[OSIRIS_NONCE_LEN];
    osiris_buffer_t *ciphertext;
} osiris_opaque_t;

/* Key thumbprint (SHA256 of DER-encoded public key) */
typedef struct osiris_key_thumbprint {
    char            base64url[OSIRIS_KEY_THUMBPRINT_LEN + 1];
    uint8_t         raw[32];
} osiris_key_thumbprint_t;

/* JWK operations */
osiris_jwk_t *osiris_jwk_new(void);
void osiris_jwk_free(osiris_jwk_t *jwk);
osiris_jwk_t *osiris_jwk_from_json(const char *json);
char *osiris_jwk_to_json(const osiris_jwk_t *jwk);

/* JWKS operations */
osiris_jwks_t *osiris_jwks_new(void);
void osiris_jwks_free(osiris_jwks_t *jwks);
int osiris_jwks_add_key(osiris_jwks_t *jwks, const osiris_jwk_t *key);
osiris_jwk_t *osiris_jwks_find_by_use(const osiris_jwks_t *jwks, 
                                       osiris_jwk_use_t use);

/* Session key operations */
int osiris_session_key_generate(osiris_session_key_t *sk);
int osiris_session_key_encrypt(const osiris_session_key_t *sk,
                               const osiris_jwk_t *public_key,
                               char **encrypted_out);
int osiris_session_key_decrypt(osiris_session_key_t *sk,
                               const char *encrypted,
                               const osiris_jwk_t *private_key);

/* Opaque data operations */
osiris_opaque_t *osiris_opaque_new(void);
void osiris_opaque_free(osiris_opaque_t *opaque);
int osiris_opaque_encrypt(osiris_opaque_t *opaque,
                          const uint8_t *plaintext, size_t plaintext_len,
                          const osiris_session_key_t *sk);
int osiris_opaque_decrypt(const osiris_opaque_t *opaque,
                          uint8_t **plaintext_out, size_t *plaintext_len,
                          const osiris_session_key_t *sk);
char *osiris_opaque_to_base64url(const osiris_opaque_t *opaque);
osiris_opaque_t *osiris_opaque_from_base64url(const char *encoded);

/* Key thumbprint operations */
int osiris_key_thumbprint_compute(osiris_key_thumbprint_t *thumbprint,
                                  const osiris_jwk_t *signing_key);

#endif /* OSIRIS_CRYPTO_H */

osiris_metadata.h

#ifndef OSIRIS_METADATA_H
#define OSIRIS_METADATA_H

#include "osiris_types.h"
#include "osiris_common.h"
#include "osiris_crypto.h"

/* Central Authority metadata */
typedef struct osiris_ca_metadata {
    osiris_urn_t     issuer;
    char             grant_endpoint[OSIRIS_URL_MAX_LEN];
    char             token_endpoint[OSIRIS_URL_MAX_LEN];
    char             jwks_uri[OSIRIS_URL_MAX_LEN];
    osiris_jwks_t   *jwks;          /* Inline JWKS (optional) */
} osiris_ca_metadata_t;

/* Resource Provider service scope */
typedef struct osiris_rp_service {
    char            *service_pattern;   /* e.g., "ceph.*@wayne.edu" */
    char            *scope;             /* Extracted scope if present */
} osiris_rp_service_t;

/* Resource Provider metadata */
typedef struct osiris_rp_metadata {
    osiris_urn_t         issuer;
    char                 request_endpoint[OSIRIS_URL_MAX_LEN];
    char                 token_endpoint[OSIRIS_URL_MAX_LEN];
    char                 jwks_uri[OSIRIS_URL_MAX_LEN];
    osiris_jwks_t       *jwks;
    osiris_rp_service_t *provides;
    size_t               provides_count;
} osiris_rp_metadata_t;

/* Metadata operations */
osiris_ca_metadata_t *osiris_ca_metadata_new(void);
void osiris_ca_metadata_free(osiris_ca_metadata_t *meta);
char *osiris_ca_metadata_to_json(const osiris_ca_metadata_t *meta);
osiris_ca_metadata_t *osiris_ca_metadata_from_json(const char *json);

osiris_rp_metadata_t *osiris_rp_metadata_new(void);
void osiris_rp_metadata_free(osiris_rp_metadata_t *meta);
char *osiris_rp_metadata_to_json(const osiris_rp_metadata_t *meta);
osiris_rp_metadata_t *osiris_rp_metadata_from_json(const char *json);

/* Service matching */
bool osiris_rp_provides_service(const osiris_rp_metadata_t *meta,
                                const char *service_type,
                                const char *scope);

#endif /* OSIRIS_METADATA_H */

osiris_access.h

#ifndef OSIRIS_ACCESS_H
#define OSIRIS_ACCESS_H

#include "osiris_types.h"
#include "osiris_common.h"
#include "osiris_crypto.h"

/* Service Level Agreement arbitrator */
typedef struct osiris_sla_arbitrator {
    char            *src_ip;
    char            *ssh_pubkey;
    char            *exec_cmd;          /* Optional command to run */
} osiris_sla_arbitrator_t;

/* Service Level Agreement */
typedef struct osiris_service_level {
    char                    *src_network;   /* CIDR notation */
    char                    *dst_network;   /* CIDR notation */
    
    /* Availability */
    double                   uptime;        /* e.g., 0.9999 for 99.99% */
    
    /* Throughput (in kbps) */
    uint64_t                 nominal_throughput;
    uint64_t                 minimum_throughput;
    
    /* Maintenance window */
    char                    *maintenance_schedule;  /* Cron format + duration */
    
    /* Arbitrator */
    osiris_sla_arbitrator_t *arbitrator;
} osiris_service_level_t;

/* Resource definition for provisioning */
typedef struct osiris_resource_def {
    char                    *common_name;
    char                    *host;
    char                    *requested_userid;
    char                    *ssh_pubkey;
    
    /* Additional arbitrary properties stored as key-value pairs */
    char                   **property_keys;
    char                   **property_values;
    size_t                   property_count;
} osiris_resource_def_t;

/* Access request item */
typedef struct osiris_access_item {
    osiris_resource_type_t   type;
    uint32_t                 kind_flags;    /* Bitfield of osiris_access_kind_t */
    
    /* Resources (can be simple strings or complex definitions) */
    char                    *resources[OSIRIS_MAX_RESOURCES];
    osiris_resource_def_t   *resource_defs[OSIRIS_MAX_RESOURCES];
    size_t                   resource_count;
    bool                     resources_are_complex;
    
    /* Service levels */
    osiris_service_level_t  *service_levels[OSIRIS_MAX_SLA_ITEMS];
    size_t                   service_level_count;
    
    /* Penalties (correspond to service levels) */
    char                    *penalties[OSIRIS_MAX_SLA_ITEMS];
    
    /* Audience restriction (optional) */
    osiris_urn_t            *restricted_aud[OSIRIS_MAX_AUDIENCES];
    size_t                   restricted_aud_count;
    
    /* Provisioning scripts (opaque/encrypted) */
    char                    *pchk_script;   /* Preflight check */
    char                    *prov_script;   /* Provision */
    char                    *dprov_script;  /* Deprovision */
    char                    *grant_script;  /* Grant access */
    char                    *revoke_script; /* Revoke access */
    
    /* Expiration times */
    time_t                   pexp;          /* Provision expiration */
    time_t                   gexp;          /* Grant expiration */
} osiris_access_item_t;

/* Requested access structure */
typedef struct osiris_requested_access {
    osiris_access_item_t    *access[OSIRIS_MAX_ACCESS_ITEMS];
    size_t                   access_count;
    
    osiris_access_item_t    *provision[OSIRIS_MAX_ACCESS_ITEMS];
    size_t                   provision_count;
} osiris_requested_access_t;

/* Granted access item (includes credentials) */
typedef struct osiris_granted_access {
    osiris_resource_type_t   type;
    uint32_t                 kind_flags;
    char                    *credentials;   /* Encrypted credentials */
    char                    *resources[OSIRIS_MAX_RESOURCES];
    size_t                   resource_count;
    time_t                   iat;
    time_t                   exp;
    
    /* Service levels that were agreed upon */
    osiris_service_level_t  *service_levels[OSIRIS_MAX_SLA_ITEMS];
    size_t                   service_level_count;
    char                    *penalties[OSIRIS_MAX_SLA_ITEMS];
} osiris_granted_access_t;

/* Denied access item */
typedef struct osiris_denied_access {
    osiris_resource_type_t   type;
    uint32_t                 kind_flags;
    char                    *resource;
    char                    *reason;
} osiris_denied_access_t;

/* Provisioned access item */
typedef struct osiris_provisioned_access {
    osiris_resource_type_t   type;
    char                    *resource;
    time_t                   iat;
    time_t                   exp;
    
    osiris_service_level_t  *service_levels[OSIRIS_MAX_SLA_ITEMS];
    size_t                   service_level_count;
    char                    *penalties[OSIRIS_MAX_SLA_ITEMS];
    
    osiris_opaque_t         *opaque_data;   /* Deprovisioning info, etc. */
} osiris_provisioned_access_t;

/* Access item operations */
osiris_access_item_t *osiris_access_item_new(void);
void osiris_access_item_free(osiris_access_item_t *item);
int osiris_access_item_add_resource(osiris_access_item_t *item, 
                                    const char *resource);
int osiris_access_item_add_resource_def(osiris_access_item_t *item,
                                        osiris_resource_def_t *def);
void osiris_access_item_set_kind(osiris_access_item_t *item, 
                                 osiris_access_kind_t kind);
bool osiris_access_item_has_kind(const osiris_access_item_t *item,
                                 osiris_access_kind_t kind);

/* Service level operations */
osiris_service_level_t *osiris_service_level_new(void);
void osiris_service_level_free(osiris_service_level_t *sl);

/* Resource definition operations */
osiris_resource_def_t *osiris_resource_def_new(void);
void osiris_resource_def_free(osiris_resource_def_t *def);
int osiris_resource_def_set_property(osiris_resource_def_t *def,
                                     const char *key, const char *value);

/* Granted access operations */
osiris_granted_access_t *osiris_granted_access_new(void);
void osiris_granted_access_free(osiris_granted_access_t *access);

/* Denied access operations */
osiris_denied_access_t *osiris_denied_access_new(void);
void osiris_denied_access_free(osiris_denied_access_t *access);

/* Provisioned access operations */
osiris_provisioned_access_t *osiris_provisioned_access_new(void);
void osiris_provisioned_access_free(osiris_provisioned_access_t *access);

#endif /* OSIRIS_ACCESS_H */

osiris_tokens.h

#ifndef OSIRIS_TOKENS_H
#define OSIRIS_TOKENS_H

#include "osiris_types.h"
#include "osiris_common.h"
#include "osiris_crypto.h"
#include "osiris_access.h"

/* JWT-like header */
typedef struct osiris_token_header {
    osiris_token_type_t  typ;
    osiris_algorithm_t   alg;
    char                *kid;   /* Key ID (optional) */
} osiris_token_header_t;

/* Subject list */
typedef struct osiris_subjects {
    osiris_urn_t        *urns[OSIRIS_MAX_SUBJECTS];
    char                *emails[OSIRIS_MAX_SUBJECTS];  /* For plain email subjects */
    size_t               count;
} osiris_subjects_t;

/* Audience list */
typedef struct osiris_audiences {
    osiris_urn_t         urns[OSIRIS_MAX_AUDIENCES];
    size_t               count;
} osiris_audiences_t;

/*
 * OSiRIS Access Request (OAR)
 * Issued by Central Authority to Resource Providers
 */
typedef struct osiris_oar {
    /* Header */
    osiris_token_header_t        header;
    
    /* Standard JWT claims */
    osiris_urn_t                 iss;       /* Issuer */
    char                         jti[OSIRIS_UUID_LEN];  /* JWT ID */
    time_t                       iat;       /* Issued at */
    time_t                       exp;       /* Expiration */
    
    /* Subjects (users/groups requesting access) */
    osiris_subjects_t            sub;
    
    /* Audiences (resource providers) */
    osiris_audiences_t           aud;
    
    /* Session keys (encrypted for each audience) */
    osiris_encrypted_session_keys_t sk;
    
    /* Opaque data (encrypted with session key) */
    osiris_opaque_t             *opaque;
    
    /* Requested access */
    osiris_requested_access_t   *requested_access;
    
    /* Raw token parts for signature verification */
    char                        *raw_header;
    char                        *raw_payload;
    char                        *signature;
} osiris_oar_t;

/*
 * Granted/Denied/Provisioned access blocks in OAG
 */
typedef struct osiris_oag_granted {
    osiris_encrypted_session_keys_t  sk;
    osiris_granted_access_t         *access[OSIRIS_MAX_ACCESS_ITEMS];
    size_t                           access_count;
} osiris_oag_granted_t;

typedef struct osiris_oag_denied {
    osiris_encrypted_session_keys_t  sk;
    osiris_denied_access_t          *access[OSIRIS_MAX_ACCESS_ITEMS];
    size_t                           access_count;
} osiris_oag_denied_t;

typedef struct osiris_oag_provisioned {
    osiris_encrypted_session_keys_t  sk;
    osiris_provisioned_access_t     *access[OSIRIS_MAX_ACCESS_ITEMS];
    size_t                           access_count;
} osiris_oag_provisioned_t;

/*
 * OSiRIS Access Grant (OAG)
 * Issued by Resource Providers to Central Authority
 */
typedef struct osiris_oag {
    /* Header */
    osiris_token_header_t        header;
    
    /* Standard claims */
    osiris_urn_t                 iss;
    time_t                       iat;
    time_t                       exp;
    char                         jti[OSIRIS_UUID_LEN];
    char                         irt[OSIRIS_UUID_LEN];  /* In response to (OAR jti) */
    
    /* Subjects */
    osiris_subjects_t            sub;
    
    /* Audiences (CA and self) */
    osiris_audiences_t           aud;
    
    /* Time to accept */
    uint32_t                     tta;
    
    /* Session keys */
    osiris_encrypted_session_keys_t sk;
    
    /* Opaque data */
    osiris_opaque_t             *opaque;
    
    /* Access blocks */
    osiris_oag_granted_t        *granted;
    osiris_oag_denied_t         *denied;
    osiris_oag_provisioned_t    *provisioned;
    
    /* Raw token parts */
    char                        *raw_header;
    char                        *raw_payload;
    char                        *signature;
} osiris_oag_t;

/*
 * OSiRIS Access Assertion (OAA)
 * Stored by Central Authority, delivered to user agents
 */
typedef struct osiris_oaa {
    /* Header */
    osiris_token_header_t        header;
    
    /* Standard claims */
    osiris_urn_t                 iss;
    char                         jti[OSIRIS_UUID_LEN];
    char                         irt[OSIRIS_UUID_LEN];  /* In response to (OAG jti) */
    time_t                       iat;
    time_t                       exp;
    
    /* Subjects */
    osiris_subjects_t            sub;
    
    /* Audiences */
    osiris_audiences_t           aud;
    
    /* Embedded grants (base64url encoded signed OAGs) */
    char                        *grants[OSIRIS_MAX_GRANTS];
    size_t                       grants_count;
    
    /* Raw token parts */
    char                        *raw_header;
    char                        *raw_payload;
    char                        *signature;
} osiris_oaa_t;

/*
 * OSiRIS Access Token (OAT)
 * JWT-compatible token containing OAAs
 */
typedef struct osiris_oat {
    /* Header */
    osiris_token_header_t        header;
    
    /* Standard claims */
    osiris_urn_t                 iss;
    char                         jti[OSIRIS_UUID_LEN];
    time_t                       iat;
    time_t                       exp;
    
    /* Subjects */
    osiris_subjects_t            sub;
    
    /* Audiences */
    osiris_audiences_t           aud;
    
    /* Session keys */
    osiris_encrypted_session_keys_t sk;
    
    /* Embedded assertions (base64url encoded signed OAAs) */
    char                        *assertions[OSIRIS_MAX_ASSERTIONS];
    size_t                       assertions_count;
    
    /* Raw token parts */
    char                        *raw_header;
    char                        *raw_payload;
    char                        *signature;
} osiris_oat_t;

/*
 * OSiRIS Refresh Token (ORT)
 * Long-lived token for refreshing OATs
 */
typedef struct osiris_ort {
    /* Header */
    osiris_token_header_t        header;
    
    /* Standard claims */
    osiris_urn_t                 iss;
    char                         jti[OSIRIS_UUID_LEN];
    char                         irt[OSIRIS_UUID_LEN];  /* References the OAT */
    time_t                       iat;
    time_t                       exp;
    
    /* Subjects */
    osiris_subjects_t            sub;
    
    /* Audiences */
    osiris_audiences_t           aud;
    
    /* Session keys */
    osiris_encrypted_session_keys_t sk;
    
    /* The nested token structure: ORT contains OAT contains OAA contains OAG */
    osiris_oat_t                *embedded_oat;
    
    /* Raw token parts */
    char                        *raw_header;
    char                        *raw_payload;
    char                        *signature;
} osiris_ort_t;

/* Token header operations */
void osiris_token_header_init(osiris_token_header_t *header,
                              osiris_token_type_t typ,
                              osiris_algorithm_t alg);
char *osiris_token_header_to_json(const osiris_token_header_t *header);

/* Subject operations */
int osiris_subjects_add_email(osiris_subjects_t *sub, const char *email);
int osiris_subjects_add_urn(osiris_subjects_t *sub, const osiris_urn_t *urn);
void osiris_subjects_clear(osiris_subjects_t *sub);

/* Audience operations */
int osiris_audiences_add(osiris_audiences_t *aud, const osiris_urn_t *urn);
void osiris_audiences_clear(osiris_audiences_t *aud);
bool osiris_audiences_contains(const osiris_audiences_t *aud, 
                               const osiris_urn_t *urn);

/* OAR operations */
osiris_oar_t *osiris_oar_new(void);
void osiris_oar_free(osiris_oar_t *oar);
char *osiris_oar_to_json(const osiris_oar_t *oar);
osiris_oar_t *osiris_oar_from_json(const char *json);
char *osiris_oar_encode(const osiris_oar_t *oar, const osiris_jwk_t *signing_key);
osiris_oar_t *osiris_oar_decode(const char *encoded, const osiris_jwks_t *keys);
bool osiris_oar_verify(const osiris_oar_t *oar, const osiris_jwk_t *key);

/* OAG operations */
osiris_oag_t *osiris_oag_new(void);
void osiris_oag_free(osiris_oag_t *oag);
char *osiris_oag_to_json(const osiris_oag_t *oag);
osiris_oag_t *osiris_oag_from_json(const char *json);
char *osiris_oag_encode(const osiris_oag_t *oag, const osiris_jwk_t *signing_key);
osiris_oag_t *osiris_oag_decode(const char *encoded, const osiris_jwks_t *keys);
bool osiris_oag_verify(const osiris_oag_t *oag, const osiris_jwk_t *key);
bool osiris_oag_is_expired(const osiris_oag_t *oag);
bool osiris_oag_is_acceptable(const osiris_oag_t *oag);  /* Check TTA */

/* OAA operations */
osiris_oaa_t *osiris_oaa_new(void);
void osiris_oaa_free(osiris_oaa_t *oaa);
char *osiris_oaa_to_json(const osiris_oaa_t *oaa);
osiris_oaa_t *osiris_oaa_from_json(const char *json);
char *osiris_oaa_encode(const osiris_oaa_t *oaa, const osiris_jwk_t *signing_key);
osiris_oaa_t *osiris_oaa_decode(const char *encoded, const osiris_jwks_t *keys);
bool osiris_oaa_verify(const osiris_oaa_t *oaa, const osiris_jwk_t *key);
int osiris_oaa_add_grant(osiris_oaa_t *oaa, const char *encoded_oag);

/* OAT operations */
osiris_oat_t *osiris_oat_new(void);
void osiris_oat_free(osiris_oat_t *oat);
char *osiris_oat_to_json(const osiris_oat_t *oat);
osiris_oat_t *osiris_oat_from_json(const char *json);
char *osiris_oat_encode(const osiris_oat_t *oat, const osiris_jwk_t *signing_key);
osiris_oat_t *osiris_oat_decode(const char *encoded, const osiris_jwks_t *keys);
bool osiris_oat_verify(const osiris_oat_t *oat, const osiris_jwk_t *key);
int osiris_oat_add_assertion(osiris_oat_t *oat, const char *encoded_oaa);

/* ORT operations */
osiris_ort_t *osiris_ort_new(void);
void osiris_ort_free(osiris_ort_t *ort);
char *osiris_ort_encode(const osiris_ort_t *ort, const osiris_jwk_t *signing_key);
osiris_ort_t *osiris_ort_decode(const char *encoded, const osiris_jwks_t *keys);
bool osiris_ort_verify(const osiris_ort_t *ort, const osiris_jwk_t *key);

/* Token validation utilities */
bool osiris_token_is_expired(time_t exp);
time_t osiris_token_time_remaining(time_t exp);

#endif /* OSIRIS_TOKENS_H */

osiris_ldap.h

#ifndef OSIRIS_LDAP_H
#define OSIRIS_LDAP_H

#include "osiris_types.h"
#include "osiris_common.h"
#include "osiris_crypto.h"

/* LDAP OID constants from the schema */
#define OSIRIS_OID_BASE              "1.3.5.1.3.1.17128.313"
#define OSIRIS_OID_KEY_THUMBPRINT    OSIRIS_OID_BASE ".1.1"
#define OSIRIS_OID_ENTITY_UUID       OSIRIS_OID_BASE ".1.2"
#define OSIRIS_OID_OAK_ENDPOINT      OSIRIS_OID_BASE ".1.3"
#define OSIRIS_OID_STP_ENDPOINT      OSIRIS_OID_BASE ".1.4"
#define OSIRIS_OID_ENC_CERT          OSIRIS_OID_BASE ".1.5"
#define OSIRIS_OID_SIG_CERT          OSIRIS_OID_BASE ".1.6"
#define OSIRIS_OID_ACCESS_TOKENS     OSIRIS_OID_BASE ".1.7"
#define OSIRIS_OID_PREV_ENC_CERTS    OSIRIS_OID_BASE ".1.8"
#define OSIRIS_OID_PREV_SIG_CERTS    OSIRIS_OID_BASE ".1.9"

#define OSIRIS_OID_ENTITY_OC         OSIRIS_OID_BASE ".1"
#define OSIRIS_OID_RP_OC             OSIRIS_OID_BASE ".2"
#define OSIRIS_OID_CA_OC             OSIRIS_OID_BASE ".3"
#define OSIRIS_OID_GROUP_OC          OSIRIS_OID_BASE ".4"

/*
 * osirisEntity objectClass
 * Base class for all OSiRIS entities
 */
typedef struct osiris_ldap_entity {
    char                     *dn;               /* Distinguished name */
    char                      entity_uuid[OSIRIS_UUID_LEN];
    osiris_key_thumbprint_t  *key_thumbprint;   /* Optional */
    char                     *cn;               /* Common name (optional) */
    char                     *description;      /* Optional */
    
    /* Certificates (DER encoded, stored as binary) */
    osiris_buffer_t          *encryption_cert;
    osiris_buffer_t          *signing_cert;
} osiris_ldap_entity_t;

/*
 * osirisResourceProvider objectClass
 * Auxiliary class for resource providers
 */
typedef struct osiris_ldap_resource_provider {
    osiris_ldap_entity_t      base;
    char                      stp_endpoint[OSIRIS_URL_MAX_LEN];
    
    /* Previous certificates for key rotation */
    osiris_buffer_t         **prev_enc_certs;
    size_t                    prev_enc_certs_count;
    osiris_buffer_t         **prev_sig_certs;
    size_t                    prev_sig_certs_count;
} osiris_ldap_resource_provider_t;

/*
 * osirisCentralAuthority objectClass
 * Auxiliary class for central authorities
 */
typedef struct osiris_ldap_central_authority {
    osiris_ldap_entity_t      base;
    char                      oak_endpoint[OSIRIS_URL_MAX_LEN];
    
    /* Previous certificates for key rotation */
    osiris_buffer_t         **prev_enc_certs;
    size_t                    prev_enc_certs_count;
    osiris_buffer_t         **prev_sig_certs;
    size_t                    prev_sig_certs_count;
} osiris_ldap_central_authority_t;

/*
 * osirisGroup objectClass
 * Groups of osirisEntity objects
 */
typedef struct osiris_ldap_group {
    char                     *dn;
    char                      entity_uuid[OSIRIS_UUID_LEN];
    char                     *cn;
    char                     *description;
    
    /* Member DNs (from groupOfNames) */
    char                    **members;
    size_t                    member_count;
} osiris_ldap_group_t;

/*
 * User entry with access tokens
 */
typedef struct osiris_ldap_user {
    osiris_ldap_entity_t      base;
    
    /* Current access tokens */
    char                    **access_tokens;
    size_t                    access_tokens_count;
} osiris_ldap_user_t;

/* Entity operations */
osiris_ldap_entity_t *osiris_ldap_entity_new(void);
void osiris_ldap_entity_free(osiris_ldap_entity_t *entity);
int osiris_ldap_entity_set_uuid(osiris_ldap_entity_t *entity, const char *uuid);
int osiris_ldap_entity_generate_uuid(osiris_ldap_entity_t *entity);
int osiris_ldap_entity_set_encryption_cert(osiris_ldap_entity_t *entity,
                                           const uint8_t *der, size_t der_len);
int osiris_ldap_entity_set_signing_cert(osiris_ldap_entity_t *entity,
                                        const uint8_t *der, size_t der_len);
int osiris_ldap_entity_compute_thumbprint(osiris_ldap_entity_t *entity);

/* Resource Provider operations */
osiris_ldap_resource_provider_t *osiris_ldap_rp_new(void);
void osiris_ldap_rp_free(osiris_ldap_resource_provider_t *rp);
int osiris_ldap_rp_add_prev_enc_cert(osiris_ldap_resource_provider_t *rp,
                                     const uint8_t *der, size_t der_len);
int osiris_ldap_rp_add_prev_sig_cert(osiris_ldap_resource_provider_t *rp,
                                     const uint8_t *der, size_t der_len);

/* Central Authority operations */
osiris_ldap_central_authority_t *osiris_ldap_ca_new(void);
void osiris_ldap_ca_free(osiris_ldap_central_authority_t *ca);
int osiris_ldap_ca_add_prev_enc_cert(osiris_ldap_central_authority_t *ca,
                                     const uint8_t *der, size_t der_len);
int osiris_ldap_ca_add_prev_sig_cert(osiris_ldap_central_authority_t *ca,
                                     const uint8_t *der, size_t der_len);

/* Group operations */
osiris_ldap_group_t *osiris_ldap_group_new(void);
void osiris_ldap_group_free(osiris_ldap_group_t *group);
int osiris_ldap_group_add_member(osiris_ldap_group_t *group, const char *member_dn);
int osiris_ldap_group_remove_member(osiris_ldap_group_t *group, const char *member_dn);
bool osiris_ldap_group_is_member(const osiris_ldap_group_t *group, const char *member_dn);

/* User operations */
osiris_ldap_user_t *osiris_ldap_user_new(void);
void osiris_ldap_user_free(osiris_ldap_user_t *user);
int osiris_ldap_user_add_token(osiris_ldap_user_t *user, const char *token);
int osiris_ldap_user_remove_token(osiris_ldap_user_t *user, const char *token);
int osiris_ldap_user_clear_expired_tokens(osiris_ldap_user_t *user);

/* LDIF generation */
char *osiris_ldap_entity_to_ldif(const osiris_ldap_entity_t *entity);
char *osiris_ldap_rp_to_ldif(const osiris_ldap_resource_provider_t *rp);
char *osiris_ldap_ca_to_ldif(const osiris_ldap_central_authority_t *ca);
char *osiris_ldap_group_to_ldif(const osiris_ldap_group_t *group);

/* URN formatting helpers */
int osiris_format_entity_urn(char *buf, size_t buflen, const char *uuid);
int osiris_format_thumbprint_urn(char *buf, size_t buflen, 
                                 const osiris_key_thumbprint_t *thumbprint);

#endif /* OSIRIS_LDAP_H */

Implementation Files

osiris_common.c

#include "osiris_common.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/* Base64URL character set */
static const char b64url_table[] = 
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

static const int b64url_decode_table[256] = {
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,
    52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
    15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,63,
    -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
    41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
};

/*
 * Buffer operations
 */
osiris_buffer_t *osiris_buffer_new(size_t initial_capacity)
{
    osiris_buffer_t *buf = calloc(1, sizeof(osiris_buffer_t));
    if (!buf) return NULL;
    
    if (initial_capacity > 0) {
        buf->data = malloc(initial_capacity);
        if (!buf->data) {
            free(buf);
            return NULL;
        }
        buf->capacity = initial_capacity;
    }
    
    return buf;
}

void osiris_buffer_free(osiris_buffer_t *buf)
{
    if (!buf) return;
    free(buf->data);
    free(buf);
}

int osiris_buffer_resize(osiris_buffer_t *buf, size_t new_capacity)
{
    if (!buf) return -1;
    
    uint8_t *new_data = realloc(buf->data, new_capacity);
    if (!new_data && new_capacity > 0) return -1;
    
    buf->data = new_data;
    buf->capacity = new_capacity;
    if (buf->len > new_capacity) {
        buf->len = new_capacity;
    }
    
    return 0;
}

int osiris_buffer_append(osiris_buffer_t *buf, const uint8_t *data, size_t len)
{
    if (!buf || !data) return -1;
    
    size_t needed = buf->len + len;
    if (needed > buf->capacity) {
        size_t new_cap = buf->capacity * 2;
        if (new_cap < needed) new_cap = needed;
        if (osiris_buffer_resize(buf, new_cap) != 0) {
            return -1;
        }
    }
    
    memcpy(buf->data + buf->len, data, len);
    buf->len += len;
    
    return 0;
}

/*
 * String operations
 */
osiris_string_t *osiris_string_new(const char *initial)
{
    osiris_string_t *str = calloc(1, sizeof(osiris_string_t));
    if (!str) return NULL;
    
    if (initial) {
        str->len = strlen(initial);
        str->capacity = str->len + 1;
        str->data = malloc(str->capacity);
        if (!str->data) {
            free(str);
            return NULL;
        }
        memcpy(str->data, initial, str->len + 1);
    }
    
    return str;
}

void osiris_string_free(osiris_string_t *str)
{
    if (!str) return;
    free(str->data);
    free(str);
}

int osiris_string_append(osiris_string_t *str, const char *data)
{
    if (!str || !data) return -1;
    return osiris_string_append_n(str, data, strlen(data));
}

int osiris_string_append_n(osiris_string_t *str, const char *data, size_t len)
{
    if (!str || !data) return -1;
    
    size_t needed = str->len + len + 1;
    if (needed > str->capacity) {
        size_t new_cap = str->capacity * 2;
        if (new_cap < needed) new_cap = needed;
        char *new_data = realloc(str->data, new_cap);
        if (!new_data) return -1;
        str->data = new_data;
        str->capacity = new_cap;
    }
    
    memcpy(str->data + str->len, data, len);
    str->len += len;
    str->data[str->len] = '\0';
    
    return 0;
}

/*
 * URN operations
 */
int osiris_urn_parse(osiris_urn_t *urn, const char *urn_str)
{
    if (!urn || !urn_str) return -1;
    
    memset(urn, 0, sizeof(osiris_urn_t));
    
    size_t len = strlen(urn_str);
    if (len >= OSIRIS_URN_MAX_LEN) return -1;
    
    strncpy(urn->full, urn_str, OSIRIS_URN_MAX_LEN - 1);
    
    /* Parse "urn:nid:nss" format */
    char *p = urn->full;
    
    /* Scheme should be "urn" */
    urn->scheme = p;
    char *colon = strchr(p, ':');
    if (!colon) return -1;
    *colon = '\0';
    
    if (strcmp(urn->scheme, "urn") != 0) return -1;
    
    /* NID (namespace identifier) */
    urn->nid = colon + 1;
    colon = strchr(urn->nid, ':');
    if (!colon) return -1;
    *colon = '\0';
    
    /* NSS (namespace specific string) */
    urn->nss = colon + 1;
    
    return 0;
}

int osiris_urn_format_uuid(osiris_urn_t *urn, const char *uuid)
{
    if (!urn || !uuid) return -1;
    
    memset(urn, 0, sizeof(osiris_urn_t));
    
    int written = snprintf(urn->full, OSIRIS_URN_MAX_LEN, "urn:uuid:%s", uuid);
    if (written < 0 || written >= OSIRIS_URN_MAX_LEN) return -1;
    
    /* Re-parse to set up pointers */
    return osiris_urn_parse(urn, urn->full);
}

int osiris_urn_format_oid(osiris_urn_t *urn, const char *oid, const char *value)
{
    if (!urn || !oid) return -1;
    
    memset(urn, 0, sizeof(osiris_urn_t));
    
    int written;
    if (value) {
        written = snprintf(urn->full, OSIRIS_URN_MAX_LEN, 
                          "urn:oid:%s:%s", oid, value);
    } else {
        written = snprintf(urn->full, OSIRIS_URN_MAX_LEN, "urn:oid:%s", oid);
    }
    
    if (written < 0 || written >= OSIRIS_URN_MAX_LEN) return -1;
    
    /* Re-parse to set up pointers */
    return osiris_urn_parse(urn, urn->full);
}

bool osiris_urn_is_uuid(const osiris_urn_t *urn)
{
    if (!urn || !urn->nid) return false;
    return strcmp(urn->nid, "uuid") == 0;
}

bool osiris_urn_is_oid(const osiris_urn_t *urn)
{
    if (!urn || !urn->nid) return false;
    return strcmp(urn->nid, "oid") == 0;
}

/*
 * Base64URL encoding
 */
int osiris_base64url_encode(const uint8_t *input, size_t input_len,
                            char *output, size_t *output_len)
{
    if (!input || !output || !output_len) return -1;
    
    size_t needed = ((input_len + 2) / 3) * 4 + 1;
    if (*output_len < needed) {
        *output_len = needed;
        return -1;
    }
    
    size_t i, j;
    for (i = 0, j = 0; i < input_len; ) {
        uint32_t octet_a = i < input_len ? input[i++] : 0;
        uint32_t octet_b = i < input_len ? input[i++] : 0;
        uint32_t octet_c = i < input_len ? input[i++] : 0;
        
        uint32_t triple = (octet_a << 16) | (octet_b << 8) | octet_c;
        
        output[j++] = b64url_table[(triple >> 18) & 0x3F];
        output[j++] = b64url_table[(triple >> 12) & 0x3F];
        output[j++] = b64url_table[(triple >> 6) & 0x3F];
        output[j++] = b64url_table[triple & 0x3F];
    }
    
    /* Remove padding (base64url doesn't use padding) */
    size_t padding = (3 - (input_len % 3)) % 3;
    j -= padding;
    
    output[j] = '\0';
    *output_len = j;
    
    return 0;
}

int osiris_base64url_decode(const char *input, size_t input_len,
                            uint8_t *output, size_t *output_len)
{
    if (!input || !output || !output_len) return -1;
    
    /* Calculate output size */
    size_t needed = (input_len * 3) / 4;
    if (*output_len < needed) {
        *output_len = needed;
        return -1;
    }
    
    size_t i, j;
    for (i = 0, j = 0; i < input_len; ) {
        uint32_t sextet_a = b64url_decode_table[(uint8_t)input[i++]];
        uint32_t sextet_b = i < input_len ? 
                           b64url_decode_table[(uint8_t)input[i++]] : 0;
        uint32_t sextet_c = i < input_len ? 
                           b64url_decode_table[(uint8_t)input[i++]] : 0;
        uint32_t sextet_d = i < input_len ? 
                           b64url_decode_table[(uint8_t)input[i++]] : 0;
        
        if (sextet_a == (uint32_t)-1 || sextet_b == (uint32_t)-1 ||
            sextet_c == (uint32_t)-1 || sextet_d == (uint32_t)-1) {
            return -1;
        }
        
        uint32_t triple = (sextet_a << 18) | (sextet_b << 12) | 
                         (sextet_c << 6) | sextet_d;
        
        if (j < *output_len) output[j++] = (triple >> 16) & 0xFF;
        if (j < *output_len) output[j++] = (triple >> 8) & 0xFF;
        if (j < *output_len) output[j++] = triple & 0xFF;
    }
    
    /* Adjust for missing padding */
    size_t padding = (4 - (input_len % 4)) % 4;
    if (padding > 0 && padding < 3) {
        j -= padding;
    }
    
    *output_len = j;
    return 0;
}

/*
 * Utility functions
 */
const char *osiris_token_type_str(osiris_token_type_t type)
{
    switch (type) {
        case OSIRIS_TOKEN_OAR: return "OAR";
        case OSIRIS_TOKEN_OAG: return "OAG";
        case OSIRIS_TOKEN_OAA: return "OAA";
        case OSIRIS_TOKEN_OAT: return "JWT";
        case OSIRIS_TOKEN_ORT: return "JWT";
        default: return "UNKNOWN";
    }
}

const char *osiris_algorithm_str(osiris_algorithm_t alg)
{
    switch (alg) {
        case OSIRIS_ALG_RS256: return "RS256";
        case OSIRIS_ALG_RS384: return "RS384";
        case OSIRIS_ALG_RS512: return "RS512";
        case OSIRIS_ALG_ES256: return "ES256";
        case OSIRIS_ALG_ES384: return "ES384";
        case OSIRIS_ALG_ES512: return "ES512";
        default: return "UNKNOWN";
    }
}

const char *osiris_resource_type_str(osiris_resource_type_t type)
{
    switch (type) {
        case OSIRIS_RESOURCE_CEPHFS_MOUNT:  return "cephfs-mount";
        case OSIRIS_RESOURCE_SHELL_ACCOUNT: return "shell-account";
        case OSIRIS_RESOURCE_S3_BUCKET:     return "s3-bucket";
        case OSIRIS_RESOURCE_BLOCK_DEVICE:  return "block-device";
        default: return "unknown";
    }
}

osiris_tokens.c

#include "osiris_tokens.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>

/*
 * Token header operations
 */
void osiris_token_header_init(osiris_token_header_t *header,
                              osiris_token_type_t typ,
                              osiris_algorithm_t alg)
{
    if (!header) return;
    memset(header, 0, sizeof(osiris_token_header_t));
    header->typ = typ;
    header->alg = alg;
}

char *osiris_token_header_to_json(const osiris_token_header_t *header)
{
    if (!header) return NULL;
    
    char *json = malloc(256);
    if (!json) return NULL;
    
    const char *typ_str = osiris_token_type_str(header->typ);
    const char *alg_str = osiris_algorithm_str(header->alg);
    
    if (header->kid) {
        snprintf(json, 256, 
                "{\"typ\":\"%s\",\"alg\":\"%s\",\"kid\":\"%s\"}",
                typ_str, alg_str, header->kid);
    } else {
        snprintf(json, 256, 
                "{\"typ\":\"%s\",\"alg\":\"%s\"}",
                typ_str, alg_str);
    }
    
    return json;
}

/*
 * Subject operations
 */
int osiris_subjects_add_email(osiris_subjects_t *sub, const char *email)
{
    if (!sub || !email) return -1;
    if (sub->count >= OSIRIS_MAX_SUBJECTS) return -1;
    
    sub->emails[sub->count] = strdup(email);
    if (!sub->emails[sub->count]) return -1;
    
    sub->urns[sub->count] = NULL;
    sub->count++;
    
    return 0;
}

int osiris_subjects_add_urn(osiris_subjects_t *sub, const osiris_urn_t *urn)
{
    if (!sub || !urn) return -1;
    if (sub->count >= OSIRIS_MAX_SUBJECTS) return -1;
    
    sub->urns[sub->count] = malloc(sizeof(osiris_urn_t));
    if (!sub->urns[sub->count]) return -1;
    
    memcpy(sub->urns[sub->count], urn, sizeof(osiris_urn_t));
    sub->emails[sub->count] = NULL;
    sub->count++;
    
    return 0;
}

void osiris_subjects_clear(osiris_subjects_t *sub)
{
    if (!sub) return;
    
    for (size_t i = 0; i < sub->count; i++) {
        free(sub->urns[i]);
        free(sub->emails[i]);
    }
    memset(sub, 0, sizeof(osiris_subjects_t));
}

/*
 * Audience operations
 */
int osiris_audiences_add(osiris_audiences_t *aud, const osiris_urn_t *urn)
{
    if (!aud || !urn) return -1;
    if (aud->count >= OSIRIS_MAX_AUDIENCES) return -1;
    
    memcpy(&aud->urns[aud->count], urn, sizeof(osiris_urn_t));
    aud->count++;
    
    return 0;
}

void osiris_audiences_clear(osiris_audiences_t *aud)
{
    if (!aud) return;
    memset(aud, 0, sizeof(osiris_audiences_t));
}

bool osiris_audiences_contains(const osiris_audiences_t *aud, 
                               const osiris_urn_t *urn)
{
    if (!aud || !urn) return false;
    
    for (size_t i = 0; i < aud->count; i++) {
        if (strcmp(aud->urns[i].full, urn->full) == 0) {
            return true;
        }
    }
    return false;
}

/*
 * OAR operations
 */
osiris_oar_t *osiris_oar_new(void)
{
    osiris_oar_t *oar = calloc(1, sizeof(osiris_oar_t));
    if (!oar) return NULL;
    
    osiris_token_header_init(&oar->header, OSIRIS_TOKEN_OAR, OSIRIS_ALG_RS256);
    oar->iat = time(NULL);
    oar->exp = oar->iat + 30;  /* Default 30 second expiry for requests */
    
    return oar;
}

void osiris_oar_free(osiris_oar_t *oar)
{
    if (!oar) return;
    
    free(oar->header.kid);
    osiris_subjects_clear(&oar->sub);
    
    for (size_t i = 0; i < oar->sk.count; i++) {
        free(oar->sk.encrypted[i]);
    }
    
    osiris_opaque_free(oar->opaque);
    
    if (oar->requested_access) {
        for (size_t i = 0; i < oar->requested_access->access_count; i++) {
            osiris_access_item_free(oar->requested_access->access[i]);
        }
        for (size_t i = 0; i < oar->requested_access->provision_count; i++) {
            osiris_access_item_free(oar->requested_access->provision[i]);
        }
        free(oar->requested_access);
    }
    
    free(oar->raw_header);
    free(oar->raw_payload);
    free(oar->signature);
    
    free(oar);
}

/*
 * OAG operations
 */
osiris_oag_t *osiris_oag_new(void)
{
    osiris_oag_t *oag = calloc(1, sizeof(osiris_oag_t));
    if (!oag) return NULL;
    
    osiris_token_header_init(&oag->header, OSIRIS_TOKEN_OAG, OSIRIS_ALG_RS256);
    oag->iat = time(NULL);
    /* OAGs have longer expiry (months/years) */
    oag->exp = oag->iat + (86400 * 365);
    oag->tta = 1300;  /* Default 15+ minute acceptance window */
    
    return oag;
}

void osiris_oag_free(osiris_oag_t *oag)
{
    if (!oag) return;
    
    free(oag->header.kid);
    osiris_subjects_clear(&oag->sub);
    
    for (size_t i = 0; i < oag->sk.count; i++) {
        free(oag->sk.encrypted[i]);
    }
    
    osiris_opaque_free(oag->opaque);
    
    if (oag->granted) {
        for (size_t i = 0; i < oag->granted->access_count; i++) {
            osiris_granted_access_free(oag->granted->access[i]);
        }
        for (size_t i = 0; i < oag->granted->sk.count; i++) {
            free(oag->granted->sk.encrypted[i]);
        }
        free(oag->granted);
    }
    
    if (oag->denied) {
        for (size_t i = 0; i < oag->denied->access_count; i++) {
            osiris_denied_access_free(oag->denied->access[i]);
        }
        for (size_t i = 0; i < oag->denied->sk.count; i++) {
            free(oag->denied->sk.encrypted[i]);
        }
        free(oag->denied);
    }
    
    if (oag->provisioned) {
        for (size_t i = 0; i < oag->provisioned->access_count; i++) {
            osiris_provisioned_access_free(oag->provisioned->access[i]);
        }
        for (size_t i = 0; i < oag->provisioned->sk.count; i++) {
            free(oag->provisioned->sk.encrypted[i]);
        }
        free(oag->provisioned);
    }
    
    free(oag->raw_header);
    free(oag->raw_payload);
    free(oag->signature);
    
    free(oag);
}

bool osiris_oag_is_expired(const osiris_oag_t *oag)
{
    if (!oag) return true;
    return time(NULL) > oag->exp;
}

bool osiris_oag_is_acceptable(const osiris_oag_t *oag)
{
    if (!oag) return false;
    return time(NULL) <= (oag->iat + oag->tta);
}

/*
 * OAA operations
 */
osiris_oaa_t *osiris_oaa_new(void)
{
    osiris_oaa_t *oaa = calloc(1, sizeof(osiris_oaa_t));
    if (!oaa) return NULL;
    
    osiris_token_header_init(&oaa->header, OSIRIS_TOKEN_OAA, OSIRIS_ALG_RS256);
    oaa->iat = time(NULL);
    oaa->exp = oaa->iat + 30;
    
    return oaa;
}

void osiris_oaa_free(osiris_oaa_t *oaa)
{
    if (!oaa) return;
    
    free(oaa->header.kid);
    osiris_subjects_clear(&oaa->sub);
    
    for (size_t i = 0; i < oaa->grants_count; i++) {
        free(oaa->grants[i]);
    }
    
    free(oaa->raw_header);
    free(oaa->raw_payload);
    free(oaa->signature);
    
    free(oaa);
}

int osiris_oaa_add_grant(osiris_oaa_t *oaa, const char *encoded_oag)
{
    if (!oaa || !encoded_oag) return -1;
    if (oaa->grants_count >= OSIRIS_MAX_GRANTS) return -1;
    
    oaa->grants[oaa->grants_count] = strdup(encoded_oag);
    if (!oaa->grants[oaa->grants_count]) return -1;
    
    oaa->grants_count++;
    return 0;
}

/*
 * OAT operations
 */
osiris_oat_t *osiris_oat_new(void)
{
    osiris_oat_t *oat = calloc(1, sizeof(osiris_oat_t));
    if (!oat) return NULL;
    
    /* OAT uses JWT type for compatibility */
    osiris_token_header_init(&oat->header, OSIRIS_TOKEN_OAT, OSIRIS_ALG_RS256);
    oat->iat = time(NULL);
    /* Default expiry: 1 week */
    oat->exp = oat->iat + (86400 * 7);
    
    return oat;
}

void osiris_oat_free(osiris_oat_t *oat)
{
    if (!oat) return;
    
    free(oat->header.kid);
    osiris_subjects_clear(&oat->sub);
    
    for (size_t i = 0; i < oat->sk.count; i++) {
        free(oat->sk.encrypted[i]);
    }
    
    for (size_t i = 0; i < oat->assertions_count; i++) {
        free(oat->assertions[i]);
    }
    
    free(oat->raw_header);
    free(oat->raw_payload);
    free(oat->signature);
    
    free(oat);
}

int osiris_oat_add_assertion(osiris_oat_t *oat, const char *encoded_oaa)
{
    if (!oat || !encoded_oaa) return -1;
    if (oat->assertions_count >= OSIRIS_MAX_ASSERTIONS) return -1;
    
    oat->assertions[oat->assertions_count] = strdup(encoded_oaa);
    if (!oat->assertions[oat->assertions_count]) return -1;
    
    oat->assertions_count++;
    return 0;
}

/*
 * ORT operations
 */
osiris_ort_t *osiris_ort_new(void)
{
    osiris_ort_t *ort = calloc(1, sizeof(osiris_ort_t));
    if (!ort) return NULL;
    
    /* ORT uses JWT type for compatibility */
    osiris_token_header_init(&ort->header, OSIRIS_TOKEN_ORT, OSIRIS_ALG_RS256);
    ort->iat = time(NULL);
    /* Default expiry: 1 year */
    ort->exp = ort->iat + (86400 * 365);
    
    return ort;
}

void osiris_ort_free(osiris_ort_t *ort)
{
    if (!ort) return;
    
    free(ort->header.kid);
    osiris_subjects_clear(&ort->sub);
    
    for (size_t i = 0; i < ort->sk.count; i++) {
        free(ort->sk.encrypted[i]);
    }
    
    osiris_oat_free(ort->embedded_oat);
    
    free(ort->raw_header);
    free(ort->raw_payload);
    free(ort->signature);
    
    free(ort);
}

/*
 * Token validation utilities
 */
bool osiris_token_is_expired(time_t exp)
{
    return time(NULL) > exp;
}

time_t osiris_token_time_remaining(time_t exp)
{
    time_t now = time(NULL);
    if (now > exp) return 0;
    return exp - now;
}

osiris_access.c

#include "osiris_access.h"
#include <stdlib.h>
#include <string.h>

/*
 * Resource definition operations
 */
osiris_resource_def_t *osiris_resource_def_new(void)
{
    return calloc(1, sizeof(osiris_resource_def_t));
}

void osiris_resource_def_free(osiris_resource_def_t *def)
{
    if (!def) return;
    
    free(def->common_name);
    free(def->host);
    free(def->requested_userid);
    free(def->ssh_pubkey);
    
    for (size_t i = 0; i < def->property_count; i++) {
        free(def->property_keys[i]);
        free(def->property_values[i]);
    }
    free(def->property_keys);
    free(def->property_values);
    
    free(def);
}

int osiris_resource_def_set_property(osiris_resource_def_t *def,
                                     const char *key, const char *value)
{
    if (!def || !key || !value) return -1;
    
    /* Resize arrays */
    size_t new_count = def->property_count + 1;
    char **new_keys = realloc(def->property_keys, 
                              new_count * sizeof(char *));
    char **new_values = realloc(def->property_values, 
                                new_count * sizeof(char *));
    
    if (!new_keys || !new_values) {
        free(new_keys);
        free(new_values);
        return -1;
    }
    
    def->property_keys = new_keys;
    def->property_values = new_values;
    
    def->property_keys[def->property_count] = strdup(key);
    def->property_values[def->property_count] = strdup(value);
    
    if (!def->property_keys[def->property_count] || 
        !def->property_values[def->property_count]) {
        return -1;
    }
    
    def->property_count = new_count;
    return 0;
}

/*
 * Service level operations
 */
osiris_service_level_t *osiris_service_level_new(void)
{
    return calloc(1, sizeof(osiris_service_level_t));
}

void osiris_service_level_free(osiris_service_level_t *sl)
{
    if (!sl) return;
    
    free(sl->src_network);
    free(sl->dst_network);
    free(sl->maintenance_schedule);
    
    if (sl->arbitrator) {
        free(sl->arbitrator->src_ip);
        free(sl->arbitrator->ssh_pubkey);
        free(sl->arbitrator->exec_cmd);
        free(sl->arbitrator);
    }
    
    free(sl);
}

/*
 * Access item operations
 */
osiris_access_item_t *osiris_access_item_new(void)
{
    osiris_access_item_t *item = calloc(1, sizeof(osiris_access_item_t));
    if (!item) return NULL;
    
    item->pexp = -1;  /* No expiry by default */
    item->gexp = -1;
    
    return item;
}

void osiris_access_item_free(osiris_access_item_t *item)
{
    if (!item) return;
    
    for (size_t i = 0; i < item->resource_count; i++) {
        free(item->resources[i]);
        osiris_resource_def_free(item->resource_defs[i]);
    }
    
    for (size_t i = 0; i < item->service_level_count; i++) {
        osiris_service_level_free(item->service_levels[i]);
        free(item->penalties[i]);
    }
    
    for (size_t i = 0; i < item->restricted_aud_count; i++) {
        free(item->restricted_aud[i]);
    }
    
    free(item->pchk_script);
    free(item->prov_script);
    free(item->dprov_script);
    free(item->grant_script);
    free(item->revoke_script);
    
    free(item);
}

int osiris_access_item_add_resource(osiris_access_item_t *item, 
                                    const char *resource)
{
    if (!item || !resource) return -1;
    if (item->resource_count >= OSIRIS_MAX_RESOURCES) return -1;
    
    item->resources[item->resource_count] = strdup(resource);
    if (!item->resources[item->resource_count]) return -1;
    
    item->resource_defs[item->resource_count] = NULL;
    item->resource_count++;
    
    return 0;
}

int osiris_access_item_add_resource_def(osiris_access_item_t *item,
                                        osiris_resource_def_t *def)
{
    if (!item || !def) return -1;
    if (item->resource_count >= OSIRIS_MAX_RESOURCES) return -1;
    
    item->resource_defs[item->resource_count] = def;
    item->resources[item->resource_count] = NULL;
    item->resources_are_complex = true;
    item->resource_count++;
    
    return 0;
}

void osiris_access_item_set_kind(osiris_access_item_t *item, 
                                 osiris_access_kind_t kind)
{
    if (!item) return;
    item->kind_flags |= kind;
}

bool osiris_access_item_has_kind(const osiris_access_item_t *item,
                                 osiris_access_kind_t kind)
{
    if (!item) return false;
    return (item->kind_flags & kind) != 0;
}

/*
 * Granted access operations
 */
osiris_granted_access_t *osiris_granted_access_new(void)
{
    return calloc(1, sizeof(osiris_granted_access_t));
}

void osiris_granted_access_free(osiris_granted_access_t *access)
{
    if (!access) return;
    
    free(access->credentials);
    
    for (size_t i = 0; i < access->resource_count; i++) {
        free(access->resources[i]);
    }
    
    for (size_t i = 0; i < access->service_level_count; i++) {
        osiris_service_level_free(access->service_levels[i]);
        free(access->penalties[i]);
    }
    
    free(access);
}

/*
 * Denied access operations
 */
osiris_denied_access_t *osiris_denied_access_new(void)
{
    return calloc(1, sizeof(osiris_denied_access_t));
}

void osiris_denied_access_free(osiris_denied_access_t *access)
{
    if (!access) return;
    
    free(access->resource);
    free(access->reason);
    free(access);
}

/*
 * Provisioned access operations
 */
osiris_provisioned_access_t *osiris_provisioned_access_new(void)
{
    return calloc(1, sizeof(osiris_provisioned_access_t));
}

void osiris_provisioned_access_free(osiris_provisioned_access_t *access)
{
    if (!access) return;
    
    free(access->resource);
    
    for (size_t i = 0; i < access->service_level_count; i++) {
        osiris_service_level_free(access->service_levels[i]);
        free(access->penalties[i]);
    }
    
    osiris_opaque_free(access->opaque_data);
    free(access);
}

osiris_ldap.c

#include "osiris_ldap.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <uuid/uuid.h>

/*
 * Entity operations
 */
osiris_ldap_entity_t *osiris_ldap_entity_new(void)
{
    return calloc(1, sizeof(osiris_ldap_entity_t));
}

void osiris_ldap_entity_free(osiris_ldap_entity_t *entity)
{
    if (!entity) return;
    
    free(entity->dn);
    free(entity->key_thumbprint);
    free(entity->cn);
    free(entity->description);
    osiris_buffer_free(entity->encryption_cert);
    osiris_buffer_free(entity->signing_cert);
    
    free(entity);
}

int osiris_ldap_entity_set_uuid(osiris_ldap_entity_t *entity, const char *uuid)
{
    if (!entity || !uuid) return -1;
    if (strlen(uuid) >= OSIRIS_UUID_LEN) return -1;
    
    strncpy(entity->entity_uuid, uuid, OSIRIS_UUID_LEN - 1);
    entity->entity_uuid[OSIRIS_UUID_LEN - 1] = '\0';
    
    return 0;
}

int osiris_ldap_entity_generate_uuid(osiris_ldap_entity_t *entity)
{
    if (!entity) return -1;
    
    uuid_t uuid;
    uuid_generate(uuid);
    uuid_unparse_upper(uuid, entity->entity_uuid);
    
    return 0;
}

int osiris_ldap_entity_set_encryption_cert(osiris_ldap_entity_t *entity,
                                           const uint8_t *der, size_t der_len)
{
    if (!entity || !der) return -1;
    
    osiris_buffer_free(entity->encryption_cert);
    entity->encryption_cert = osiris_buffer_new(der_len);
    if (!entity->encryption_cert) return -1;
    
    return osiris_buffer_append(entity->encryption_cert, der, der_len);
}

int osiris_ldap_entity_set_signing_cert(osiris_ldap_entity_t *entity,
                                        const uint8_t *der, size_t der_len)
{
    if (!entity || !der) return -1;
    
    osiris_buffer_free(entity->signing_cert);
    entity->signing_cert = osiris_buffer_new(der_len);
    if (!entity->signing_cert) return -1;
    
    return osiris_buffer_append(entity->signing_cert, der, der_len);
}

/*
 * Resource Provider operations
 */
osiris_ldap_resource_provider_t *osiris_ldap_rp_new(void)
{
    return calloc(1, sizeof(osiris_ldap_resource_provider_t));
}

void osiris_ldap_rp_free(osiris_ldap_resource_provider_t *rp)
{
    if (!rp) return;
    
    /* Free base entity fields */
    free(rp->base.dn);
    free(rp->base.key_thumbprint);
    free(rp->base.cn);
    free(rp->base.description);
    osiris_buffer_free(rp->base.encryption_cert);
    osiris_buffer_free(rp->base.signing_cert);
    
    /* Free previous certificates */
    for (size_t i = 0; i < rp->prev_enc_certs_count; i++) {
        osiris_buffer_free(rp->prev_enc_certs[i]);
    }
    free(rp->prev_enc_certs);
    
    for (size_t i = 0; i < rp->prev_sig_certs_count; i++) {
        osiris_buffer_free(rp->prev_sig_certs[i]);
    }
    free(rp->prev_sig_certs);
    
    free(rp);
}

int osiris_ldap_rp_add_prev_enc_cert(osiris_ldap_resource_provider_t *rp,
                                     const uint8_t *der, size_t der_len)
{
    if (!rp || !der) return -1;
    
    osiris_buffer_t **new_certs = realloc(rp->prev_enc_certs,
        (rp->prev_enc_certs_count + 1) * sizeof(osiris_buffer_t *));
    if (!new_certs) return -1;
    
    rp->prev_enc_certs = new_certs;
    rp->prev_enc_certs[rp->prev_enc_certs_count] = osiris_buffer_new(der_len);
    if (!rp->prev_enc_certs[rp->prev_enc_certs_count]) return -1;
    
    osiris_buffer_append(rp->prev_enc_certs[rp->prev_enc_certs_count], 
                         der, der_len);
    rp->prev_enc_certs_count++;
    
    return 0;
}

/*
 * Central Authority operations
 */
osiris_ldap_central_authority_t *osiris_ldap_ca_new(void)
{
    return calloc(1, sizeof(osiris_ldap_central_authority_t));
}

void osiris_ldap_ca_free(osiris_ldap_central_authority_t *ca)
{
    if (!ca) return;
    
    /* Free base entity fields */
    free(ca->base.dn);
    free(ca->base.key_thumbprint);
    free(ca->base.cn);
    free(ca->base.description);
    osiris_buffer_free(ca->base.encryption_cert);
    osiris_buffer_free(ca->base.signing_cert);
    
    /* Free previous certificates */
    for (size_t i = 0; i < ca->prev_enc_certs_count; i++) {
        osiris_buffer_free(ca->prev_enc_certs[i]);
    }
    free(ca->prev_enc_certs);
    
    for (size_t i = 0; i < ca->prev_sig_certs_count; i++) {
        osiris_buffer_free(ca->prev_sig_certs[i]);
    }
    free(ca->prev_sig_certs);
    
    free(ca);
}

/*
 * Group operations
 */
osiris_ldap_group_t *osiris_ldap_group_new(void)
{
    return calloc(1, sizeof(osiris_ldap_group_t));
}

void osiris_ldap_group_free(osiris_ldap_group_t *group)
{
    if (!group) return;
    
    free(group->dn);
    free(group->cn);
    free(group->description);
    
    for (size_t i = 0; i < group->member_count; i++) {
        free(group->members[i]);
    }
    free(group->members);
    
    free(group);
}

int osiris_ldap_group_add_member(osiris_ldap_group_t *group, 
                                 const char *member_dn)
{
    if (!group || !member_dn) return -1;
    
    char **new_members = realloc(group->members,
        (group->member_count + 1) * sizeof(char *));
    if (!new_members) return -1;
    
    group->members = new_members;
    group->members[group->member_count] = strdup(member_dn);
    if (!group->members[group->member_count]) return -1;
    
    group->member_count++;
    return 0;
}

int osiris_ldap_group_remove_member(osiris_ldap_group_t *group, 
                                    const char *member_dn)
{
    if (!group || !member_dn) return -1;
    
    for (size_t i = 0; i < group->member_count; i++) {
        if (strcmp(group->members[i], member_dn) == 0) {
            free(group->members[i]);
            
            /* Shift remaining members */
            for (size_t j = i; j < group->member_count - 1; j++) {
                group->members[j] = group->members[j + 1];
            }
            group->member_count--;
            return 0;
        }
    }
    
    return -1;  /* Not found */
}

bool osiris_ldap_group_is_member(const osiris_ldap_group_t *group, 
                                 const char *member_dn)
{
    if (!group || !member_dn) return false;
    
    for (size_t i = 0; i < group->member_count; i++) {
        if (strcmp(group->members[i], member_dn) == 0) {
            return true;
        }
    }
    return false;
}

/*
 * User operations
 */
osiris_ldap_user_t *osiris_ldap_user_new(void)
{
    return calloc(1, sizeof(osiris_ldap_user_t));
}

void osiris_ldap_user_free(osiris_ldap_user_t *user)
{
    if (!user) return;
    
    /* Free base entity */
    free(user->base.dn);
    free(user->base.key_thumbprint);
    free(user->base.cn);
    free(user->base.description);
    osiris_buffer_free(user->base.encryption_cert);
    osiris_buffer_free(user->base.signing_cert);
    
    /* Free tokens */
    for (size_t i = 0; i < user->access_tokens_count; i++) {
        free(user->access_tokens[i]);
    }
    free(user->access_tokens);
    
    free(user);
}

int osiris_ldap_user_add_token(osiris_ldap_user_t *user, const char *token)
{
    if (!user || !token) return -1;
    
    char **new_tokens = realloc(user->access_tokens,
        (user->access_tokens_count + 1) * sizeof(char *));
    if (!new_tokens) return -1;
    
    user->access_tokens = new_tokens;
    user->access_tokens[user->access_tokens_count] = strdup(token);
    if (!user->access_tokens[user->access_tokens_count]) return -1;
    
    user->access_tokens_count++;
    return 0;
}

/*
 * URN formatting helpers
 */
int osiris_format_entity_urn(char *buf, size_t buflen, const char *uuid)
{
    if (!buf || !uuid) return -1;
    
    int written = snprintf(buf, buflen, 
                          "urn:oid:" OSIRIS_OID_ENTITY_UUID ":%s", uuid);
    
    if (written < 0 || (size_t)written >= buflen) return -1;
    return 0;
}

int osiris_format_thumbprint_urn(char *buf, size_t buflen, 
                                 const osiris_key_thumbprint_t *thumbprint)
{
    if (!buf || !thumbprint) return -1;
    
    int written = snprintf(buf, buflen, 
                          "urn:oid:" OSIRIS_OID_KEY_THUMBPRINT ":%s", 
                          thumbprint->base64url);
    
    if (written < 0 || (size_t)written >= buflen) return -1;
    return 0;
}

/*
 * LDIF generation
 */
char *osiris_ldap_entity_to_ldif(const osiris_ldap_entity_t *entity)
{
    if (!entity || !entity->dn) return NULL;
    
    osiris_string_t *ldif = osiris_string_new("");
    if (!ldif) return NULL;
    
    /* DN */
    osiris_string_append(ldif, "dn: ");
    osiris_string_append(ldif, entity->dn);
    osiris_string_append(ldif, "\n");
    
    /* Object class */
    osiris_string_append(ldif, "objectClass: osirisEntity\n");
    
    /* Required: osirisEntityUniqueID */
    osiris_string_append(ldif, "osirisEntityUniqueID: ");
    osiris_string_append(ldif, entity->entity_uuid);
    osiris_string_append(ldif, "\n");
    
    /* Optional: cn */
    if (entity->cn) {
        osiris_string_append(ldif, "cn: ");
        osiris_string_append(ldif, entity->cn);
        osiris_string_append(ldif, "\n");
    }
    
    /* Optional: description */
    if (entity->description) {
        osiris_string_append(ldif, "description: ");
        osiris_string_append(ldif, entity->description);
        osiris_string_append(ldif, "\n");
    }
    
    /* Optional: osirisKeyThumbprint */
    if (entity->key_thumbprint) {
        osiris_string_append(ldif, "osirisKeyThumbprint: ");
        osiris_string_append(ldif, entity->key_thumbprint->base64url);
        osiris_string_append(ldif, "\n");
    }
    
    /* Certificates would need base64 encoding for LDIF */
    /* ... */
    
    osiris_string_append(ldif, "\n");
    
    char *result = strdup(ldif->data);
    osiris_string_free(ldif);
    
    return result;
}

Example Usage

#include "osiris_tokens.h"
#include "osiris_access.h"
#include "osiris_ldap.h"
#include <stdio.h>

int main(void)
{
    /* Create a new Access Request */
    osiris_oar_t *oar = osiris_oar_new();
    if (!oar) {
        fprintf(stderr, "Failed to create OAR\n");
        return 1;
    }
    
    /* Set issuer (Central Authority) */
    osiris_urn_format_uuid(&oar->iss, "58F1C380-FC8F-4D1E-8C5B-0FC32F81087D");
    
    /* Add subjects */
    osiris_subjects_add_email(&oar->sub, "ak1520@wayne.edu");
    
    osiris_urn_t group_urn;
    osiris_urn_format_oid(&group_urn, OSIRIS_OID_ENTITY_UUID,
                          "85B68BF3-2343-42FF-A0C4-C10E1C3CA868");
    osiris_subjects_add_urn(&oar->sub, &group_urn);
    
    /* Add audiences (Resource Providers) */
    osiris_urn_t rp_urn;
    osiris_urn_format_uuid(&rp_urn, "6D522874-F79E-4577-8EFF-414CF6895065");
    osiris_audiences_add(&oar->aud, &rp_urn);
    
    /* Create access request */
    oar->requested_access = calloc(1, sizeof(osiris_requested_access_t));
    
    /* Request read access to CephFS mount */
    osiris_access_item_t *ceph_access = osiris_access_item_new();
    ceph_access->type = OSIRIS_RESOURCE_CEPHFS_MOUNT;
    osiris_access_item_set_kind(ceph_access, OSIRIS_ACCESS_READ);
    osiris_access_item_add_resource(ceph_access, "science1:/some/science");
    osiris_access_item_add_resource(ceph_access, "sci45:/more/science");
    
    oar->requested_access->access[0] = ceph_access;
    oar->requested_access->access_count = 1;
    
    /* Request shell account provisioning */
    osiris_access_item_t *shell_provision = osiris_access_item_new();
    shell_provision->type = OSIRIS_RESOURCE_SHELL_ACCOUNT;
    osiris_access_item_set_kind(shell_provision, OSIRIS_ACCESS_LOGIN);
    osiris_access_item_set_kind(shell_provision, OSIRIS_ACCESS_SUDO);
    
    osiris_resource_def_t *shell_def = osiris_resource_def_new();
    shell_def->common_name = strdup("ssh://ak1520@shells.archimedes.gr");
    shell_def->host = strdup("shells.archimedes.gr");
    shell_def->requested_userid = strdup("ak1520");
    shell_def->ssh_pubkey = strdup(
        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB3+iRTnUqdbCgiXY3rbVbVXR1r1"
        "RbZE/z3Pfxb6M/qz ak1520@example.edu");
    
    osiris_access_item_add_resource_def(shell_provision, shell_def);
    
    oar->requested_access->provision[0] = shell_provision;
    oar->requested_access->provision_count = 1;
    
    printf("Created OAR with:\n");
    printf("  Issuer: %s\n", oar->iss.full);
    printf("  Subjects: %zu\n", oar->sub.count);
    printf("  Audiences: %zu\n", oar->aud.count);
    printf("  Access requests: %zu\n", oar->requested_access->access_count);
    printf("  Provision requests: %zu\n", 
           oar->requested_access->provision_count);
    
    /* Create an LDAP entity */
    osiris_ldap_resource_provider_t *rp = osiris_ldap_rp_new();
    osiris_ldap_entity_generate_uuid(&rp->base);
    rp->base.cn = strdup("WSU STPd");
    strncpy(rp->stp_endpoint, 
            "https://stpd-01.wsu.osris.org:8181/oar/",
            OSIRIS_URL_MAX_LEN - 1);
    
    printf("\nCreated Resource Provider:\n");
    printf("  UUID: %s\n", rp->base.entity_uuid);
    printf("  CN: %s\n", rp->base.cn);
    printf("  STP Endpoint: %s\n", rp->stp_endpoint);
    
    /* Cleanup */
    osiris_oar_free(oar);
    osiris_ldap_rp_free(rp);
    
    printf("\nAll structures cleaned up successfully.\n");
    
    return 0;
}

These implementations provide the core data structures for the OSiRIS Access Assertions system. The code includes memory management with proper allocation and deallocation, type-safe enumerations for token types and access kinds, and a layered architecture that mirrors the document's token hierarchy (OAR → OAG → OAA → OAT/ORT).