|
Xoxa-c
0.3.1
Normalizer/Parser for XML
|
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>
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. | |
| SignatureDetail * | xoxa_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. | |
| ParserState * | xoxa_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. | |
| 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. | |
| 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. | |
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].
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);
}
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.
| typedef void(* output_callback_end_t)(ParserState *, void *data) |
The type of the Xoxa callback finaliser.
The callback takes two arguments:
| typedef void(* output_callback_t)(const byte *bytes, size_t len, void *data) |
The type of the Xoxa callback.
The callback takes three arguments:
| typedef uint8_t ParserFlags |
Various flags which control the parser.
The flags are:
| 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.
| 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).
| details | a 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.
| buf | the buffer of output data |
| len | the length of the buffer |
| data | the 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.
| parser | the Xoxa parser |
| digest_name | the name of a digest algorithm |
| int xoxa_digest_is_initialized | ( | ParserState * | parser | ) |
Tests whether a digest has been initialized.
| parser | the parser state |
| 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.
| P | a 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.
| P | a configured parser, after a parse has completed successfully |
| lenp | if non-NULL, this points to a location which is filled in with the length of the digest in bytes |
| 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.
| P | a configured parser, after a parser has completed successfully |
| 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)
| fd | the identifier of the file descriptor which is to be read in |
| 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)
| filename | the file which is to be read in |
| 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)
| xmlcontent | the string which is to be read in |
| 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.
| src | an initialised InputSource object, which must not be NULL |
| void xoxa_null_callback | ( | const byte * | buf, |
| size_t | len, | ||
| void * | data | ||
| ) |
The 'null' callback receives a line of ESIS output and discards it.
| buf | the buffer of output data |
| len | the length of the buffer |
| data | the 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*).
| P | a configured parser |
| 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.
| parser | the parser state |
| digest_name | the name of a digest algorithm |
| 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).
| PS | a configured parser state |
detail | void xoxa_parser_flags | ( | ParserState * | P, |
| ParserFlags | PF | ||
| ) |
Sets parser flags.
| P | an initialised parser |
| PF | one 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*).
| PS | a configured parser state |
| 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).
| P | a parser state, which must not be NULL |
| cb | a callback function, which must not be NULL |
| data | a blob of data to be passed to the callback function when it is called |
| label | a name for this, which is useful for debugging |
| 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.
| P | a parser state |
| cb_end | a finalizer function |
| 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.
| P | a configured parser |
| fd | an open file descriptor |
1.8.2