3

I'm trying to build a set of sequences using the openssl C API. As was noted in various places, the documentation is VERY sparse on this and code samples seem to be non-existent.

I've found various suggestions on the web but none that seemed to work correctly.

I've gotten that far in order to create sequences:

#include <openssl/asn1t.h>

countdef struct StringStructure {
    ASN1_INTEGER *count;
    ASN1_INTEGER *asnVersion;
    ASN1_OCTET_STRING *value;
} StringSequence;

DECLARE_ASN1_FUNCTIONS(StringSequence)

ASN1_SEQUENCE(StringSequence) = {
    ASN1_SIMPLE(StringSequence, count, ASN1_INTEGER),
    ASN1_SIMPLE(StringSequence, asnVersion, ASN1_INTEGER),
    ASN1_SIMPLE(StringSequence, value, ASN1_OCTET_STRING),
} ASN1_SEQUENCE_END(StringSequence)

IMPLEMENT_ASN1_FUNCTIONS(StringSequence)

auto aSeq = StringSequence_new();
aSeq->count = ASN1_INTEGER_new();
aSeq->asnVersion = ASN1_INTEGER_new();
aSeq->value = ASN1_OCTET_STRING_new();
if (!ASN1_INTEGER_set(aSeq->count, 10) ||
    !ASN1_INTEGER_set(aSeq->asnVersion, 1) ||
    !ASN1_STRING_set(aSeq->value, "Test", -1)) {
    // -- Error
}

auto anotherSeq = StringSequence_new();
anotherSeq->count = ASN1_INTEGER_new();
anotherSeq->asnVersion = ASN1_INTEGER_new();
anotherSeq->value = ASN1_OCTET_STRING_new();
if (!ASN1_INTEGER_set(anotherSeq->count, 32) ||
    !ASN1_INTEGER_set(anotherSeq->asnVersion, 1) ||
    !ASN1_STRING_set(anotherSeq->value, "Something Else", -1)) {
    // -- Error
}

Where do I go from there in order to build a set of these?

Didier Malenfant
  • 729
  • 1
  • 10
  • 25
  • 1
    Have you seen this? https://stackoverflow.com/a/12108234 – Robert Harvey Dec 17 '18 at 05:40
  • 1
    Do you know for a fact that it contains the info I need? I just spend two night going thru other docs that really explained nothing so it would be nice, if you have the answer, to provide it here instead of sending me on a potential wild goose chase :) – Didier Malenfant Dec 17 '18 at 05:52
  • 1
    No, sorry, I haven't opened these files and checked them specifically for you. I point out the POD files because they appear to be the "official" documentation, so if you haven't read them yet, you need to do so. – Robert Harvey Dec 17 '18 at 16:10

1 Answers1

5

The OpenSSL source code is your best documentation...

As an example of a construct like the one you are trying to build, check out the PKCS7_SIGNED ASN1 definition in crypto/pkcs7/pk7_asn1.c:

ASN1_NDEF_SEQUENCE(PKCS7_SIGNED) = {
        ASN1_SIMPLE(PKCS7_SIGNED, version, ASN1_INTEGER),
        ASN1_SET_OF(PKCS7_SIGNED, md_algs, X509_ALGOR),
        ASN1_SIMPLE(PKCS7_SIGNED, contents, PKCS7),
        ASN1_IMP_SEQUENCE_OF_OPT(PKCS7_SIGNED, cert, X509, 0),
        ASN1_IMP_SET_OF_OPT(PKCS7_SIGNED, crl, X509_CRL, 1),
        ASN1_SET_OF(PKCS7_SIGNED, signer_info, PKCS7_SIGNER_INFO)
} ASN1_NDEF_SEQUENCE_END(PKCS7_SIGNED)

Its second member, md_algs, is a set of X509_ALGOR, which is in itself a sequence defined in crypto/asn1/x_algor.c:

ASN1_SEQUENCE(X509_ALGOR) = {
        ASN1_SIMPLE(X509_ALGOR, algorithm, ASN1_OBJECT),
        ASN1_OPT(X509_ALGOR, parameter, ASN1_ANY)
} ASN1_SEQUENCE_END(X509_ALGOR)

So that field md_algs is a set of sequences, like you are asking for. The equivalent C- structure definitions can be found in include/openssl/pkcs7.h:

typedef struct pkcs7_signed_st {
    ASN1_INTEGER *version;      /* version 1 */
    STACK_OF(X509_ALGOR) *md_algs; /* md used */
    STACK_OF(X509) *cert;       /* [ 0 ] */
    STACK_OF(X509_CRL) *crl;    /* [ 1 ] */
    STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
    struct pkcs7_st *contents;
} PKCS7_SIGNED;

The md_algs field shows that to capture the set-construct, you need to use the STACK API, which is intended to handle collections. In your case, that would be a STACK_OF(StringSequence).

Reinier Torenbeek
  • 16,669
  • 7
  • 46
  • 69
  • Very complete answer. Thank you! – Didier Malenfant Dec 17 '18 at 19:37
  • A quick follow up on this, the example above still creates a sequence that contains one set. I'm able to use something like `sk_StringSequence_new_null()` to create a standalone set but I couldn't find any way to then encode that to ASN1. It seems like there is no equivalent of `DECLARE_ASN1_FUNCTIONS()` and `IMPLEMENT_ASN1_FUNCTIONS()` for objects defined via `DEFINE_STACK_OF()`. For now I decided to convert to parent sequence to ASN1 and then grab only the set data from inside of it. It's all done using ASN1 methods so it should be pretty safe, if ugly. – Didier Malenfant Dec 18 '18 at 19:52