Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encode and decode a secret key #627

Closed
MaryamSD opened this issue Dec 1, 2015 · 10 comments
Closed

encode and decode a secret key #627

MaryamSD opened this issue Dec 1, 2015 · 10 comments

Comments

@MaryamSD
Copy link

MaryamSD commented Dec 1, 2015

Hi,
I need an encode function for using in sc_pkcs15_encode_df to encode a "secret key" object.
I'm checking new changes for secret keys in libopensc. There is a function named sc_pkcs15_decode_skdf_entry in pkcs15_skey.c file that calls ASN1 decode function.
This function can be used for encode too? or I must develop encode_entry function?

@viktorTarasov
@frankmorgner

@frankmorgner
Copy link
Member

sc_pkcs15_decode_skdf_entry parses a buffer and initializes a struct sc_pkcs15_object * accordingly. I did not fully understand what you're trying to do, but it's best if you had a look into the code to understand what a specific function is doing.

@dengert
Copy link
Member

dengert commented Dec 2, 2015

PKCS#15 V1.1 Section " 6.5.1 The SecretKeys type" defines the ASN.1 for 10 different keys. But it is from 2000, before AES. OpenSC in pkcs15-sec.c defines c_asn1_skey, c_asn1_skey_choice and c_asn1_skey_choice. these only handle desKey, des2Key and des3Key.

Maybe ISO 7816-15 has a more up to date version. If anyone has one.

sc_pkcs15_encode_skdf_entry would be the encode function, but it is not implemented.

@MaryamSD
Copy link
Author

MaryamSD commented Dec 3, 2015

@frankmorgner

sc_pkcs15_decode_skdf_entry parses a buffer and initializes a struct sc_pkcs15_object * accordingly. I did not fully understand what you're trying to do, but it's best if you had a look into the code to understand what a specific function is doing.

I'm trying to create secret key objects. Now, All things is ok and secret key object created successfully, but there is a problem. After create object, if we call FindObjects over a new session there isn't object. I trace opensc code and understand that we need a sc_pkcs15_encode_df to get an encoded buffer of object and use this buffer in sc_pkcs15init_update_file.

@dengert

PKCS#15 V1.1 Section " 6.5.1 The SecretKeys type" defines the ASN.1 for 10 different keys. But it is from 2000, before AES. OpenSC in pkcs15-sec.c defines c_asn1_skey, c_asn1_skey_choice and c_asn1_skey_choice. these only handle desKey, des2Key and des3Key.

Yes, I study pkcs15 and understand sc_pkcs15_decode_skdf_entry. Also I investigate OpenSC code related to secret keys.
Can I add AES algorithms to this choice?

sc_pkcs15_encode_skdf_entry would be the encode function, but it is not implemented.

If I follow sc_pkcs15_decode_skdf_entry to implement sc_pkcs15_encode_skdf_entry, Is there any problem in sc_asn1_encode function? Are defined All necessary structures and data to encode?

@frankmorgner
Copy link
Member

Quoting from ISO/IEC 7816-15:

8.6.1 SecretKeyChoice

SecretKeyChoice ::= CHOICE {
  algIndependentKey SecretKeyObject {SecretKeyAttributes},
  genericSecretKey [15] SecretKeyObject {GenericKeyAttributes},
  ... -- For future extensions
} -- Note: Context tags [0] – [14] are historical and not to be used

NOTE PKCS#15 uses these tags.

You should wrap your AES-key into GenericKeyAttributes

@MaryamSD
Copy link
Author

MaryamSD commented Dec 5, 2015

Quoting from ISO/IEC 7816-15:

8.6.1 SecretKeyChoice

SecretKeyChoice ::= CHOICE {
algIndependentKey SecretKeyObject {SecretKeyAttributes},
genericSecretKey [15] SecretKeyObject {GenericKeyAttributes},
... -- For future extensions
} -- Note: Context tags [0] – [14] are historical and not to be used
NOTE PKCS#15 uses these tags.
You should wrap your AES-key into GenericKeyAttributes

Thanks. I'm applied this note in c_asn1_skey_choice:

#define C_ASN1_SKEY_CHOICE_SIZE 6
static const struct sc_asn1_entry c_asn1_skey_choice[C_ASN1_SKEY_CHOICE_SIZE] = {
    { "genericSecretKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
    { "desKey",     SC_ASN1_PKCS15_OBJECT, SC_ASN1_CTX | 2 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
    { "des2Key",    SC_ASN1_PKCS15_OBJECT, SC_ASN1_CTX | 3 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
    { "des3Key",    SC_ASN1_PKCS15_OBJECT, SC_ASN1_CTX | 4 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
    { "aesKey",     SC_ASN1_PKCS15_OBJECT, SC_ASN1_CTX | 15 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
    { NULL, 0, 0, 0, NULL, NULL }
};

I'm developed sc_pkcs15_encode_skdf_entry:

int sc_pkcs15_encode_skdf_entry(struct sc_context *ctx,
                 const struct sc_pkcs15_object *obj,
                 u8 **buf, size_t *buflen)
{
    struct sc_pkcs15_seckey_info *info;
    int r;
    size_t usage_len = sizeof(info->usage);
    size_t af_len = sizeof(info->access_flags);
    struct sc_asn1_entry asn1_com_key_attr[C_ASN1_COM_KEY_ATTR_SIZE];
    struct sc_asn1_entry asn1_com_skey_attr[C_ASN1_COM_SKEY_ATTR_SIZE];
    struct sc_asn1_entry asn1_generic_skey_attr[C_ASN1_COM_GENERIC_SKEY_ATTR_SIZE];
    struct sc_asn1_entry asn1_skey_choice[C_ASN1_SKEY_CHOICE_SIZE];
    struct sc_asn1_entry asn1_skey[C_ASN1_SKEY_SIZE];
    struct sc_asn1_pkcs15_object skey_des_obj = { (struct sc_pkcs15_object *)obj, 
                                                   asn1_com_key_attr, asn1_com_skey_attr, asn1_generic_skey_attr };
    info = (struct sc_pkcs15_seckey_info *)obj->data;

    SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_ASN1);

    sc_copy_asn1_entry(c_asn1_skey, asn1_skey);
    sc_copy_asn1_entry(c_asn1_skey_choice, asn1_skey_choice);
    sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr);
    sc_copy_asn1_entry(c_asn1_com_skey_attr, asn1_com_skey_attr);
    sc_copy_asn1_entry(c_asn1_generic_skey_attr, asn1_generic_skey_attr);

    sc_format_asn1_entry(asn1_skey + 0, asn1_skey_choice, NULL, 1);
    sc_format_asn1_entry(asn1_skey_choice + 0, &skey_des_obj, NULL, 1);
    sc_format_asn1_entry(asn1_skey_choice + 1, &skey_des_obj, NULL, 1);
    sc_format_asn1_entry(asn1_skey_choice + 2, &skey_des_obj, NULL, 1);
    sc_format_asn1_entry(asn1_skey_choice + 3, &skey_des_obj, NULL, 1);

    sc_format_asn1_entry(asn1_com_key_attr + 0, &info->id, NULL, 1);
    sc_format_asn1_entry(asn1_com_key_attr + 1, &info->usage, &usage_len, 1);
    sc_format_asn1_entry(asn1_com_key_attr + 2, &info->native, NULL, 1);
    sc_format_asn1_entry(asn1_com_key_attr + 3, &info->access_flags, &af_len, 1);
    sc_format_asn1_entry(asn1_com_key_attr + 4, &info->key_reference, NULL, 1);
    sc_format_asn1_entry(asn1_com_skey_attr + 0, &info->secretkey_length, NULL, 1);
    sc_format_asn1_entry(asn1_generic_skey_attr + 0, &info->path, NULL, 1);

    if (obj->type == SC_PKCS15_TYPE_SKEY_DES)
        asn1_skey_choice[1].flags |= SC_ASN1_PRESENT;       
    else if (obj->type == SC_PKCS15_TYPE_SKEY_2DES)
        asn1_skey_choice[2].flags |= SC_ASN1_PRESENT;
    else if (obj->type == SC_PKCS15_TYPE_SKEY_3DES)
        asn1_skey_choice[3].flags |= SC_ASN1_PRESENT;
    else
        LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported secret key type");

    r = sc_asn1_encode(ctx, asn1_skey, buf, buflen);

    LOG_TEST_RET(ctx, r, "ASN.1 decoding failed");
    //LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
}

but there is a problem in asn1.c , asn1_encode_entry function. In bellow loop code, list has 6 element and all of theme has type = SC_ASN1_CHOICE, so we get SC_ERROR_INVALID_ASN1_OBJECT in second repetition for "deskey" entry. Should be set a special flag?

if (entry->type == SC_ASN1_CHOICE)
{
    const struct sc_asn1_entry *list, *choice = NULL;

    list = (const struct sc_asn1_entry *) parm;
    while (list->name != NULL)
    {
        if (list->flags & SC_ASN1_PRESENT) {
            if (choice) {
                sc_debug(ctx, SC_LOG_DEBUG_ASN1,
                    "ASN.1 problem: more than "
                    "one CHOICE when encoding %s: "
                    "%s and %s both present\n",
                    entry->name,
                    choice->name,
                    list->name);
                return SC_ERROR_INVALID_ASN1_OBJECT;
            }
            choice = list;
        }
        list++;
    }
    if(choice == NULL)
        goto no_object;
    return asn1_encode_entry(ctx, choice, obj, objlen, depth + 1);
}

@MaryamSD
Copy link
Author

MaryamSD commented Dec 5, 2015

should be sc_format_asn1_entry (in sc_pkcs15_encode_skdf_entry) called only for one of the choices? should be I format according to obj->type? If it's true, what is usage "genericsecretkey" (first choice)?

@dengert
Copy link
Member

dengert commented Dec 5, 2015

When encoding, you only format one entry in the list. 

Look at  asn1_pubkey_choice in sc_pkcs15_encode_pukdf_entry
 

switch (obj->type) {
case SC_PKCS15_TYPE_PUBKEY_RSA:
              sc_format_asn1_entry(asn1_pubkey_choice + 0,
&rsakey_obj, NULL, 1);
...
case SC_PKCS15_TYPE_PUBKEY_DSA:
                sc_format_asn1_entry(asn1_pubkey_choice + 1,
&dsakey_obj, NULL, 1);
...
case SC_PKCS15_TYPE_PUBKEY_GOSTR3410:
                 sc_format_asn1_entry(asn1_pubkey_choice + 2,
&gostr3410key_obj, NULL, 1);
...
case SC_PKCS15_TYPE_PUBKEY_EC:
                 sc_format_asn1_entry(asn1_pubkey_choice + 3,
&eckey_obj, NULL, 1);
...
case SC_PKCS15_TYPE_PUBKEY_EC:
                 sc_format_asn1_entry(asn1_pubkey_choice + 3,
&eckey_obj, NULL, 1);

On 12/5/2015 4:37 AM, MaryamSD wrote:



    Quoting from ISO/IEC 7816-15:
    8.6.1 SecretKeyChoice
    SecretKeyChoice ::= CHOICE {
      algIndependentKey SecretKeyObject {SecretKeyAttributes},
      genericSecretKey [15] SecretKeyObject {GenericKeyAttributes},
      ... -- For future extensions
      } -- Note: Context tags [0] – [14] are historical and not to
      be used
      NOTE PKCS#15 uses these tags.
      You should wrap your AES-key into GenericKeyAttributes

  Thanks. I'm applied this note in c_asn1_skey_choice:

    #define C_ASN1_SKEY_CHOICE_SIZE 6

static const struct sc_asn1_entry c_asn1_skey_choice[C_ASN1_SKEY_CHOICE_SIZE] = {
{ "genericSecretKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
{ "desKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_CTX | 2 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
{ "des2Key", SC_ASN1_PKCS15_OBJECT, SC_ASN1_CTX | 3 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
{ "des3Key", SC_ASN1_PKCS15_OBJECT, SC_ASN1_CTX | 4 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
{ "aesKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_CTX | 15 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};

  I'm developed sc_pkcs15_encode_skdf_entry:

    int sc_pkcs15_encode_skdf_entry(struct sc_context *ctx,
             const struct sc_pkcs15_object *obj,
             u8 **buf, size_t *buflen)

{
struct sc_pkcs15_seckey_info *info;
int r;
size_t usage_len = sizeof(info->usage);
size_t af_len = sizeof(info->access_flags);
struct sc_asn1_entry asn1_com_key_attr[C_ASN1_COM_KEY_ATTR_SIZE];
struct sc_asn1_entry asn1_com_skey_attr[C_ASN1_COM_SKEY_ATTR_SIZE];
struct sc_asn1_entry asn1_generic_skey_attr[C_ASN1_COM_GENERIC_SKEY_ATTR_SIZE];
struct sc_asn1_entry asn1_skey_choice[C_ASN1_SKEY_CHOICE_SIZE];
struct sc_asn1_entry asn1_skey[C_ASN1_SKEY_SIZE];
struct sc_asn1_pkcs15_object skey_des_obj = { (struct sc_pkcs15_object *)obj,
asn1_com_key_attr, asn1_com_skey_attr, asn1_generic_skey_attr };
info = (struct sc_pkcs15_seckey_info *)obj->data;

SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_ASN1);

sc_copy_asn1_entry(c_asn1_skey, asn1_skey);
sc_copy_asn1_entry(c_asn1_skey_choice, asn1_skey_choice);
sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr);
sc_copy_asn1_entry(c_asn1_com_skey_attr, asn1_com_skey_attr);
sc_copy_asn1_entry(c_asn1_generic_skey_attr, asn1_generic_skey_attr);

sc_format_asn1_entry(asn1_skey + 0, asn1_skey_choice, NULL, 1);
sc_format_asn1_entry(asn1_skey_choice + 0, &skey_des_obj, NULL, 1);
sc_format_asn1_entry(asn1_skey_choice + 1, &skey_des_obj, NULL, 1);
sc_format_asn1_entry(asn1_skey_choice + 2, &skey_des_obj, NULL, 1);
sc_format_asn1_entry(asn1_skey_choice + 3, &skey_des_obj, NULL, 1);

sc_format_asn1_entry(asn1_com_key_attr + 0, &info->id, NULL, 1);
sc_format_asn1_entry(asn1_com_key_attr + 1, &info->usage, &usage_len, 1);
sc_format_asn1_entry(asn1_com_key_attr + 2, &info->native, NULL, 1);
sc_format_asn1_entry(asn1_com_key_attr + 3, &info->access_flags, &af_len, 1);
sc_format_asn1_entry(asn1_com_key_attr + 4, &info->key_reference, NULL, 1);
sc_format_asn1_entry(asn1_com_skey_attr + 0, &info->secretkey_length, NULL, 1);
sc_format_asn1_entry(asn1_generic_skey_attr + 0, &info->path, NULL, 1);

if (obj->type == SC_PKCS15_TYPE_SKEY_DES)
    asn1_skey_choice[1].flags |= SC_ASN1_PRESENT;       
else if (obj->type == SC_PKCS15_TYPE_SKEY_2DES)
    asn1_skey_choice[2].flags |= SC_ASN1_PRESENT;
else if (obj->type == SC_PKCS15_TYPE_SKEY_3DES)
    asn1_skey_choice[3].flags |= SC_ASN1_PRESENT;
else
    LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported secret key type");

r = sc_asn1_encode(ctx, asn1_skey, buf, buflen);

LOG_TEST_RET(ctx, r, "ASN.1 decoding failed");
//LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);

}

  but there is a problem in asn1.c , asn1_encode_entry function.
    In bellow loop code, list has 6 element and all of theme has
    type = SC_ASN1_CHOICE, so we get SC_ERROR_INVALID_ASN1_OBJECT in
    second repetition for "deskey" entry. Should be set a special
    flag?

    if (entry->type == SC_ASN1_CHOICE)

{
const struct sc_asn1_entry *list, *choice = NULL;

list = (const struct sc_asn1_entry *) parm;
while (list->name != NULL)
{
    if (list->flags & SC_ASN1_PRESENT) {
        if (choice) {
            sc_debug(ctx, SC_LOG_DEBUG_ASN1,
                "ASN.1 problem: more than "
                "one CHOICE when encoding %s: "
                "%s and %s both present\n",
                entry->name,
                choice->name,
                list->name);
            return SC_ERROR_INVALID_ASN1_OBJECT;
        }
        choice = list;
    }
    list++;
}
if(choice == NULL)
    goto no_object;
return asn1_encode_entry(ctx, choice, obj, objlen, depth + 1);

}

  —
    Reply to this email directly or view
      it on GitHub.









-- 

Douglas E. Engert DEEngert@gmail.com

@MaryamSD
Copy link
Author

MaryamSD commented Dec 5, 2015

Thanks.

@dengert
Copy link
Member

dengert commented Dec 5, 2015

Looks like PKCS#15 and 7816-15 have changed the name of the untagged first choie from:
genericSecretKey SecretKeyObject {GenericSecretKeyAttributes},
to:
algIndependentKey SecretKeyObject {SecretKeyAttributes},
and added:
genericSecretKey [15] SecretKeyObject {GenericKeyAttributes},

You may need to read PKCS#15 and 7816-15 to see if this is just a name change (GenericSecretKeyAttributes to SecretKeyAttributes) or someting else.
PKCS#15 "6.5.2 Generic secret key objects" and "6.5.3 Tagged key objects" might help.

Are there any existing PKCS#15 cards that actually store secret keys?

@dengert
Copy link
Member

dengert commented Dec 5, 2015

One more thing. (I don't have a copy of 7816-15) but would sepeculate that GenericKeyAttributes
are a sequence with an OID. For example 2.16.840.1.101.3.4.1 for AES.
http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants