Return to pkcs11_creds.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / pkcs11 |
1.1 misho 1: /* 2: * Copyright (C) 2010 Martin Willi 3: * Copyright (C) 2010 revosec AG 4: * 5: * This program is free software; you can redistribute it and/or modify it 6: * under the terms of the GNU General Public License as published by the 7: * Free Software Foundation; either version 2 of the License, or (at your 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 9: * 10: * This program is distributed in the hope that it will be useful, but 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13: * for more details. 14: */ 15: 16: #include "pkcs11_creds.h" 17: #include "pkcs11_manager.h" 18: 19: #include <utils/debug.h> 20: #include <collections/linked_list.h> 21: 22: typedef struct private_pkcs11_creds_t private_pkcs11_creds_t; 23: 24: /** 25: * Private data of an pkcs11_creds_t object. 26: */ 27: struct private_pkcs11_creds_t { 28: 29: /** 30: * Public pkcs11_creds_t interface. 31: */ 32: pkcs11_creds_t public; 33: 34: /** 35: * PKCS# library 36: */ 37: pkcs11_library_t *lib; 38: 39: /** 40: * Token slot 41: */ 42: CK_SLOT_ID slot; 43: 44: /** 45: * List of trusted certificates 46: */ 47: linked_list_t *trusted; 48: 49: /** 50: * List of untrusted certificates 51: */ 52: linked_list_t *untrusted; 53: }; 54: 55: /** 56: * Find certificates, optionally trusted 57: */ 58: static void find_certificates(private_pkcs11_creds_t *this, 59: CK_SESSION_HANDLE session) 60: { 61: CK_OBJECT_CLASS class = CKO_CERTIFICATE; 62: CK_CERTIFICATE_TYPE type = CKC_X_509; 63: CK_BBOOL trusted = TRUE; 64: CK_ATTRIBUTE tmpl[] = { 65: {CKA_CLASS, &class, sizeof(class)}, 66: {CKA_CERTIFICATE_TYPE, &type, sizeof(type)}, 67: }; 68: CK_OBJECT_HANDLE object; 69: CK_ATTRIBUTE attr[] = { 70: {CKA_VALUE, NULL, 0}, 71: {CKA_LABEL, NULL, 0}, 72: {CKA_TRUSTED, &trusted, sizeof(trusted)} 73: }; 74: enumerator_t *enumerator; 75: linked_list_t *raw; 76: certificate_t *cert; 77: struct { 78: chunk_t value; 79: chunk_t label; 80: bool trusted; 81: } *entry; 82: int count = countof(attr); 83: 84: /* store result in a temporary list, avoid recursive operation */ 85: raw = linked_list_create(); 86: /* do not use trusted argument if not supported */ 87: if (!(this->lib->get_features(this->lib) & PKCS11_TRUSTED_CERTS)) 88: { 89: count--; 90: } 91: enumerator = this->lib->create_object_enumerator(this->lib, 92: session, tmpl, countof(tmpl), attr, count); 93: while (enumerator->enumerate(enumerator, &object)) 94: { 95: entry = malloc(sizeof(*entry)); 96: entry->value = chunk_clone( 97: chunk_create(attr[0].pValue, attr[0].ulValueLen)); 98: entry->label = chunk_clone( 99: chunk_create(attr[1].pValue, attr[1].ulValueLen)); 100: entry->trusted = trusted; 101: raw->insert_last(raw, entry); 102: } 103: enumerator->destroy(enumerator); 104: 105: while (raw->remove_first(raw, (void**)&entry) == SUCCESS) 106: { 107: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, 108: BUILD_BLOB_ASN1_DER, entry->value, 109: BUILD_END); 110: if (cert) 111: { 112: DBG1(DBG_CFG, " loaded %strusted cert '%.*s'", 113: entry->trusted ? "" : "un", (int)entry->label.len, 114: entry->label.ptr); 115: /* trusted certificates are also returned as untrusted */ 116: this->untrusted->insert_last(this->untrusted, cert); 117: if (entry->trusted) 118: { 119: this->trusted->insert_last(this->trusted, cert->get_ref(cert)); 120: } 121: } 122: else 123: { 124: DBG1(DBG_CFG, " loading cert '%.*s' failed", 125: (int)entry->label.len, entry->label.ptr); 126: } 127: free(entry->value.ptr); 128: free(entry->label.ptr); 129: free(entry); 130: } 131: raw->destroy(raw); 132: } 133: 134: /** 135: * Load in the certificates from the token 136: */ 137: static bool load_certificates(private_pkcs11_creds_t *this) 138: { 139: CK_SESSION_HANDLE session; 140: CK_RV rv; 141: 142: rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, 143: NULL, NULL, &session); 144: if (rv != CKR_OK) 145: { 146: DBG1(DBG_CFG, "opening session failed: %N", ck_rv_names, rv); 147: return FALSE; 148: } 149: 150: find_certificates(this, session); 151: 152: this->lib->f->C_CloseSession(session); 153: return TRUE; 154: } 155: 156: CALLBACK(certs_filter, bool, 157: identification_t *id, enumerator_t *orig, va_list args) 158: { 159: public_key_t *public; 160: certificate_t *cert, **out; 161: 162: VA_ARGS_VGET(args, out); 163: 164: while (orig->enumerate(orig, &cert)) 165: { 166: if (id == NULL || cert->has_subject(cert, id)) 167: { 168: *out = cert; 169: return TRUE; 170: } 171: public = cert->get_public_key(cert); 172: if (public) 173: { 174: if (public->has_fingerprint(public, id->get_encoding(id))) 175: { 176: public->destroy(public); 177: *out = cert; 178: return TRUE; 179: } 180: public->destroy(public); 181: } 182: } 183: return FALSE; 184: } 185: 186: METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, 187: private_pkcs11_creds_t *this, certificate_type_t cert, key_type_t key, 188: identification_t *id, bool trusted) 189: { 190: enumerator_t *inner; 191: 192: if (cert != CERT_X509 && cert != CERT_ANY) 193: { 194: return NULL; 195: } 196: if (trusted) 197: { 198: inner = this->trusted->create_enumerator(this->trusted); 199: } 200: else 201: { 202: inner = this->untrusted->create_enumerator(this->untrusted); 203: } 204: return enumerator_create_filter(inner, certs_filter, id, NULL); 205: } 206: 207: METHOD(pkcs11_creds_t, get_library, pkcs11_library_t*, 208: private_pkcs11_creds_t *this) 209: { 210: return this->lib; 211: } 212: 213: METHOD(pkcs11_creds_t, get_slot, CK_SLOT_ID, 214: private_pkcs11_creds_t *this) 215: { 216: return this->slot; 217: } 218: 219: METHOD(pkcs11_creds_t, destroy, void, 220: private_pkcs11_creds_t *this) 221: { 222: this->trusted->destroy_offset(this->trusted, 223: offsetof(certificate_t, destroy)); 224: this->untrusted->destroy_offset(this->untrusted, 225: offsetof(certificate_t, destroy)); 226: free(this); 227: } 228: 229: /** 230: * See header 231: */ 232: pkcs11_creds_t *pkcs11_creds_create(pkcs11_library_t *p11, CK_SLOT_ID slot) 233: { 234: private_pkcs11_creds_t *this; 235: 236: INIT(this, 237: .public = { 238: .set = { 239: .create_shared_enumerator = (void*)enumerator_create_empty, 240: .create_private_enumerator = (void*)enumerator_create_empty, 241: .create_cert_enumerator = _create_cert_enumerator, 242: .create_cdp_enumerator = (void*)enumerator_create_empty, 243: .cache_cert = (void*)nop, 244: }, 245: .get_library = _get_library, 246: .get_slot = _get_slot, 247: .destroy = _destroy, 248: }, 249: .lib = p11, 250: .slot = slot, 251: .trusted = linked_list_create(), 252: .untrusted = linked_list_create(), 253: ); 254: 255: if (!load_certificates(this)) 256: { 257: destroy(this); 258: return NULL; 259: } 260: 261: return &this->public; 262: } 263: 264: /** 265: * See header. 266: */ 267: certificate_t *pkcs11_creds_load(certificate_type_t type, va_list args) 268: { 269: chunk_t keyid = chunk_empty, data = chunk_empty; 270: enumerator_t *enumerator, *certs; 271: pkcs11_manager_t *manager; 272: pkcs11_library_t *p11; 273: certificate_t *cert = NULL; 274: CK_SLOT_ID current, slot = -1; 275: char *module = NULL; 276: 277: while (TRUE) 278: { 279: switch (va_arg(args, builder_part_t)) 280: { 281: case BUILD_PKCS11_KEYID: 282: keyid = va_arg(args, chunk_t); 283: continue; 284: case BUILD_PKCS11_SLOT: 285: slot = va_arg(args, int); 286: continue; 287: case BUILD_PKCS11_MODULE: 288: module = va_arg(args, char*); 289: continue; 290: case BUILD_END: 291: break; 292: default: 293: return NULL; 294: } 295: break; 296: } 297: if (!keyid.len) 298: { 299: return NULL; 300: } 301: 302: manager = lib->get(lib, "pkcs11-manager"); 303: if (!manager) 304: { 305: return NULL; 306: } 307: enumerator = manager->create_token_enumerator(manager); 308: while (enumerator->enumerate(enumerator, &p11, ¤t)) 309: { 310: CK_OBJECT_CLASS class = CKO_CERTIFICATE; 311: CK_CERTIFICATE_TYPE ck_type = CKC_X_509; 312: CK_ATTRIBUTE tmpl[] = { 313: {CKA_CLASS, &class, sizeof(class)}, 314: {CKA_CERTIFICATE_TYPE, &ck_type, sizeof(ck_type)}, 315: {CKA_ID, keyid.ptr, keyid.len}, 316: }; 317: CK_ATTRIBUTE attr[] = { 318: {CKA_VALUE, NULL, 0}, 319: }; 320: CK_OBJECT_HANDLE object; 321: CK_SESSION_HANDLE session; 322: CK_RV rv; 323: 324: if (slot != -1 && slot != current) 325: { 326: continue; 327: } 328: if (module && !streq(module, p11->get_name(p11))) 329: { 330: continue; 331: } 332: 333: rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL, 334: &session); 335: if (rv != CKR_OK) 336: { 337: DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv); 338: continue; 339: } 340: certs = p11->create_object_enumerator(p11, session, 341: tmpl, countof(tmpl), attr, countof(attr)); 342: if (certs->enumerate(certs, &object)) 343: { 344: data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen)); 345: } 346: certs->destroy(certs); 347: p11->f->C_CloseSession(session); 348: 349: if (data.ptr) 350: { 351: break; 352: } 353: } 354: enumerator->destroy(enumerator); 355: 356: if (data.ptr) 357: { 358: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, 359: BUILD_BLOB_ASN1_DER, data, BUILD_END); 360: free(data.ptr); 361: if (!cert) 362: { 363: DBG1(DBG_CFG, "parsing PKCS#11 certificate %#B failed", &keyid); 364: } 365: } 366: else 367: { 368: DBG1(DBG_CFG, "PKCS#11 certificate %#B not found", &keyid); 369: } 370: return cert; 371: }