summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2008-12-02 20:49:19 +0000
committerStef Walter <stef@memberwebs.com>2008-12-02 20:49:19 +0000
commitc92e343c53743180c8854cb10da8bf522dd43d76 (patch)
tree3eb5527afeab8ef34cc3319cd8928c12614e8f65
parente7d5c6b4b04bb34172788fba5532b89e70a1f5ac (diff)
Load certificates by key ID if finding by CKA_ID. Use standard function for returning a string.
-rw-r--r--ckcapi-cert.c201
-rw-r--r--ckcapi.c49
-rw-r--r--ckcapi.h7
3 files changed, 151 insertions, 106 deletions
diff --git a/ckcapi-cert.c b/ckcapi-cert.c
index ebb34ff..6e51f3e 100644
--- a/ckcapi-cert.c
+++ b/ckcapi-cert.c
@@ -309,46 +309,25 @@ ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
WCHAR* utf16 = NULL;
DWORD size;
- /* Get the UTF16 string, a worst case of twice as long as UTF8 */
- if(data)
- {
- size = *len * sizeof(WCHAR);
- utf16 = _alloca(size);
- }
-
- if(!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
- utf16, &size))
+ if(!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &size))
{
err = GetLastError();
if(err == CRYPT_E_NOT_FOUND)
- utf16 = L"";
+ utf16 = L"Unnamed Certificate";
else
return ckcapi_winerr_to_ckr(err);
}
- if(utf16)
+ if(!utf16)
{
- /* Always have a default name */
- if(!utf16[0])
- {
- utf16 = L"Unnamed Certificate";
- size = wcslen(utf16) * 2;
- }
-
- /* Convert the data into the buffer */
- *len = WideCharToMultiByte(CP_UTF8, 0, utf16, size / sizeof(WCHAR),
- data, *len, NULL, NULL);
- if(!*len)
+ utf16 = _alloca(size);
+ if(!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, utf16, &size))
return ckcapi_winerr_to_ckr(GetLastError());
}
- else
- {
- /* Just return an appropriate allocation length */
- *len = (size / sizeof(WCHAR)) + sizeof(WCHAR);
- }
+ return ckcapi_return_string(data, len, utf16);
}
- return CKR_OK;
+ break;
/*
* A byte array unique to this certificate. The CKA_ID of
@@ -417,7 +396,7 @@ ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
*/
case CKA_VALUE:
return ckcapi_return_data(data, len, cert->pbCertEncoded,
- cert->cbCertEncoded);
+ cert->cbCertEncoded);
/*
* If CKA_VALUE not specified, this is where the full
@@ -514,22 +493,36 @@ register_cert_object(CkCapiSession* sess, PCCERT_CONTEXT cert, CkCapiObject** ob
}
static CK_RV
-find_in_store(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
- CK_ULONG count, CkCapiArray* arr)
+find_in_store(CkCapiSession* sess, DWORD find_type, const void *find_criteria,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
{
PCCERT_CONTEXT cert = NULL;
CkCapiObject* obj;
- CertObjectData cdata;
CkCapiObjectData* objdata;
+ CertObjectData cdata;
+ DWORD err;
CK_RV ret = CKR_OK;
/* No store, no objects */
if(!sess->store)
return CKR_OK;
- /* Match each certificate */
- while((cert = CertEnumCertificatesInStore(sess->store, cert)) != NULL)
+ for(;;)
{
+ cert = CertFindCertificateInStore(sess->store, CKCAPI_ENCODINGS, 0,
+ find_type, find_criteria, cert);
+ if(cert == NULL)
+ {
+ err = GetLastError();
+
+ /* Certificate not found, we don't care */
+ if(err == CRYPT_E_NOT_FOUND)
+ return CKR_OK;
+ else
+ return ckcapi_winerr_to_ckr(err);
+ }
+
+ /* Match the certificate */
cdata.cert = cert;
cdata.base.object = 0;
cdata.base.data_funcs = &cert_objdata_vtable;
@@ -537,72 +530,22 @@ find_in_store(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
if(ckcapi_object_data_match(&cdata.base, match, count))
{
ret = register_cert_object(sess, cert, &obj);
- if(ret != CKR_OK)
- break;
-
- ASSERT(obj);
-
- /* Store away the object data for performance reasons */
- objdata = cert_alloc_data(sess, obj, cert);
- if(objdata)
+ if(ret == CKR_OK)
{
- ckcapi_session_take_object_data(sess, obj, objdata);
-
- /* For continuing the enumeration */
- cert = CertDuplicateCertificateContext(cert);
- }
-
- ckcapi_array_append(arr, obj->id);
- }
- }
-
- return ret;
-}
-
-static CK_RV
-match_in_store(CkCapiSession* sess, PCERT_INFO info, CK_ATTRIBUTE_PTR match,
- CK_ULONG count, CkCapiArray* arr)
-{
- PCCERT_CONTEXT cert = NULL;
- CkCapiObject* obj;
- CkCapiObjectData* objdata;
- CertObjectData cdata;
- DWORD err;
- CK_RV ret = CKR_OK;
-
- /* No store, no objects */
- if(!sess->store)
- return CKR_OK;
-
- cert = CertGetSubjectCertificateFromStore(sess->store, CKCAPI_ENCODINGS, info);
- if(cert == NULL)
- {
- err = GetLastError();
+ ASSERT(obj);
- /* Certificate not found, we don't care */
- if(err == CRYPT_E_NOT_FOUND)
- return CKR_OK;
- else
- return ckcapi_winerr_to_ckr(err);
- }
-
- /* Match the certificate */
- cdata.cert = cert;
- cdata.base.object = 0;
- cdata.base.data_funcs = &cert_objdata_vtable;
+ /* Store away the object data for performance reasons */
+ objdata = cert_alloc_data(sess, obj, cert);
+ if(objdata)
+ {
+ ckcapi_session_take_object_data(sess, obj, objdata);
- if(ckcapi_object_data_match(&cdata.base, match, count))
- {
- ret = register_cert_object(sess, cert, &obj);
- if(ret == CKR_OK)
- {
- ASSERT(obj);
+ /* For continuing the enumeration */
+ cert = CertDuplicateCertificateContext(cert);
+ }
- /* Store away the object data for performance reasons */
- objdata = cert_alloc_data(sess, obj, cert);
- if(objdata)
- ckcapi_session_take_object_data(sess, obj, objdata);
- ckcapi_array_append(arr, obj->id);
+ ckcapi_array_append(arr, obj->id);
+ }
}
}
@@ -617,20 +560,46 @@ ckcapi_cert_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR matc
CK_ULONG count, CkCapiArray* arr)
{
CRYPT_INTEGER_BLOB* serial = NULL;
- CERT_INFO info;
CK_RV ret;
CK_ULONG i;
DWORD size;
+ CERT_INFO find_info; /* For searching by issuer and serial */
+ CRYPT_HASH_BLOB find_key; /* For searching by ID */
+
/* We only have certificates here */
if(cls != CKO_CERTIFICATE && cls != CKO_ANY)
return CKR_OK;
+ /* Only work with slots that have certificates */
+ if(!(ckcapi_token_get_flags (sess->slot) & CKCAPI_SLOT_CERTS))
+ return CKR_OK;
+
/*
+ * There are some better searches we can do rather than
+ * listing everything.
+ *
+ * CKA_ISSUER + CKA_SERIAL_NUMBER
* See if we have a issuer and serial number for a
* specific certificate to find.
+ *
+ * CKA_ID
+ * Search by key identifier
+ *
+ * TODO: could search by hash (use CertFindCertificateInStore
+ * with CERT_FIND_HASH or CERT_FIND_SHA1_HASH or CERT_FIND_MD5_HASH)
+ *
+ * TODO: could search by issuer (use CertFindCertificateInStore
+ * with CERT_FIND_ISSUER_NAME)
+ *
+ * TODO: could search by subject (use CertFindCertificateInStore
+ * with CERT_FIND_SUBJECT_NAME)
+ *
+ * TODO: could search by CKA_VALUE (use CertFindCertificateInStore
+ * with CERT_FIND_EXISTING)
*/
- memset(&info, 0, sizeof(info));
+ memset(&find_info, 0, sizeof(find_info));
+ memset(&find_key, 0, sizeof(find_key));
for(i = 0; i < count; ++i)
{
@@ -639,10 +608,11 @@ ckcapi_cert_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR matc
if(match[i].type == CKA_ISSUER)
{
- info.Issuer.cbData = match[i].ulValueLen;
- info.Issuer.pbData = match[i].pValue;
+ find_info.Issuer.cbData = match[i].ulValueLen;
+ find_info.Issuer.pbData = match[i].pValue;
}
- else if(!serial && match[i].type == CKA_SERIAL_NUMBER)
+
+ else if(match[i].type == CKA_SERIAL_NUMBER && !serial)
{
if(!CryptDecodeObject(CKCAPI_ENCODINGS, X509_MULTI_BYTE_INTEGER,
match[i].pValue, match[i].ulValueLen, 0, NULL, &size))
@@ -658,18 +628,37 @@ ckcapi_cert_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR matc
ASSERT(serial->cbData);
ASSERT(serial->pbData);
- info.SerialNumber.cbData = serial->cbData;
- info.SerialNumber.pbData = serial->pbData;
+ find_info.SerialNumber.cbData = serial->cbData;
+ find_info.SerialNumber.pbData = serial->pbData;
+ }
+
+ else if(match[i].type == CKA_ID)
+ {
+ find_key.cbData = match[i].ulValueLen;
+ find_key.pbData = match[i].pValue;
}
}
/* Match a specific certificate */
- if(info.SerialNumber.cbData && info.Issuer.cbData)
- ret = match_in_store(sess, &info, match, count, arr);
+ if(find_info.SerialNumber.cbData && find_info.Issuer.cbData)
+ {
+ ret = find_in_store(sess, CERT_FIND_SUBJECT_CERT, &find_info,
+ match, count, arr);
+ }
+
+ /* Find all certificates with key identifier */
+ else if(find_key.cbData)
+ {
+ ret = find_in_store(sess, CERT_FIND_KEY_IDENTIFIER, &find_key,
+ match, count, arr);
+ }
/* Match any ol certificate */
else
- ret = find_in_store(sess, match, count, arr);
+ {
+ ret = find_in_store(sess, CERT_FIND_ANY, NULL,
+ match, count, arr);
+ }
if(serial)
free(serial);
diff --git a/ckcapi.c b/ckcapi.c
index 1b6654e..9ea7815 100644
--- a/ckcapi.c
+++ b/ckcapi.c
@@ -160,6 +160,55 @@ ckcapi_return_data(CK_VOID_PTR dst, CK_ULONG_PTR dlen,
return CKR_OK;
}
+CK_RV
+ckcapi_return_string(CK_VOID_PTR dst, CK_ULONG_PTR dlen,
+ WCHAR* string)
+{
+ DWORD error;
+ int result;
+
+ SetLastError(0);
+
+ /*
+ * Sadly WideCharToMultiByte doesn't handle zero
+ * length strings properly. So we have to special
+ * case this part.
+ */
+ if(!string[0])
+ return ckcapi_return_data(dst, dlen, "\0", 1);
+
+ result = WideCharToMultiByte(CP_UTF8, 0, string, -1,
+ dst, dst ? *dlen : 0, NULL, NULL);
+
+
+ /* An error result somehow */
+ if(!result)
+ {
+ error = GetLastError();
+ switch(error)
+ {
+ /* If buffer was too short, calculate good buffer length */
+ case ERROR_INSUFFICIENT_BUFFER:
+ result = WideCharToMultiByte(CP_UTF8, 0, string, -1,
+ NULL, 0, NULL, NULL);
+ if(!result)
+ return CKR_GENERAL_ERROR;
+ *dlen = result;
+ return CKR_BUFFER_TOO_SMALL;
+
+ /* A strange zero length success */
+ case ERROR_SUCCESS:
+ break;
+
+ /* All other errors are not handleable */
+ default:
+ return CKR_GENERAL_ERROR;
+ }
+ }
+
+ *dlen = result;
+ return CKR_OK;
+}
/* ---------------------------------------------------------------- */
diff --git a/ckcapi.h b/ckcapi.h
index 5283cc4..707d7f8 100644
--- a/ckcapi.h
+++ b/ckcapi.h
@@ -91,6 +91,13 @@ CK_RV ckcapi_winerr_to_ckr (DWORD werr);
CK_RV ckcapi_return_data (CK_VOID_PTR dst, CK_ULONG_PTR dlen,
CK_VOID_PTR src, DWORD slen);
+/*
+ * This stores a string in the output buffer with appropriate
+ * PKCS#11 codes when the buffer is too short, or the caller
+ * just wants to know the length, etc.
+ */
+CK_RV ckcapi_return_string (CK_VOID_PTR dst, CK_ULONG_PTR dlen,
+ WCHAR* string);
/* ------------------------------------------------------------------ */