From 3d8ed01d2653c45e52821ba00ac72099a12600e1 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Fri, 27 Apr 2007 03:19:46 +0000 Subject: --- ckcapi-object.c | 655 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 655 insertions(+) create mode 100644 ckcapi-object.c (limited to 'ckcapi-object.c') diff --git a/ckcapi-object.c b/ckcapi-object.c new file mode 100644 index 0000000..531ad2f --- /dev/null +++ b/ckcapi-object.c @@ -0,0 +1,655 @@ + +#include "cryptoki-capi.h" + +#include +#include + +enum +{ + DATA_UNKNOWN = 0, + DATA_BOOL, + DATA_ULONG, + DATA_DATE, + DATA_BYTES +}; + + +int +attribute_data_type(CK_ATTRIBUTE_TYPE type) +{ + switch(type) + { + // CK_ULONG attribute types + case CKA_CLASS: + case CKA_CERTIFICATE_TYPE: + case CKA_CERTIFICATE_CATEGORY: + case CKA_KEY_TYPE: + case CKA_MODULUS_BITS: + case CKA_PRIME_BITS: + case CKA_SUBPRIME_BITS: + case CKA_SUB_PRIME_BITS: + case CKA_VALUE_BITS: + case CKA_VALUE_LEN: + case CKA_KEY_GEN_MECHANISM: + case CKA_HW_FEATURE_TYPE: + case CKA_PIXEL_X: + case CKA_PIXEL_Y: + case CKA_RESOLUTION: + case CKA_CHAR_ROWS: + case CKA_CHAR_COLUMNS: + case CKA_BITS_PER_PIXEL: + case CKA_MECHANISM_TYPE: + case CKA_JAVA_MIDP_SECURITY_DOMAIN: + return DATA_ULONG: + + // CK_BBOOL attribute types + case CKA_TOKEN: + case CKA_PRIVATE: + case CKA_MODIFIABLE: + case CKA_TRUSTED: + case CKA_SENSITIVE: + case CKA_DECRYPT: + case CKA_SIGN: + case CKA_SIGN_RECOVER: + case CKA_UNWRAP: + case CKA_EXTRACTABLE: + case CKA_NEVER_EXTRACTABLE: + case CKA_ALWAYS_SENSITIVE: + case CKA_WRAP_WITH_TRUSTED: + case CKA_ALWAYS_AUTHENTICATE + case CKA_ENCRYPT: + case CKA_WRAP: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + case CKA_DERIVE: + case CKA_LOCAL: + case CKA_RESET_ON_INIT: + case CKA_HAS_RESET: + case CKA_COLOR: + return DATA_BOOL; + + // Raw or string data + case CKA_LABEL: + case CKA_APPLICATION: + case CKA_VALUE: + case CKA_OBJECT_ID: + case CKA_CHECK_VALUE: + case CKA_ISSUER: + case CKA_SERIAL_NUMBER: + case CKA_SUBJECT: + case CKA_ID: + case CKA_URL: + case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: + case CKA_HASH_OF_ISSUER_PUBLIC_KEY: + case CKA_AC_ISSUER: + case CKA_OWNER: + case CKA_ATTR_TYPES: + case CKA_MODULUS: + case CKA_PUBLIC_EXPONENT: + case CKA_PRIVATE_EXPONENT: + case CKA_PRIME_1: + case CKA_PRIME_2: + case CKA_EXPONENT_1: + case CKA_EXPONENT_2: + case CKA_COEFFICIENT: + case CKA_PRIME: + case CKA_SUBPRIME: + case CKA_BASE: + case CKA_ECDSA_PARAMS: + case CKA_EC_PARAMS: + case CKA_EC_POINT: + case CKA_CHAR_SETS: + case CKA_ENCODING_METHODS: + case CKA_MIME_TYPES: + case CKA_REQUIRED_CMS_ATTRIBUTES: + case CKA_DEFAULT_CMS_ATTRIBUTES: + case CKA_SUPPORTED_CMS_ATTRIBUTES: + return DATA_BYTES; + + // CK_DATE data + case CKA_START_DATE: + case CKA_END_DATE: + return DATA_DATE; + + // Arrays are nasty + case CKA_WRAP_TEMPLATE: + case CKA_ALLOWED_MECHANISMS: + case CKA_UNWRAP_TEMPLATE: + default: + return DATA_UNKNOWN; + }; +} + +CK_RV +attribute_fill(CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_TYPE type, + CK_VOID_PTR* val, CK_ULONG len) +{ + ASSERT(attr); + ASSERT(val); + ASSERT(len); + + attr->type = type; + + if(attr->pValue && attr->ulValueLen < len) + { + attr->ulValueLen = len; + return CKR_BUFFER_TOO_SMALL; + } + + else if(!attr->pValue) + { + attr->ulValueLen = len; + return CKR_OK; + } + + else + { + memcpy(attr->pValue, &val, len); + attr->ulValueLen = len; + return CKR_OK; + } +} + +CK_RV +attribute_match(CK_ATTRIBUTE_PTR attr, CK_ATTRIBUTE_TYPE type, + CK_VOID_PTR* val, CK_ULONG len) +{ + ASSERT(attr); + ASSERT(val); + ASSERT(len); + + if(attr->pValue && attr->ulValueLen == len && + memcmp(attr->pValue, &val, len); + return CKR_OK; + return CKR_CANCEL; +} + +/* -------------------------------------------------------------------------- + * CERTIFICATES + */ + +static CK_RV +cert_bool_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert, + CK_ATTRIBUTE_PTR attr, CK_BBOOL fill) +{ + CK_BBOOL val; + switch(type) + { + /* + * Resides on the token + * - Always true for CAPI objects. + */ + case CKA_TOKEN: + val = CK_TRUE; + break; + + /* + * Private vs. Public object. + * - Always false for certificates. + */ + case CKA_PRIVATE: + val = CK_FALSE; + break; + + /* + * If object can be modified. + * - Currently always false. In the future with additional + * functionality this may change. + */ + case CKA_MODIFIABLE: + val = CK_FALSE; + break; + + /* + * Whether the certificate can be trusted for the application + * in which it was created. + * - Use CertGetCertificateChain to build up a chain + * for this certificate, and then look in the CERT_CHAIN_CONTEXT + * TrustStatus field. + */ + case CKA_TRUSTED: + /* TODO: Implement */ + + default: + return CK_CANCEL; + }; + + if(fill) + return attribute_fill(attr, type, &val, sizeof(CK_BBOOL)); + else + return attribute_match(attr, type, &val, sizeof(CK_BBOOL)); +} + +static CK_RV +cert_ulong_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert, + CK_ATTRIBUTE_PTR attr, CK_BBOOL fill) +{ + CK_ULONG val; + switch(type) + { + + /* + * Object class. + * - Always CKO_CERTIFICATE for certificates. + */ + case CKA_OBJECT_CLASS: + val = CKO_CERTIFICATE; + break; + + /* + * Type of certificate. + * - Always X509. + */ + case CKA_CERTIFICATE_TYPE: + val = CKC_X_509; + break; + + /* + * Whether a CA, user certificate, other. + * - Get certificate szOID_ENHANCED_KEY_USAGE + * extension or CERT_CTL_PROP_ID and look into CTL_USAGE structure. + */ + case CKA_CERTIFICATE_CATEGORY: + /* TODO: Implement */ + + default: + return CK_CANCEL; + }; + + if(fill) + return attribute_fill(attr, type, &val, sizeof(CK_ULONG)); + else + return attribute_match(attr, type, &val, sizeof(CK_ULONG)); +} + +static CK_RV +cert_bytes_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert, + CK_ATTRIBUTE_PTR attr, CK_BBOOL fill) +{ + switch(type) + { + + /* + * Description of the object. + * - We use CAPI's CERT_FRIENDLY_NAME_PROP_ID property, + * converted into UTF8. + */ + case CKA_LABEL: + xxxxx + break; + + /* + * A byte array unique to this certificate. The CKA_ID of + * matching certificates and private keys should match. + * Should match the key identifier in an X.509v3 certificate. + * + * We use CAPI's CERT_KEY_IDENTIFIER_PROP_ID property directly. + */ + case CKA_ID: + xxxxx + break; + + /* + * DER-encoding of the certificate subject name. + * + * We use CAPI's CERT_CONTEXT pCertInfo->Subject field + * directly. + */ + case CKA_SUBJECT: + xxxxx + break; + + /* + * DER-encoding of the certificate issuer name. + * + * We use CAPI's CERT_CONTEXT pCertInfo->Issuer field + * directly. + */ + case CKA_ISSUER: + xxxxx + break; + + /* + * DER-encoding of the certificate serial number. + * + * TODO: + * BOOL rc = CryptEncodeObject(X509_ASN_ENCODING, + * X509_MULTI_BYTE_INTEGER, + * &certContext->pCertInfo->SerialNumber, + * co->derSerial, + * &size); + */ + case CKA_SERIAL_NUMBER: + xxxxx + break; + + /* + * BER-encoding of the full certificate. + * + * We use CAPI's CERT_CONTEXT pbCertEncoded field directly. + */ + case CKA_VALUE: + xxxxx + break; + + /* + * If CKA_VALUE not specified, this is where the full + * certificate can be found. + * + * We don't support this. All our certificates are present + * in full. + */ + case CKA_URL: + break; + + /* + * Checksum + * - TODO: Work out what to do here + */ + case CKA_CHECKSUM: + break; + + /* + * TODO: Should we support these? + */ + CKA_HASH_OF_SUBJECT_PUBLIC_KEY + CKA_HASH_OF_ISSUER_PUBLIC_KEY + break; + + /* Not supported */ + + default: + break + }; +}; + +static xxx +cert_date_attribute() +{ + switch(type) + { + + /* + * Start date for the certificate. + * - TODO: Work out where to get this. + */ + pCertInfo->NotBefore; + case CKA_START_DATE: + xxxx; + break; + + /* + * End date for the certificate. + * - TODO: Work out where to get this. + */ + pCertInfo->NotAfter; + case CKA_END_DATE: + xxxx; + break; + }; +} +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +static CK_RV +cert_ulong_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert, + CK_ATTRIBUTE_PTR attr) +{ + CK_ATTRIBUTE_PTR ret; + CK_BBOOL val; + + switch(type) + { + case CKA_TOKEN: + val = CK_TRUE; + break; + case CKA_PRIVATE: + case CKA_MODIFIABLE: + val = CK_FALSE; + break; + }; + + /* If attr is initialized, just do a match */ + if(attr.type == type) + { + if(attr->pValue && attr->ulValueLen == sizeof(CK_BBOOL) && + memcmp(attr->pValue, &val, sizeof(CK_BBOOL)); + return CKR_OK; + return CKR_CANCEL; + } + + /* Otherwise fill in the value */ + else + { + return prep_attribute(attr, type, &val, sizeof(CK_BBOOL); + } +} + +static CK_ATTRIBUTE_PTR +cert_load_attribute(CK_ATTRIBUTE_TYPE type, PCCERT_CONTEXT cert) +{ + CK_BBOOL vval = CK_FALSE; + CK_ULONG uval = 0; + CK_VOID_PTR val; + CK_ULONG n_val; + + switch(type) + { + case CKA_CLASS: + uval = CKO_CERTIFICATE; + break; + case CKA_TOKEN; + + } +} + +static CK_BBOOL +cert_match_attr(CK_ATTRIBUTE_PTR match, PCCERT_CONTEXT cert) +{ + CK_ATTRIBUTE_PTR attr; + CK_BBOOL ret; + + attr = cert_load_attribute(match->type, cert); + if(!attr) + return CK_FALSE; + + ret = (attr->ulValueLen == match->ulValueLen && + memcmp(attr->pValue, match->pValue, attr->ulValueLen) == 0); + + free_attribute(attr); + return ret; +} + +static CK_BBOOL +cert_match(CK_ATTRIBUTE_PTR matches, CK_ULONG count, + PCCERT_CONTEXT cert) +{ + CK_ULONG i; + + for(i = 0; i < count; ++i) + { + if(!cert_match_attr(&match[i], cert)) + return CK_FALSE; + } + + return CK_TRUE; +} + +static CK_RV +gather_store_certs(const char* store_name, Array* arr, + CK_ATTRIBUTE_PTR match, CK_ULONG count) +{ + PCCERT_CONTEXT cert = NULL; + CK_OBJECT_HANDLE obj; + HCERTSTORE store; + DWORD err; + CK_RV ret = CKR_OK; + + store = CertOpenSystemStore((HCRYPTPROV)NULL, store_name); + if(store == NULL) + { + err = GetLastError(); + + /* Store not found, we don't care */ + if(err == ERROR_FILE_NOT_FOUND) + return CKR_OK; + + else + return ckcapi_winerr_to_ckr(err); + } + + /* Match each certificate */ + while((cert = CertEnumCertificatesInStore(store, cert)) != NULL) + { + if(match_cert(match, count, cert)) + { + obj = register_cert(store, cert); + if(!obj) + { + ret = CKR_HOST_MEMORY; + break; + } + + ckcapi_util_array_append(arr, obj); + } + } + + ASSERT(store); + CertCloseStore(store, 0); + + return ret; +} + +/* ---------------------------------------------------------------------------- + * FIND + */ + +BOOL +get_ulong_attribute(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR templ, + CK_ULONG count, CK_ULONG* val) +{ + CK_ULONG i; + + ASSERT(val); + ASSERT(!count || templ); + + for(i = 0; i < count; ++i) + { + if(templ[i].type == type) + { + *val = *((CK_ULONG*)templ[i].pValue); + return TRUE; + } + } + + return FALSE; +} + + + + +CK_RV +gather_objects(Array* arr, CK_ATTRIBUTE_PTR match, CK_ULONG count) +{ + CK_OBJECT_CLASS ocls = CK_INVALID_HANDLE; + CK_RV ret = CKR_OK; + + get_ulong_attribute(CKA_CLASS, match, count, &ocls); + switch(ocls) + { + /* all different classes */ + case CK_INVALID_HANDLE: + case CKO_CERTIFICATE: + ret = gather_certificates(arr, match, count); + break; + case CKO_PUBLIC_KEY: + case CKO_PRIVATE_KEY: + default: + break; + }; + + return ret; +} + +void +cleanup_find_operation(Session* sess) +{ + ASSERT(sess->operation_type == OPERATION_FIND); + if(sess->operation_data) + ckcapi_util_array_free((Array*)sess->operation_data, TRUE); + sess->operation_type = OPERATION_NONE; + sess->operation_data = NULL; + sess->operation_cancel = NULL; +} + +CK_RV +ckcapi_object_find_init(Session* sess, CK_ATTRIBUTE_PTR match, + CK_ULONG count) +{ + Array* arr; + CK_RV ret; + + ASSERT(sess); + ASSERT(!count || match); + + if(sess->operation_type != OPERATION_NONE) + return CKR_OPERATION_ACTIVE; + + arr = ckcapi_util_array_new(0, 1, sizeof(CK_OBJECT_HANDLE)); + if(!arr) + return CKR_HOST_MEMORY; + + ret = gather_objects(arr, match, count); + if(ret != CKR_OK) + { + ckcapi_util_array_free(arr, TRUE); + return ret; + } + + sess->operation_type = OPERATION_FIND; + sess->operation_data = arr; + sess->operation_cancel = cleanup_find_operation; + + return CKR_OK; +} + +CK_RV +ckcapi_object_find(Session* sess, CK_OBJECT_HANDLE_PTR objects, + CK_ULONG max_object_count, CK_ULONG_PTR object_count) +{ + Array* arr; + size_t i; + + ASSERT(sess); + ASSERT(object_count); + ASSERT(!max_object_count || objects); + + if(sess->operation_type != OPERATION_FIND) + return CKR_OPERATION_NOT_INITIALIZED; + + if(!max_object_count) + { + *object_count = 0; + return CKR_OK; + } + + arr = (Array*)sess->operation_data; + *object_count = (max_object_count > arr->len ? arr->len : max_object_count); + for(i = 0; i < *object_count; ++i) + objects[i] = ckcapi_util_array_index(arr, CK_OBJECT_HANDLE, i); + ckcapi_util_array_remove_range(arr, 0, *object_count); + + return CKR_OK; +} + +CK_RV +ckcapi_objects_find_final(Session* sess) +{ + ASSERT(sess); + + if(sess->operation_type != OPERATION_FIND) + return CKR_OPERATION_NOT_INITIALIZED; + + cleanup_find_operation(sess); + return CKR_OK; +} + -- cgit v1.2.3