[openssl-users] SOLVED --- ASN.1: Parsing a 'context-specific' class (or app/private class)

Massimiliano Pala director at openca.org
Wed Sep 2 14:11:54 UTC 2015


Hi all,

since someone asked, here's my solution (if someone knows of a better 
one, please let me know).

The problem that I tried to solve is how to parse the CRYTPLIB-specific 
envelope for signatures. In particular, the example reported in my 
original e-mail was a DSA signature. The main issue here was how to 
parse a context-specific 0-tagged value inside the structure. Here's the 
parsing:

         0:d=0  hl=2 l=  98 cons: SEQUENCE
         2:d=1  hl=2 l=   1 prim:  INTEGER           :03
         5:d=1  hl=2 l=  20 prim:  cont [ 0 ]
        27:d=1  hl=2 l=   9 cons:  SEQUENCE
        29:d=2  hl=2 l=   5 prim:   OBJECT            :sha1
        36:d=2  hl=2 l=   0 prim:   NULL
        38:d=1  hl=2 l=  11 cons:  SEQUENCE
        40:d=2  hl=2 l=   7 prim:   OBJECT :dsaEncryption
        49:d=2  hl=2 l=   0 prim:   NULL
        51:d=1  hl=2 l=  47 prim:  OCTET STRING

Since I could not find any ASN1 macro that would allow me to specify the 
field after the INTEGER (offset 5, class context-specific (0x80), no tag 
(0x0), and length 20), so I defined a new ASN1_ITEM type that uses the 
d2i_ASN1_bytes()/i2d_ASN1_bytes() for parsing or generating the value:

    *typedef ASN1_OCTET_STRING CRYPTLIB_KEYID;*
         // Defines the CRYPTLIB_KEYID as a string (keyID)

    ASN1_VALUE *cryptlib_keyid_d2i_func(ASN1_VALUE **a, const unsigned
    char **in, long length) {

         ASN1_VALUE * ret = NULL;
             // Return Value

         // Parse the key identifier
         ret = (ASN1_VALUE *)d2i_ASN1_bytes(NULL, in, length, 0,
    V_ASN1_CONTEXT_SPECIFIC);

         // Assigns the value (if the pointer to the structure was passed)
         if (a != NULL) *a = ret;

         // Returns the parsed value
         return ret;
    }

    int cryptlib_keyid_i2d_func(ASN1_VALUE *a, unsigned char **in) {
         // Generates the DER from the passed value
         return i2d_ASN1_bytes((ASN1_STRING *)a, in, 0, 0x80);
    }

    // Definition of the callbacks for the compat type
    static ASN1_COMPAT_FUNCS cryptlib_keyid_pf = {
             (ASN1_new_func *)ASN1_OCTET_STRING_new,
             (ASN1_free_func *)ASN1_OCTET_STRING_free,
    *cryptlib_keyid_d2i_func*,
    *cryptlib_keyid_i2d_func*
    };

    ASN1_ITEM_start(*CRYPTLIB_KEYID*)
       ASN1_ITYPE_COMPAT, V_ASN1_OCTET_STRING, NULL, 0,
    &cryptlib_keyid_pf, sizeof(*CRYPTLIB_KEYID*), "*CRYPTLIB_KEYID*"
    ASN1_ITEM_end(*CRYPTLIB_KEYID*)

    DECLARE_ASN1_FUNCTIONS(*CRYPTLIB_KEYID*);
    IMPLEMENT_ASN1_FUNCTIONS(*CRYPTLIB_KEYID*);

This allowed me to define the CRYPTLIB_SIG by using the usual macros:

    typedef struct sig_t {
         ASN1_INTEGER *version;
    *CRYPTLIB_KEYID* *keyId;
         X509_ALGOR *hashAlgorithm;
         X509_ALGOR *sigAlgorithm;
         ASN1_OCTET_STRING *value;
    } CRYPTLIB_SIG;

    ASN1_SEQUENCE(CRYPTLIB_SIG) = {
             ASN1_SIMPLE(CRYPTLIB_SIG, version, ASN1_INTEGER),
             ASN1_SIMPLE(CRYPTLIB_SIG, keyId, *CRYPTLIB_KEYID*),
             ASN1_SIMPLE(CRYPTLIB_SIG, hashAlgorithm, X509_ALGOR),
             ASN1_SIMPLE(CRYPTLIB_SIG, sigAlgorithm, X509_ALGOR),
             ASN1_SIMPLE(CRYPTLIB_SIG, value, ASN1_OCTET_STRING)
    } ASN1_SEQUENCE_END(CRYPTLIB_SIG)

    DECLARE_ASN1_FUNCTIONS(CRYPTLIB_SIG)
    IMPLEMENT_ASN1_FUNCTIONS(CRYPTLIB_SIG)

Maybe a little hackerish solution... but this is the easiest I could 
think of. Does anybody have a better solution ?

Also, is there anybody who knows how to use the new ADB macros? Or is 
there any documentation on how to use them? That would be really useful 
to have...

Cheers,
Max

P.S.: The contents of the 'value' field in CRYPTLIB_SIG can be simply 
parsed by using the appropriate key-parsing function. In the example, 
you can use the d2i_DSA_SIG()/i2d_DSA_SIG() for parsing the actual DSA 
signatures.

P.P.S: Parsing application or private classes should require minimum 
changes (e.g., changing the class value from 0x80 to 0xC0 should allow 
to parse/generate private fields).

On 9/1/15 3:48 PM, Sec_Aficiondado wrote:
> Hi Massimiliano,
>
> Please do share it here on the list. There might not be an immediate need for it, but you'll save a couple of days to the next poor soul that ventures down the same path :)
>
> Your solution will be indexed and pop right up on search engines in the future.
>
> Thanks!
> Sent from my mobile
>
>> On Aug 31, 2015, at 7:10 PM, Massimiliano Pala <director at openca.org> wrote:
>>
>> Hi all,
>>
>> I actually figured it out, if anybody is curious about the solution for parsing this CRYPTLIB signature envelope (in this case DSA) - write to me directly, I will be happy to share the solution.
>>
>> Cheers,
>> Max
>>
>>> On 8/29/15 6:56 PM, Massimiliano Pala wrote:
>>> Hi all,
>>>
>>> I am trying to parse a sequence that has, after an integer, a 'private' (xclass) item. I was wondering what is the right templates / macros to be able to generate the ASN1 functions with the usual macro. An example of the structure I have to parse (B64 - DER), is the following:
>>>
>>> MGICAQOAFGZKq8/wIYS7Iueq6NuaC3ESPqUKMAkGBSsOAwIaBQAwCwYHKoZIzjgEAQUABC8wLQIVAJTJ6W2QjBIbVQdAtLbPO3y1wazHAhRsXivNO/Eg4GMEgcmEx8OgsIxGzQ==
>>>
>>> [ you can paste it into http://www.lapo.it/asn1js/ to get useful info. ]
>>>
>>> The field that is giving me issues is the 2nd field in the sequence - offest 5, length 20 (i.e., after SEQUENCE (2 bytes) + INTEGER (3 bytes) and then the 20bytes field that I want to parse). The type is 0x80 - context specific. By using the ASN1_get_object() function, I get the correct size (20), the tag (0), and the xclass (128). Now, how do I go in order to generate the useful ASN1 function with teh usual macros ? Here's an example (besides the second field) for what I am trying to do:
>>>
>>> ASN1_SEQUENCE(TYPE) = {
>>>
>>>     ASN1_SIMPLE(TYPE, field1, ASN1_INTEGER),
>>>
>>>     XXXXXXX(TYPE, field2, YYYYY),                      <<-- What shall be used here ? What Macro ?
>>>
>>>     ASN1_SEQUENCE_OF(TYPE, field3, ASN1_OBJECT),
>>>
>>>     ASN1_SEQUENCE_OF(TYPE, field3, ASN1_OBJECT),
>>>
>>>     ASN1_SIMPLE(TYPE, field3, ASN1_OCTET_STRING)       <<-- This might be wrong as well - just noticed it is a very
>>>
>>> } ASN1_SEQUENCE_END(TYPE)                                    weird encoding (octet-string that encapsulates a sequence of integers)
>>>
>>>
>>> Is there a way to have the macros do the work (e.g., shall I use other macros - template? - to define the field somehow) ? Or shall I just write my own d2i_ and i2d_ functions ?
>>>
>>> Please let me know,
>>>
>>> Cheers,
>>> Max
>>>
>>> _______________________________________________
>>> openssl-users mailing list
>>> To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users
>> _______________________________________________
>> openssl-users mailing list
>> To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users
> _______________________________________________
> openssl-users mailing list
> To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mta.openssl.org/pipermail/openssl-users/attachments/20150902/f4725f6e/attachment-0001.html>


More information about the openssl-users mailing list