From 9b25b05d7aa4a816cfa06f4750cb600cb94e27b7 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Wed, 18 Nov 2009 17:30:31 +0000 Subject: Add support for checking AES keys and DH derive --- src/dh.c | 131 ++++++++++++++++++++++++++ src/key.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/p11-tests-lib.h | 2 + 3 files changed, 383 insertions(+), 7 deletions(-) diff --git a/src/dh.c b/src/dh.c index 3325caa..7016498 100644 --- a/src/dh.c +++ b/src/dh.c @@ -7,6 +7,137 @@ #include +static int +compare_secret_values (void *one, size_t n_one, void *two, size_t n_two) +{ + if (n_one > n_two) + return memcmp (one + (n_one - n_two), two, n_two); + else + return memcmp (one, two + (n_two - n_one), n_one); +} + +static DH* +generate_peer_dh (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key) +{ + CK_ATTRIBUTE attrs[2]; + CK_BYTE prime[16384]; + CK_BYTE base[1024]; + DH *dh; + + attrs[0].type = CKA_PRIME; + attrs[0].ulValueLen = sizeof (prime); + attrs[0].pValue = prime; + + attrs[1].type = CKA_BASE; + attrs[1].ulValueLen = sizeof (base); + attrs[1].pValue = base; + + if (!p11t_object_get (session, key, attrs, 2)) + return NULL; + + if(attrs[0].ulValueLen == CK_INVALID || + attrs[1].ulValueLen == CK_INVALID) + return NULL; + + dh = DH_new (); + dh->p = BN_bin2bn (prime, attrs[0].ulValueLen, NULL); + dh->g = BN_bin2bn (base, attrs[1].ulValueLen, NULL); + assert(dh && dh->p && dh->g); + + if (!DH_generate_key (dh)) { + DH_free (dh); + return NULL; + } + + return dh; +} + +int +test_dh_private_derive (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE pub, CK_OBJECT_HANDLE prv) +{ + CK_ATTRIBUTE attrs[3]; + CK_KEY_TYPE key_type = CKK_AES; + CK_OBJECT_CLASS klass = CKO_SECRET_KEY; + CK_BYTE buffer[16384]; + CK_BYTE value[16384]; + CK_OBJECT_HANDLE derived; + CK_MECHANISM mech; + BIGNUM *our_pub; + CK_RV rv; + DH *dh; + + P11T_SECTION("C_DeriveKey"); + + /* Setup peer's DH */ + dh = generate_peer_dh (session, pub); + if (dh == NULL) + p11t_check_warn ("Couldn't retrieve DH parameters from DH pub key"); + + /* Dig out our public key */ + attrs[0].type = CKA_VALUE; + attrs[0].pValue = value; + attrs[0].ulValueLen = sizeof (value); + if (p11t_object_get (session, pub, attrs, 1)) { + our_pub = BN_bin2bn (value, attrs[0].ulValueLen, NULL); + } else { + p11t_check_warn ("Couldn't retrieve DH public value from DH pub key"); + our_pub = NULL; + } + + mech.mechanism = CKM_DH_PKCS_DERIVE; + mech.pParameter = buffer; + mech.ulParameterLen = BN_num_bytes (dh->pub_key); + BN_bn2bin (dh->pub_key, buffer); + + /* TODO: How can we know this key type is supported? */ + attrs[0].type = CKA_KEY_TYPE; + attrs[0].pValue = &key_type; + attrs[0].ulValueLen = sizeof (key_type); + + attrs[1].type = CKA_CLASS; + attrs[1].pValue = &klass; + attrs[1].ulValueLen = sizeof (klass); + + rv = (p11t_module_funcs->C_DeriveKey) (session, &mech, prv, attrs, 2, &derived); + P11T_CHECK_RV ("CKM_DH_PKCS_DERIVE", rv, CKR_OK); + + /* Compare to our generated key */ + attrs[0].type = CKA_VALUE; + attrs[0].pValue = value; + attrs[0].ulValueLen = sizeof (value); + if (p11t_object_get (session, derived, attrs, 1) && attrs[0].ulValueLen != (CK_ULONG)-1 && + dh != NULL && our_pub != NULL) { + if (!DH_compute_key (buffer, our_pub, dh)) + assert (0); + if (compare_secret_values (value, attrs[0].ulValueLen, buffer, DH_size (dh)) != 0) + P11T_CHECK_FAIL_MSG ("CKM_DH_PKCS_DERIVE", "Derived key has wrong secret value"); + } + + BN_free (our_pub); + DH_free (dh); + + return p11t_key_test (session, derived, CKO_SECRET_KEY); +} + +int +p11t_dh_test_key_pair (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE pub, CK_OBJECT_HANDLE prv) +{ + CK_ULONG mechanisms[128]; + CK_ATTRIBUTE attr = { CKA_ALLOWED_MECHANISMS, mechanisms, sizeof (mechanisms) }; + CK_ULONG i; + + /* Let's see if it support derivation */ + if (!p11t_object_get (session, prv, &attr, 1)) + return STOP; + + for (i = 0; i < attr.ulValueLen / sizeof (CK_ULONG); ++i) { + if (mechanisms[i] == CKM_DH_PKCS_DERIVE) + test_dh_private_derive (session, pub, prv); + } + + return CONTINUE; +} + static void test_dh_key_pair_gen (CK_SLOT_ID slot, CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR info) { diff --git a/src/key.c b/src/key.c index a305215..41f66f4 100644 --- a/src/key.c +++ b/src/key.c @@ -1,6 +1,8 @@ #include "p11-tests-lib.h" +#include + /* ---------------------------------------------------------------------------------- * TESTS */ @@ -265,6 +267,102 @@ test_private_attributes(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) return CONTINUE; } +static int +test_secret_attributes (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) +{ + CK_ATTRIBUTE attr; + CK_BBOOL bval; + CK_RV rv; + + attr.type = CKA_SENSITIVE; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_SENSITIVE", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_SENSITIVE", bval); + + attr.type = CKA_ENCRYPT; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_ENCRYPT", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_ENCRYPT", bval); + + attr.type = CKA_DECRYPT; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_DECRYPT", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_DECRYPT", bval); + + attr.type = CKA_SIGN; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_SIGN", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_SIGN", bval); + + attr.type = CKA_VERIFY; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_VERIFY", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_VERIFY", bval); + + attr.type = CKA_WRAP; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_WRAP", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_WRAP", bval); + + attr.type = CKA_UNWRAP; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_UNWRAP", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_UNWRAP", bval); + + attr.type = CKA_EXTRACTABLE; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_EXTRACTABLE", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_EXTRACTABLE", bval); + + attr.type = CKA_ALWAYS_SENSITIVE; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_ALWAYS_SENSITIVE", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_ALWAYS_SENSITIVE", bval); + + attr.type = CKA_NEVER_EXTRACTABLE; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_NEVER_EXTRACTABLE", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_NEVER_EXTRACTABLE", bval); + + if(p11t_test_unexpected) { + attr.type = CKA_WRAP_WITH_TRUSTED; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_WRAP_WITH_TRUSTED", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_WRAP_WITH_TRUSTED", bval); + } + + attr.type = CKA_TRUSTED; + attr.pValue = &bval; + attr.ulValueLen = sizeof (bval); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_TRUSTED", rv, CKR_OK); + P11T_CHECK_BOOL ("CKA_TRUSTED", bval); + + return CONTINUE; +} + static int test_rsa_public(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) { @@ -702,6 +800,73 @@ test_dh_private (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) return CONTINUE; } +static int +test_aes_secret (session, object) +{ + CK_ATTRIBUTE attr; + CK_BYTE buffer[16384]; + CK_BYTE check[1024]; + EVP_CIPHER_CTX ctx; + CK_ULONG length; + void *plaintext; + int outlen; + CK_RV rv; + + P11T_SECTION ("CKK_AES Secret"); + + attr.type = CKA_CHECK_VALUE; + attr.pValue = check; + attr.ulValueLen = sizeof (check); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_CHECK_VALUE", rv, CKR_OK); + if (attr.ulValueLen != 3) + P11T_CHECK_FAIL_MSG ("CKA_CHECK_VALUE", "Should be 3 bytes"); + + attr.type = CKA_VALUE_LEN; + attr.pValue = &length; + attr.ulValueLen = sizeof (length); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + P11T_CHECK_RV ("CKA_VALUE_LEN", rv, CKR_OK); + + attr.type = CKA_VALUE; + attr.pValue = buffer; + attr.ulValueLen = sizeof (buffer); + rv = (p11t_module_funcs->C_GetAttributeValue) (session, object, &attr, 1); + if (rv != CKR_ATTRIBUTE_SENSITIVE) { + P11T_CHECK_RV ("CKA_VALUE", rv, CKR_OK); + + if (length != attr.ulValueLen) + P11T_CHECK_FAIL_MSG ("CKA_VALUE_LEN", "Should match the length of CKA_VALUE"); + + switch (attr.ulValueLen) { + case 16: + EVP_EncryptInit (&ctx, EVP_aes_128_ecb (), buffer, NULL); + break; + case 24: + EVP_EncryptInit (&ctx, EVP_aes_192_ecb (), buffer, NULL); + break; + case 32: + EVP_EncryptInit (&ctx, EVP_aes_256_ecb (), buffer, NULL); + break; + default: + P11T_CHECK_FAIL_MSG ("CKA_VALUE", "Length should be 16, 24 or 32 bytes"); + break; + }; + + plaintext = calloc (attr.ulValueLen, 1); + if (!EVP_EncryptUpdate (&ctx, buffer, &outlen, plaintext, attr.ulValueLen)) + assert (0); + assert (outlen == attr.ulValueLen); + + EVP_CIPHER_CTX_cleanup (&ctx); + + if (memcmp (check, buffer, 3) != 0) + P11T_CHECK_FAIL_MSG ("CKA_CHECK_VALUE", "Check value is not correct"); + + } + + return CONTINUE; +} static int test_rsa_public_create(CK_SESSION_HANDLE session, CK_BBOOL token, RSA *rsa, CK_OBJECT_HANDLE_PTR result) @@ -1127,19 +1292,83 @@ test_dh_create(CK_SESSION_HANDLE session, CK_BBOOL token) test_dh_public_create (session, token, dh, &pub); test_dh_private_create (session, token, dh, &prv); + if (pub != 0 && prv != 0) + p11t_dh_test_key_pair (session, pub, prv); + + P11T_SECTION ("C_DestroyObject"); + + rv = (p11t_module_funcs->C_DestroyObject) (session, pub); + P11T_CHECK_RV ("DH Public Key", rv, CKR_OK); + rv = (p11t_module_funcs->C_DestroyObject) (session, prv); + P11T_CHECK_RV ("DH Private Key", rv, CKR_OK); + + DH_free (dh); + return CONTINUE; +} + +static int +test_aes_secret_create (CK_SESSION_HANDLE session, CK_BBOOL token, void *value, + size_t length, CK_OBJECT_HANDLE_PTR result) +{ + CK_OBJECT_HANDLE object; + CK_ATTRIBUTE attrs[10]; + CK_KEY_TYPE key_type = CKK_AES; + CK_OBJECT_CLASS klass = CKO_SECRET_KEY; + CK_RV rv; + + P11T_SECTION("C_CreateObject"); + + /* Fill in all the attributes */ + attrs[0].type = CKA_TOKEN; + attrs[0].pValue = &token; + attrs[0].ulValueLen = sizeof (token); + + attrs[1].type = CKA_CLASS; + attrs[1].ulValueLen = sizeof (klass); + attrs[1].pValue = &klass; + + attrs[2].type = CKA_LABEL; + attrs[2].pValue = "Test AES Secret Key"; + attrs[2].ulValueLen = 20; + + attrs[3].type = CKA_KEY_TYPE; + attrs[3].pValue = &key_type; + attrs[3].ulValueLen = sizeof (key_type); + + attrs[4].type = CKA_VALUE; + attrs[4].ulValueLen = length; + attrs[4].pValue = value; + + rv = (p11t_module_funcs->C_CreateObject) (session, attrs, 5, &object); + if (rv == CKR_TEMPLATE_INCOMPLETE) + return CONTINUE; + P11T_CHECK_RV ("AES Secret Key", rv, CKR_OK); + + p11t_key_test (session, object, CKO_SECRET_KEY); + *result = object; + return CONTINUE; +} + +static int +test_aes_create (CK_SESSION_HANDLE session, CK_BBOOL token) +{ + CK_OBJECT_HANDLE key; + CK_RV rv; + + key = 0; + if (!test_aes_secret_create (session, token, "0123456789ABCDEF", 16, &key)) + return STOP; + #if 0 if (pub != 0) - p11t_dh_test_public_key (session, pub); - if (prv != 0) - p11t_dh_test_private_key (session, prv); + p11t_aes_test_secret_key (session, key); #endif - P11T_SECTION("C_DestroyObject"); + P11T_SECTION ("C_DestroyObject"); - rv = (p11t_module_funcs->C_DestroyObject)(session, pub); - P11T_CHECK_RV("DH Public Key", rv, CKR_OK); + rv = (p11t_module_funcs->C_DestroyObject) (session, key); + P11T_CHECK_RV ("AES Secret Key", rv, CKR_OK); - DH_free (dh); return CONTINUE; } @@ -1216,6 +1445,10 @@ p11t_key_test (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_OBJECT_CLA test_dsa_public (session, object); else if (key_type == CKK_DH) test_dh_public (session, object); + } else if (key_class == CKO_SECRET_KEY) { + test_secret_attributes (session, object); + if (key_type == CKK_AES) + test_aes_secret (session, object); } } @@ -1268,6 +1501,16 @@ p11t_key_tests(void) test_dsa_create (session, CK_FALSE); test_dh_create (session, CK_FALSE); } + + klass = CKO_SECRET_KEY; + objects = p11t_object_find (session, attrs, 1, &n_objects); + for (i = 0; objects && i < n_objects; ++i) + p11t_key_test (session, objects[i], klass); + free (objects); + + if (p11t_test_write_session) { + test_aes_create (session, CK_FALSE); + } } p11t_session_close(session); diff --git a/src/p11-tests-lib.h b/src/p11-tests-lib.h index 500f75c..c7368d9 100644 --- a/src/p11-tests-lib.h +++ b/src/p11-tests-lib.h @@ -18,6 +18,7 @@ #include #include +#include #define CK_INVALID ((CK_ULONG)-1) @@ -140,6 +141,7 @@ int p11t_dh_test_generate_pair (CK_SESSION_HANDLE session); void p11t_dh_tests (void); int p11t_dh_test_generate_pair (CK_SESSION_HANDLE session); +int p11t_dh_test_key_pair (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE pub, CK_OBJECT_HANDLE prv); /* ------------------------------------------------------------------- * key.c -- cgit v1.2.3