Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.


OSX Receipt validation in Swift, part 4: Accessing a C union from Swift

Receipts are stored in a so called PKCS7 container. Accessing the components in this container using openSSL will hit a snag: the PKCS7 structure is defined using a "union". Unfortunately, Swift 1.2 does not allow direct access to C union elements. So it will be necessary to define a few C-functions to access this part of the container.

We find the definition of the PKCS7 structure in "openssl/pkcs7.h" as follows:

typedef struct pkcs7_st {
     * The following is non NULL if it contains ASN1 encoding of this
     * structure
    unsigned char *asn1;
    long length;
# define PKCS7_S_HEADER  0
# define PKCS7_S_BODY    1
# define PKCS7_S_TAIL    2
    int state;                  /* used during processing */
    int detached;
    ASN1_OBJECT *type;
    /* content as defined by the type */
     * all encryption/message digests are applied to the 'contents', leaving
     * out the 'type' field.
    union {
        char *ptr;
        /* NID_pkcs7_data */
        ASN1_OCTET_STRING *data;
        /* NID_pkcs7_signed */
        PKCS7_SIGNED *sign;
        /* NID_pkcs7_enveloped */
        PKCS7_ENVELOPE *enveloped;
        /* NID_pkcs7_signedAndEnveloped */
        PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
        /* NID_pkcs7_digest */
        PKCS7_DIGEST *digest;
        /* NID_pkcs7_encrypted */
        PKCS7_ENCRYPT *encrypted;
        /* Anything else */
        ASN1_TYPE *other;
    } d;

} PKCS7;

In Swift we can access the normal elements as follows:

if OBJ_obj2nid(receiptPKCS7.memory.type) != NID_pkcs7_signed {...}

But for the union part this does not work.

Instead we can define accessor functions in C and made these visible to Swift in the MyGreatApp-Bridging-Header.h file.

The header file (pkcs7_union_accessors.h) for these accessors is:

#ifndef __MyGreatApp__pkcs7_union_accessors__
#define __MyGreatApp__pkcs7_union_accessors__

#include <openssl/pkcs7.h>

char *pkcs7_d_char(PKCS7 *ptr);
ASN1_OCTET_STRING *pkcs7_d_data(PKCS7 *ptr);
PKCS7_SIGNED *pkcs7_d_sign(PKCS7 *ptr);
PKCS7_ENVELOPE *pkcs7_d_enveloped(PKCS7 *ptr);
PKCS7_SIGN_ENVELOPE *pkcs7_d_signed_and_enveloped(PKCS7 *ptr);
PKCS7_DIGEST *pkcs7_d_digest(PKCS7 *ptr);
PKCS7_ENCRYPT *pkcs7_d_encrypted(PKCS7 *ptr);
ASN1_TYPE *pkcs7_d_other(PKCS7 *ptr);

#endif /* defined(__MyGreatApp__pkcs7_union_accessors__) */

The corresponding implementation file (pkcs7_union_accessors.c) is as follows:

#include "pkcs7_union_accessors.h"

inline char *pkcs7_d_char(PKCS7 *ptr) {
    return ptr->d.ptr;

inline ASN1_OCTET_STRING *pkcs7_d_data(PKCS7 *ptr) {
    return ptr->;

inline PKCS7_SIGNED *pkcs7_d_sign(PKCS7 *ptr) {
    return ptr->d.sign;

inline PKCS7_ENVELOPE *pkcs7_d_enveloped(PKCS7 *ptr) {
    return ptr->d.enveloped;

inline PKCS7_SIGN_ENVELOPE *pkcs7_d_signed_and_enveloped(PKCS7 *ptr) {
    return ptr->d.signed_and_enveloped;

inline PKCS7_DIGEST *pkcs7_d_digest(PKCS7 *ptr) {
    return ptr->d.digest;

inline PKCS7_ENCRYPT *pkcs7_d_encrypted(PKCS7 *ptr) {
    return ptr->d.encrypted;

inline ASN1_TYPE *pkcs7_d_other(PKCS7 *ptr) {
    return ptr->d.other;


I am not sure if the 'inline' works across languages, but it won't hurt so I just put it in.

Using these functions we can now access the union part as follows:

if OBJ_obj2nid(pkcs7_d_sign(receiptPKCS7).memory.contents.memory.type) != NID_pkcs7_data {...}

I am pretty sure it is also possible to use some nifty type conversion, but this works for me.

Next up in the series part 5: The device GUID

Happy coding...

Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.

No comments:

Post a Comment