/* C11. Both sides as a fail-closed, transport-free callback scaffold. * All callbacks below must be implemented; begin_verified verifies signatures, * context, current authority, freshness and state under one transaction lock. * close rolls back unless commit_once succeeded. Callback messages are caller- * allocated; their storage/ownership remains with the adapter. See README.md. */ #include #include typedef enum { REGISTER, USE, REVOKE, RETRACT } bp_op; typedef struct { const char *const *fields; size_t count; const char *signature; } bp_message; typedef struct bp_tx bp_tx; struct bp_tx { void *state; bp_op op; const bp_message *(*cached)(bp_tx *); int (*register_key)(bp_tx *); int (*require_entitlement)(bp_tx *); int (*revoke_target)(bp_tx *); int (*retract_relation)(bp_tx *); int (*sign_result)(bp_tx *, bp_message *); int (*commit_once)(bp_tx *,const bp_message *); void (*close)(bp_tx *); }; typedef struct { void *state; int (*challenge)(void *,bp_op,const char *,const char *,const char *,bp_message *); int (*verify_provider_and_approve)(void *,const bp_message *); int (*sign_proof)(void *,const bp_message *,bp_message *); int (*verify_result_and_apply)(void *,const bp_message *); int (*begin_verified)(void *,const bp_message *,const char *,bp_tx **); int (*recover_revoke)(void *,const char *,const char *,const char *,bp_message *); } bp_ports; int bp_token_respond(bp_ports *p,const bp_message *q,bp_message *proof) { if (!p||!q||!proof||!p->verify_provider_and_approve||!p->sign_proof) return -1; if (p->verify_provider_and_approve(p->state,q)) return -1; return p->sign_proof(p->state,q,proof); } int bp_token_accept(bp_ports *p,const bp_message *result) { if (!p||!result||!p->verify_result_and_apply) return -1; return p->verify_result_and_apply(p->state,result); } int bp_provider_start(bp_ports *p,bp_op op,const char *rid,const char *target, const char *context,bp_message *out) { if (!p||!p->challenge||!rid||!target||!context||!out) return -1; return p->challenge(p->state,op,rid,target,context,out); } int bp_provider_finish(bp_ports *p,const bp_message *proof,const char *context, bp_message *result,bool *fresh) { bp_tx *tx=NULL; const bp_message *old; int rc=-1; if (!p||!proof||!context||!result||!fresh||!p->begin_verified) return -1; *fresh=false; if (p->begin_verified(p->state,proof,context,&tx)||!tx) return -1; if (!tx->close) return -1; /* Invalid adapter: callbacks must be installed together. */ if (!tx->cached||!tx->sign_result||!tx->commit_once) goto done; old=tx->cached(tx); if(old){*result=*old; rc=0; goto done;} switch(tx->op){ case REGISTER: if(tx->register_key) rc=tx->register_key(tx); break; case USE: if(tx->require_entitlement) rc=tx->require_entitlement(tx); break; case REVOKE: if(tx->revoke_target) rc=tx->revoke_target(tx); break; case RETRACT: if(tx->retract_relation) rc=tx->retract_relation(tx); break; default: rc=-1; } if(rc||tx->sign_result(tx,result)){rc=-1;goto done;} rc=tx->commit_once(tx,result); if(!rc)*fresh=true; done: tx->close(tx); return rc; } int bp_provider_lost(bp_ports *p,const char *rid,const char *target, const char *context,bp_message *out) { if(!p||!p->recover_revoke||!rid||!target||!context||!out)return -1; return p->recover_revoke(p->state,rid,target,context,out); } const char *bp_legacy_value(const char *value,bool approved,bool selected) { return approved&&selected&&value&&value[0]?value:NULL; /* Returned bytes are for the agreed renderer/driver, NOT a new reader command. */ }