summaryrefslogtreecommitdiff
path: root/ckcapi-cert.c
diff options
context:
space:
mode:
Diffstat (limited to 'ckcapi-cert.c')
-rw-r--r--ckcapi-cert.c222
1 files changed, 161 insertions, 61 deletions
diff --git a/ckcapi-cert.c b/ckcapi-cert.c
index 0162983..887fefb 100644
--- a/ckcapi-cert.c
+++ b/ckcapi-cert.c
@@ -15,6 +15,18 @@
#define USE_ENCODINGS (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
+/* All the stores we look in for certificates, in this order */
+static const char* CERT_STORES[] = {
+ "My",
+ "AddressBook",
+ "CA",
+ "Root",
+ "Trust",
+ "TrustedPeople",
+ "AuthRoot",
+ NULL
+};
+
typedef struct _CertObject
{
CkCapiObject obj;
@@ -33,37 +45,6 @@ typedef struct _CertObject
}
CertObject;
-typedef struct _CertUnique
-{
- int otype;
- BYTE key[1];
-}
-CertUnique;
-
-static CK_RV
-copy_static_data(CK_VOID_PTR val, CK_ULONG_PTR len,
- CK_VOID_PTR data, DWORD cb)
-{
- if(cb == 0)
- return CKR_ATTRIBUTE_TYPE_INVALID;
-
- if(!val)
- {
- *len = cb;
- return CKR_OK;
- }
-
- if(cb > *len)
- {
- *len = cb;
- return CKR_BUFFER_TOO_SMALL;
- }
-
- *len = cb;
- memcpy(val, data, cb);
- return CKR_OK;
-}
-
static CK_RV
cert_bool_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
CK_VOID_PTR data, CK_ULONG_PTR len)
@@ -114,7 +95,7 @@ cert_bool_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
return CKR_ATTRIBUTE_TYPE_INVALID;
};
- return copy_static_data(data, len, &val, sizeof(CK_BBOOL));
+ return ckcapi_return_data(data, len, &val, sizeof(CK_BBOOL));
}
static CK_RV
@@ -163,12 +144,12 @@ cert_ulong_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
return CKR_BUFFER_TOO_SMALL;
}
- return copy_static_data(data, len, &val, sizeof(CK_ULONG));
+ return ckcapi_return_data(data, len, &val, sizeof(CK_ULONG));
}
-static CK_RV
-cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
- CK_VOID_PTR data, CK_ULONG_PTR len)
+CK_RV
+ckcapi_cert_get_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
+ CK_VOID_PTR data, CK_ULONG_PTR len)
{
PCCERT_CONTEXT cert = (PCCERT_CONTEXT)obj;
DWORD err;
@@ -258,7 +239,7 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
* directly.
*/
case CKA_SUBJECT:
- return copy_static_data(data, len, cert->pCertInfo->Subject.pbData,
+ return ckcapi_return_data(data, len, cert->pCertInfo->Subject.pbData,
cert->pCertInfo->Subject.cbData);
/*
@@ -268,7 +249,7 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
* directly.
*/
case CKA_ISSUER:
- return copy_static_data(data, len, cert->pCertInfo->Issuer.pbData,
+ return ckcapi_return_data(data, len, cert->pCertInfo->Issuer.pbData,
cert->pCertInfo->Issuer.cbData);
/*
@@ -298,7 +279,7 @@ cert_bytes_attribute(void* obj, CK_ATTRIBUTE_TYPE type,
* We use CAPI's CERT_CONTEXT pbCertEncoded field directly.
*/
case CKA_VALUE:
- return copy_static_data(data, len, cert->pbCertEncoded,
+ return ckcapi_return_data(data, len, cert->pbCertEncoded,
cert->cbCertEncoded);
/*
@@ -372,13 +353,13 @@ cert_release(void* data)
static const CkCapiObjectDataVtable cert_objdata_vtable = {
cert_bool_attribute,
cert_ulong_attribute,
- cert_bytes_attribute,
+ ckcapi_cert_get_bytes_attribute,
cert_date_attribute,
cert_release,
};
static CK_RV
-cert_load(CkCapiObject* obj, CkCapiObjectData* objdata)
+cert_load_data(CkCapiSession* sess, CkCapiObject* obj, CkCapiObjectData* objdata)
{
CertObject* cobj = (CertObject*)obj;
HCERTSTORE store;
@@ -419,6 +400,10 @@ cert_load(CkCapiObject* obj, CkCapiObjectData* objdata)
return ckcapi_winerr_to_ckr(GetLastError());
}
+ /*
+ * Important: The trust stuff depends on the objdata value of a
+ * certificate object is a CERT_CONTEXT pointer.
+ */
objdata->data = (void*)cert;
objdata->data_funcs = cert_objdata_vtable;
return CKR_OK;
@@ -434,7 +419,7 @@ cert_object_release(void* data)
}
static const CkCapiObjectVtable cert_object_vtable = {
- cert_load,
+ cert_load_data,
cert_object_release,
};
@@ -500,9 +485,9 @@ clear_object_data_for_store(CkCapiSession* sess, CkCapiObject* obj,
ckcapi_session_clear_object_data(sess, obj);
}
-CK_RV
-ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name,
- CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
+static CK_RV
+find_in_store(CkCapiSession* sess, const char* store_name,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
{
PCCERT_CONTEXT cert = NULL;
CkCapiObject* obj;
@@ -549,10 +534,73 @@ ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name,
CertFreeCertificateContext((PCCERT_CONTEXT)objdata.data);
}
- ckcapi_array_append(arr, obj->id);
+ ckcapi_array_append(arr, obj);
+ }
+ }
+
+ ASSERT(store);
+ CertCloseStore(store, 0);
+
+ return ret;
+}
+
+static CK_RV
+match_in_store(CkCapiSession* sess, const char* store_name, PCERT_INFO info,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
+{
+ PCCERT_CONTEXT cert = NULL;
+ CkCapiObject* obj;
+ HCERTSTORE store;
+ CkCapiObjectData objdata;
+ 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);
+ }
+
+ cert = CertGetSubjectCertificateFromStore(store, USE_ENCODINGS, info);
+ 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 */
+ objdata.data = (void*)cert;
+ objdata.data_funcs = cert_objdata_vtable;
+
+ if(ckcapi_object_data_match(&objdata, match, count))
+ {
+ ret = register_cert_object(sess, store_name, cert, &obj);
+ if(ret == CKR_OK)
+ {
+ ASSERT(obj);
+
+ /* Store away the object data for performance reasons */
+ ret = ckcapi_session_set_object_data(sess, obj, &objdata);
+ if(ret == CKR_OK)
+ ckcapi_array_append(arr, obj);
}
}
+ if(ret != CKR_OK && cert)
+ CertFreeCertificateContext(cert);
+
+
ASSERT(store);
CertCloseStore(store, 0);
@@ -560,23 +608,75 @@ ckcapi_cert_find_in_store(CkCapiSession* sess, const char* store_name,
}
CK_RV
-ckcapi_cert_find_all(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
- CK_ULONG count, CkCapiArray* arr)
+ckcapi_cert_find(CkCapiSession* sess, CK_OBJECT_CLASS cls, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, CkCapiArray* arr)
{
+ CRYPT_INTEGER_BLOB* serial = NULL;
+ CERT_INFO info;
CK_RV ret;
+ BOOL specific;
+ CK_ULONG i;
+ DWORD size;
+
+ /* We only have certificates here */
+ if(cls != CKO_CERTIFICATE && cls != CKO_ANY)
+ return CKR_OK;
+
+ /*
+ * See if we have a issuer and serial number for a
+ * specific certificate to find.
+ */
+ memset(&info, 0, sizeof(info));
+
+ for(i = 0; i < count; ++i)
+ {
+ if(!match[i].pValue || !match[i].ulValueLen)
+ continue;
+
+ if(match[i].type == CKA_ISSUER)
+ {
+ info.Issuer.cbData = match[i].ulValueLen;
+ info.Issuer.pbData = match[i].pValue;
+ }
+ else if(!serial && match[i].type == CKA_SERIAL_NUMBER)
+ {
+ if(!CryptDecodeObject(USE_ENCODINGS, X509_MULTI_BYTE_INTEGER,
+ match[i].pValue, match[i].ulValueLen, 0, NULL, &size))
+ {
+ continue;
+ }
+
+ serial = calloc(1, size);
+ if(!CryptDecodeObject(USE_ENCODINGS, X509_MULTI_BYTE_INTEGER,
+ match[i].pValue, match[i].ulValueLen, 0, serial, &size))
+ continue;
+
+ ASSERT(serial->cbData);
+ ASSERT(serial->pbData);
+
+ info.SerialNumber.cbData = serial->cbData;
+ info.SerialNumber.pbData = serial->pbData;
+ }
+ }
+
+ specific = info.SerialNumber.cbData && info.Issuer.cbData;
+
+ for(i = 0; CERT_STORES[i]; ++i)
+ {
+ /* Match a specific certificate */
+ if(specific)
+ ret = match_in_store(sess, CERT_STORES[i], &info, match, count, arr);
+
+ /* Match any ol certificate */
+ else
+ ret = find_in_store(sess, CERT_STORES[i], match, count, arr);
+
+ if(ret != CKR_OK)
+ break;
+ }
+
+ if(serial)
+ free(serial);
- ret = ckcapi_cert_find_in_store(sess, "My", match, count, arr);
- if(ret == CKR_OK)
- ret = ckcapi_cert_find_in_store(sess, "AddressBook", match, count, arr);
- if(ret == CKR_OK)
- ret = ckcapi_cert_find_in_store(sess, "CA", match, count, arr);
- if(ret == CKR_OK)
- ret = ckcapi_cert_find_in_store(sess, "Root", match, count, arr);
- if(ret == CKR_OK)
- ret = ckcapi_cert_find_in_store(sess, "Trust", match, count, arr);
- if(ret == CKR_OK)
- ret = ckcapi_cert_find_in_store(sess, "TrustedPeople", match, count, arr);
- if(ret == CKR_OK)
- ret = ckcapi_cert_find_in_store(sess, "AuthRoot", match, count, arr);
return ret;
}