diff options
Diffstat (limited to 'ckcapi-cert.c')
-rw-r--r-- | ckcapi-cert.c | 222 |
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; } |