### 3.3 Creating a SPA Message ¶

This section describes the process for creating a new fko SPA message. After creating a context, there are still some requisite SPA data fields and SPA parameters that need to be set before the final encrypted message is ready.

The following list contains the minimum required fields for a complete fko SPA message. You should also take note of the order of these parameters as well. Setting the “type” parameters first is recommended (if you want a type other than the default).

- digest_type – (default may suffice)
- message_type – (default may suffice)
- encryption_type – (default may suffice)
- rand_val – (default should suffice)
- time_stamp – (default should suffice)
- username – (default may suffice)
- spa_message – (must be explicitly set)

If using gpg encryption:

- gpg_recipient – (must be explicitly set)
- gpg_signer – (optional, but recommended - must be explicitly set if used)
- gpg_home_dir – (default may suffice - typically $HOME/.gnupg)

When a context is initialized, some of the SPA data fields are pre-set with default values (see SPA Data Format). For fields such as `rand_val`, `username`, `timestamp`, `message_type`, and `digest_type`, these defaults may be sufficient.

The functions used to set the various SPA data fields and parameters are described in detail in Setting SPA Data.

Note: Attempts to call any “`fko_`” function on a context that has not been initialized can have undefined consequences. Libfko will attempt to recover, and if successful, will return a status of `FKO_ERROR_CTX_NOT_INITIALIZED`.

A common SPA message is a simple access request. This request asks the fwknop server to create a temporary firewall rule to allow a particular IP address access to a particular port on the fwknop server. Assuming the defaults are fine for this, all we need to do is create the context, set the message data field, call the `fko_spa_data_final` function to encode and encrypt, process the message, then destroy the context. Below, we have a contrived bit of code demonstrating this:

    int
    main(int argc, char **argv)
    {
        fko_ctx_t   ctx;           /* FKO Context */
        char       *key;           /* Encryption passphrase */
        char       *hmac_key;      /* HMAC key */
        char       *final_spa;     /* Final encrypted SPA data */
        int         key_len;       /* Length of encryption key */
        int         hmac_key_len;  /* Length of HMAC key */
        int         rc;            /* Result code */
        int         hmac_type = FKO_HMAC_SHA256;   /* Default HMAC digest */
        int         enc_mode  = FKO_ENC_MODE_ASYMMETRIC;  /* Use GPG */

        /*  Assume we processed the command line
         *  and retrieved the password and the HMAC key and
        *   set their associated lengths.
        */

        /* Create the context */
        rc = fko_new(&ctx);
        if(rc != FKO_SUCCESS)
        {
            fprintf(stderr, "Error creating context: %s\n", fko_errstr(rc));
            exit(1);
        }

        /* Set the SPA message field - asking to open tcp port 22
         * for the system at 192.168.0.33
        */
        rc = fko_set_spa_message(ctx, "192.168.0.33,tcp/22");
        if(rc != FKO_SUCCESS)
        {
            fprintf(stderr, "Set SPA message failed: %s\n", fko_errstr(rc));
            exit(1);
        }

        /* Let us assume we are using GPG encryption.  So we need to
         * set the encryption type and set the required GPG parameters
         * (we can skip checking return values for brevity).
        */
        rc = fko_set_spa_encryption_type(ctx, FKO_ENCRYPTION_GPG);

        /* Key for the recipient */
        rc = fko_set_gpg_recipient(ctx, "recip@some.where");

        /* Key for the signer (if you want to sign it) */
        rc = fko_set_gpg_signer(ctx, "me@right.here");

        /* Finalize the SPA data */
        rc = fko_spa_data_final(ctx, key, key_len, enc_mode,
                hmac_key, hmac_key_len, hmac_type);
        if(rc != FKO_SUCCESS)
        {
            fprintf(stderr, "Error encoding SPA data: %s\n",
                fko_errstr(rc));
            exit(1);
        }

        /* Take the final message and do something with it */
        rc = fko_get_spa_data(ctx, &final_spa);

        /* Assume this function packs the spa data into a UDP
         * packet and sends it to the server.
        */
        send_spa_message(final_spa);

        /* Done with the context */
        fko_destroy(ctx);

        exit(0);
    }