Xoxa-c  0.3.1
Normalizer/Parser for XML
 All Data Structures Files Functions Variables Typedefs Enumerations Pages
Data Structures | Typedefs | Enumerations | Functions
xoxa.h File Reference

The interface to the Xoxa library. More...

#include <stdlib.h>
#include <stdint.h>
#include <sys/select.h>
#include <stdio.h>
#include <setjmp.h>
#include <expat.h>
Include dependency graph for xoxa.h:

Go to the source code of this file.

Data Structures

struct  gpg_result_s
 The SignatureDetail structure represents the results of a PGP verification action. More...
 
struct  ParserState_s
 The Xoxa parser state structure. More...
 

Typedefs

typedef void(* output_callback_end_t )(ParserState *, void *data)
 The type of the Xoxa callback finaliser.
 
typedef void(* output_callback_t )(const byte *bytes, size_t len, void *data)
 The type of the Xoxa callback.
 
typedef uint8_t ParserFlags
 Various flags which control the parser.
 
typedef struct ParserState_s ParserState
 The structure which contains all of the state of the Xoxa parser.
 
typedef struct gpg_result_s SignatureDetail
 The SignatureDetail structure represents the results of a PGP verification action.
 

Enumerations

enum  GPGResult
 The possible results of a PGP verification action.
 

Functions

void gpg_signature_free (SignatureDetail *)
 Free SignatureDetail contents (note, we do not assume here that the SignatureDetails object itself is malloced, so we do not free it).
 
void xoxa_default_callback (const byte *buf, size_t len, void *data)
 The 'default' callback receives a line of ESIS output and writes it to stdout.
 
int xoxa_digest_initialize (ParserState *parser, const char *digest_name)
 Initialise the parser for calculating a message digest of the content.
 
int xoxa_digest_is_initialized (ParserState *parser)
 Tests whether a digest has been initialized.
 
const char * xoxa_digest_library_ident (void)
 Returns some identification of the library providing the digest services.
 
const char * xoxa_error_message (ParserState *)
 Retrieve any error message which has been collected during a parse.
 
byte * xoxa_get_digest (ParserState *, size_t *)
 Retrieve a message digest from the parser, after a parse has completed.
 
SignatureDetailxoxa_get_signature (ParserState *P)
 Retrieve a PGP signature from the parser.
 
InputSource * xoxa_new_input_source_from_fd (const int fd)
 Creates an InputSource from the named file descriptor.
 
InputSource * xoxa_new_input_source_from_filename (const char *filename)
 Creates an InputSource from the named file.
 
InputSource * xoxa_new_input_source_from_string (const char *xmlcontent)
 Creates an InputSource from the given content, which should be an string containing XML.
 
ParserStatexoxa_new_parser (InputSource *)
 Returns a freshly-initialised parser.
 
void xoxa_null_callback (const byte *buf, size_t len, void *data)
 The 'null' callback receives a line of ESIS output and discards it.
 
int xoxa_parse (ParserState *)
 Parse the input, using the configured parser.
 
int xoxa_parse_for_digest (ParserState *parser, const char *digest_name)
 Parses the content of the input configured into the given parser.
 
SignatureDetailxoxa_parse_for_pgp_verify (ParserState *PS)
 Given a configured parser, ready to start parsing, verify the PGP signature which we expect to find within the XML file.
 
void xoxa_parser_flags (ParserState *, ParserFlags)
 Sets parser flags.
 
const char * xoxa_parser_library_ident (void)
 Returns the version string of the underlying Expat library.
 
int xoxa_pgp_verify_initialize (ParserState *PS)
 Initialise a parser to verify a PGP signature.
 
int xoxa_push_output_callback (ParserState *P, output_callback_t cb, void *data, const char *label)
 Push a callback onto the callback stack.
 
void xoxa_register_output_callback_finalizer (ParserState *P, output_callback_end_t cb_end)
 Register a finaliser to be called when the top callback on the stack is popped.
 
void xoxa_release_parser (ParserState *)
 Releases the parser and the contained input source.
 
void xoxa_signature_fd (ParserState *, int)
 Specify the file-descriptor to which the library should write a signature block.
 

Detailed Description

The interface to the Xoxa library.

This library supports a normalizing transformation on XML files, which makes them suitable for cryptographic signing. Partly as an example of its use, it also includes support for generating and displaying the cryptographic digest of such a normalized version of the XML file.

For more details, see ... [paper to come].

Using the Library

To use the library, create an InputSource from an XML file, and create a parser using this. When the file is subsequently parsed, each line of the normalized result is be fed to a single callback function. The default callback action is to print this line to the standard output.

For example:

    #include <xoxa.h>
    // Callback: we simply write out the normalized block
    // (this is the default action).
    void output_callback(const byte* bytes, size_t len, void* data)
    {
        FILE* o = (FILE*)data;
        if (len == 0) {
            const byte* p;
            for (p=bytes; *p!=0; p++) {
                // nothing
            }
            fwrite(bytes, sizeof(byte), p-bytes, o);
        } else {
            fwrite(bytes, sizeof(byte), len, o);
        }
    }
    int main(int argc, char** argv)
    {
        InputSource* src;
        ParserState* parser;
        if (argc != 2) {
            fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
            exit(1);
        }
        src = xoxa_new_input_source_from_filename(argv[1]);
        parser = xoxa_new_parser(src);
        xoxa_register_output_callback(parser, output_callback, (void*)stdout);
        xoxa_parse(parser);
        xoxa_release_parser(parser);
    }

Alternatively, the input can be parsed to provide a message digest of the normalized input:

#include <xoxa.h>

int main(int argc, char** argv)
{
    InputSource* src;
    ParserState* parser;
    unsigned char* digest;
    unsigned int digest_len;
    unsigned int i;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        exit(1);
    }

    src = xoxa_new_input_source_from_filename(argv[1]);
    parser = xoxa_new_parser(src);
    digest = xoxa_parse_for_digest(parser, "SHA1", &digest_len);
    printf("Digest:");
    for (i=0; i<digest_len; i++) {
        printf(" %02x", digest[i]);
    }
    printf("\n");
    xoxa_release_parser(parser);
}

Wrapping Expat

The library also provides a set of functions Xoxa_... which precisely mirror the XML_... functions of the Expat library, and which can be used in an analogous way. See the documentation for Xoxa_ParserCreate() and friends.

See Also
xoxa_expat.h

Typedef Documentation

typedef void(* output_callback_end_t)(ParserState *, void *data)

The type of the Xoxa callback finaliser.

The callback takes two arguments:

  • 'bytes' is the array of bytes to process.
  • 'data' is the pointer registered when the callback is registered with xoxa_register_output_callback.
typedef void(* output_callback_t)(const byte *bytes, size_t len, void *data)

The type of the Xoxa callback.

The callback takes three arguments:

  • 'bytes' is the array of bytes to process.
  • 'len' is the number of bytes in this array to process; len may be passed as zero, indicating that the byte array is null-terminated.
  • 'data' is the pointer registered when the callback is registered with xoxa_push_output_callback.
typedef uint8_t ParserFlags

Various flags which control the parser.

The flags are:

  • XOXA_REPORT_ALL : do not normalize the output
  • XOXA_QUIET : be quiet – not verbose
  • XOXA_FEEDBACK : 'normal' feedback
  • XOXA_CHATTER : output more extensive tracing information
typedef struct gpg_result_s SignatureDetail

The SignatureDetail structure represents the results of a PGP verification action.

If the status is good_sig or bad_sig, then there are further details available in the corresponding elements of the detail union.

Function Documentation

void gpg_signature_free ( SignatureDetail details)

Free SignatureDetail contents (note, we do not assume here that the SignatureDetails object itself is malloced, so we do not free it).

Parameters
detailsa pointer to a struct which may have been returned as part of a signature verification process
void xoxa_default_callback ( const byte *  buf,
size_t  len,
void *  data 
)

The 'default' callback receives a line of ESIS output and writes it to stdout.

If 'len' is zero, then the buf is null-terminated; if not, then it gives the number of bytes to be written out.

Parameters
bufthe buffer of output data
lenthe length of the buffer
datathe user-supplied data blob
int xoxa_digest_initialize ( ParserState parser,
const char *  digest_name 
)

Initialise the parser for calculating a message digest of the content.

The function returns a pointer which must be passed to xoxa_digest_finalize after the parse is complete: this frees memory, and so must be called whether or not the parse was successful.

The list of available digests depends somewhat on the compilation context, but should include for example "SHA1".

The value void* parser->digest_ctx is available to be set to a digest context object.

Parameters
parserthe Xoxa parser
digest_namethe name of a digest algorithm
Returns
zero on success, or non-zero on error (possibly with an error message in the parser
int xoxa_digest_is_initialized ( ParserState parser)

Tests whether a digest has been initialized.

Parameters
parserthe parser state
Returns
non-zero (true) if a digest has been initialised
const char* xoxa_digest_library_ident ( void  )

Returns some identification of the library providing the digest services.

The returned string should not be freed.

const char* xoxa_error_message ( ParserState P)

Retrieve any error message which has been collected during a parse.

This string is owned by the parser, and must not be freed by the caller.

Parameters
Pa parser, which has been used to parse an input source
byte* xoxa_get_digest ( ParserState P,
size_t *  lenp 
)

Retrieve a message digest from the parser, after a parse has completed.

If the parsed document did not contain a digest, this returns NULL (that is, it is not an error to call both this and xoxa_get_signature to detect which structures are available).

The resulting byte array is owned by the ParserState, and should not be freed by the caller.

Parameters
Pa configured parser, after a parse has completed successfully
lenpif non-NULL, this points to a location which is filled in with the length of the digest in bytes
Returns
a pointer to the message digest, or NULL if P is NULL or if no digest is available
See Also
xoxa_get_signature
SignatureDetail* xoxa_get_signature ( ParserState P)

Retrieve a PGP signature from the parser.

If the parsed document did not contain a signature, this returns NULL (that is, it is not an error to call both this and xoxa_get_digest to detect which structures are available).

The returned struct is owned by the parser struct, and should not be freed by the caller.

Parameters
Pa configured parser, after a parser has completed successfully
Returns
a pointer to a SignatureDetail struct, or NULL if P is NULL or if no signature is available
See Also
xoxa_get_digest
InputSource* xoxa_new_input_source_from_fd ( const int  fd)

Creates an InputSource from the named file descriptor.

The InputSource should be handed to a xoxa_new_parser function, which will free it when necessary. Returns NULL if there's any problem. (in fact, the only problem is memory exhaustion, which causes an immediate exit)

Parameters
fdthe identifier of the file descriptor which is to be read in
Returns
a new InputSource
InputSource* xoxa_new_input_source_from_filename ( const char *  filename)

Creates an InputSource from the named file.

The InputSource should be handed to a xoxa_new_parser function, which will free it when necessary. Returns NULL if there's any problem. (in fact, the only problem is memory exhaustion, which causes an immediate exit)

Parameters
filenamethe file which is to be read in
Returns
a new InputSource
InputSource* xoxa_new_input_source_from_string ( const char *  xmlcontent)

Creates an InputSource from the given content, which should be an string containing XML.

This string is not copied, so should not be freed during a parse. The InputSource should be handed to a xoxa_new_parser function, which will free it when necessary. Returns NULL if there's any problem. (in fact, the only problem is memory exhaustion, which causes an immediate exit)

Parameters
xmlcontentthe string which is to be read in
Returns
a new InputSource
ParserState* xoxa_new_parser ( InputSource *  src)

Returns a freshly-initialised parser.

After this call, the InputSource object is owned by the Parser, and will be released in xoxa_release_parser.

If there is an error, print a message to stderr and return NULL.

Parameters
srcan initialised InputSource object, which must not be NULL
Returns
a fresh parser
void xoxa_null_callback ( const byte *  buf,
size_t  len,
void *  data 
)

The 'null' callback receives a line of ESIS output and discards it.

Parameters
bufthe buffer of output data
lenthe length of the buffer
datathe user-supplied data blob
int xoxa_parse ( ParserState P)

Parse the input, using the configured parser.

If there is an error, then there will be an error message string available through xoxa_error_message(ParserState*).

Parameters
Pa configured parser
Returns
zero on success, and non-zero on any error
int xoxa_parse_for_digest ( ParserState parser,
const char *  digest_name 
)

Parses the content of the input configured into the given parser.

This is a convenience wrapper for the sequence:

digest_ctx = xoxa_digest_initialize(parser, digest_name);
parse_status = xoxa_parse(parser);
digest = xoxa_get_digest(parser, digest_ctx, digest_len_ptr);
return digest;

or

 xoxa_pgp_verify_initialize(ParserState*);
 parse_status = xoxa_parse(parser);
 return xoxa_get_signature(ParserState*).

The list of available digests depends somewhat on the compilation context, but should include for example "SHA1". If the digest name is "pgp", then do a PGP verification of the XML content. If it is "_", then scan the content for a <?signature?> PI which indicates the element to digest/verify with "following::*[1]".

If there is an error, return NULL; an error message will be available from xoxa_error_message(ParserState*).

On successful return, either xoxa_get_signature(ParserState*) or xoxa_get_digest(ParserState* P, unsigned int* lenp) will return non-NULL.

Parameters
parserthe parser state
digest_namethe name of a digest algorithm
Returns
non-zero on error; zero on success
SignatureDetail* xoxa_parse_for_pgp_verify ( ParserState PS)

Given a configured parser, ready to start parsing, verify the PGP signature which we expect to find within the XML file.

This is a convenience method, and wraps xoxa_pgp_verify_initialize(ParserState*) and xoxa_get_signature(ParserState*).

If the parse is successful, returns the SignatureDetail pointer (note that this is dependent on the parse being successful; the verification may or may not be).

Parameters
PSa configured parser state
Returns
on error, NULL; on success the filled-in argument detail
void xoxa_parser_flags ( ParserState P,
ParserFlags  PF 
)

Sets parser flags.

Parameters
Pan initialised parser
PFone or more flags, or-ed together
int xoxa_pgp_verify_initialize ( ParserState PS)

Initialise a parser to verify a PGP signature.

On the successful completion of a parser, the results can be retrieved by xoxa_get_signature(ParserState*).

Parameters
PSa configured parser state
Returns
zero on success
int xoxa_push_output_callback ( ParserState P,
output_callback_t  cb,
void *  data,
const char *  label 
)

Push a callback onto the callback stack.

This may be done before a parse is started, or during a parse (for example at the start of an element). In the latter case, the callback is popped at the end of the element, and any associated finaliser called then.

When a callback is called, the other callbacks below it in the stack are called also.

The default callback (which is added if no callback is provided by the user) writes the normalized ESIS information to the standard output. If you wish to suppress this, then you must push the callback xoxa_null_callback (which does nothing).

Parameters
Pa parser state, which must not be NULL
cba callback function, which must not be NULL
dataa blob of data to be passed to the callback function when it is called
labela name for this, which is useful for debugging
See Also
xoxa_register_output_callback_finalizer
xoxa_null_callback
void xoxa_register_output_callback_finalizer ( ParserState P,
output_callback_end_t  cb_end 
)

Register a finaliser to be called when the top callback on the stack is popped.

Parameters
Pa parser state
cb_enda finalizer function
See Also
xoxa_push_output_callback
void xoxa_signature_fd ( ParserState P,
int  fd 
)

Specify the file-descriptor to which the library should write a signature block.

If this is provided, then when the library encounters a <?signature?> PI, it writes the contents of the armor="..." PI 'attribute' to the given open file-descriptor. The precise behaviour of the library in this respect may change in future beta versions, if and when further signature mechanisms are supported.

Parameters
Pa configured parser
fdan open file descriptor