static int parse_rsa_private_key(hx509_context context, const char *fn, struct hx509_collector *c, const hx509_pem_header *headers, const void *data, size_t len) { int ret = 0; const char *enc; enc = hx509_pem_find_header(headers, "Proc-Type"); if (enc) { const char *dek; char *type, *iv; ssize_t ssize, size; void *ivdata; const EVP_CIPHER *cipher; const struct _hx509_password *pw; hx509_lock lock; int i, decrypted = 0; lock = _hx509_collector_get_lock(c); if (lock == NULL) { hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, "Failed to get password for " "password protected file %s", fn); return HX509_ALG_NOT_SUPP; } if (strcmp(enc, "4,ENCRYPTED") != 0) { hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, "RSA key encrypted in unknown method %s " "in file", enc, fn); hx509_clear_error_string(context); return HX509_PARSING_KEY_FAILED; } dek = hx509_pem_find_header(headers, "DEK-Info"); if (dek == NULL) { hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, "Encrypted RSA missing DEK-Info"); return HX509_PARSING_KEY_FAILED; } type = strdup(dek); if (type == NULL) { hx509_clear_error_string(context); return ENOMEM; } iv = strchr(type, ','); if (iv == NULL) { free(type); hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, "IV missing"); return HX509_PARSING_KEY_FAILED; } *iv++ = '\0'; size = strlen(iv); ivdata = malloc(size); if (ivdata == NULL) { hx509_clear_error_string(context); free(type); return ENOMEM; } cipher = EVP_get_cipherbyname(type); if (cipher == NULL) { free(ivdata); hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, "RSA key encrypted with " "unsupported cipher: %s", type); free(type); return HX509_ALG_NOT_SUPP; } #define PKCS5_SALT_LEN 8 ssize = hex_decode(iv, ivdata, size); free(type); type = NULL; iv = NULL; if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) { free(ivdata); hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, "Salt have wrong length in RSA key file"); return HX509_PARSING_KEY_FAILED; } pw = _hx509_lock_get_passwords(lock); if (pw != NULL) { const void *password; size_t passwordlen; for (i = 0; i < pw->len; i++) { password = pw->val[i]; passwordlen = strlen(password); ret = try_decrypt(context, c, hx509_signature_rsa(), cipher, ivdata, password, passwordlen, data, len); if (ret == 0) { decrypted = 1; break; } } } if (!decrypted) { hx509_prompt prompt; char password[128]; memset(&prompt, 0, sizeof(prompt)); prompt.prompt = "Password for keyfile: "; prompt.type = HX509_PROMPT_TYPE_PASSWORD; prompt.reply.data = password; prompt.reply.length = sizeof(password); ret = hx509_lock_prompt(lock, &prompt); if (ret == 0) ret = try_decrypt(context, c, hx509_signature_rsa(), cipher, ivdata, password, strlen(password), data, len); /* XXX add password to lock password collection ? */ memset(password, 0, sizeof(password)); } free(ivdata); } else { heim_octet_string keydata; keydata.data = rk_UNCONST(data); keydata.length = len; ret = _hx509_collector_private_key_add(context, c, hx509_signature_rsa(), NULL, &keydata, NULL); } return ret; }
static int p11_get_session(hx509_context context, struct p11_module *p, struct p11_slot *slot, hx509_lock lock, CK_SESSION_HANDLE *psession) { CK_RV ret; if (slot->flags & P11_SESSION_IN_USE) _hx509_abort("slot already in session"); if (slot->flags & P11_SESSION) { slot->flags |= P11_SESSION_IN_USE; *psession = slot->session; return 0; } ret = P11FUNC(p, OpenSession, (slot->id, CKF_SERIAL_SESSION, NULL, NULL, &slot->session)); if (ret != CKR_OK) { if (context) hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION, "Failed to OpenSession for slot id %d " "with error: 0x%08x", (int)slot->id, ret); return HX509_PKCS11_OPEN_SESSION; } slot->flags |= P11_SESSION; /* * If we have have to login, and haven't tried before and have a * prompter or known to work pin code. * * This code is very conversative and only uses the prompter in * the hx509_lock, the reason is that it's bad to try many * passwords on a pkcs11 token, it might lock up and have to be * unlocked by a administrator. * * XXX try harder to not use pin several times on the same card. */ if ( (slot->flags & P11_LOGIN_REQ) && (slot->flags & P11_LOGIN_DONE) == 0 && (lock || slot->pin)) { hx509_prompt prompt; char pin[20]; char *str; slot->flags |= P11_LOGIN_DONE; if (slot->pin == NULL) { memset(&prompt, 0, sizeof(prompt)); asprintf(&str, "PIN code for %s: ", slot->name); prompt.prompt = str; prompt.type = HX509_PROMPT_TYPE_PASSWORD; prompt.reply.data = pin; prompt.reply.length = sizeof(pin); ret = hx509_lock_prompt(lock, &prompt); if (ret) { free(str); if (context) hx509_set_error_string(context, 0, ret, "Failed to get pin code for slot " "id %d with error: %d", (int)slot->id, ret); return ret; } free(str); } else { strlcpy(pin, slot->pin, sizeof(pin)); } ret = P11FUNC(p, Login, (slot->session, CKU_USER, (unsigned char*)pin, strlen(pin))); if (ret != CKR_OK) { if (context) hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN, "Failed to login on slot id %d " "with error: 0x%08x", (int)slot->id, ret); p11_put_session(p, slot, slot->session); return HX509_PKCS11_LOGIN; } if (slot->pin == NULL) { slot->pin = strdup(pin); if (slot->pin == NULL) { if (context) hx509_set_error_string(context, 0, ENOMEM, "out of memory"); p11_put_session(p, slot, slot->session); return ENOMEM; } } } else slot->flags |= P11_LOGIN_DONE; slot->flags |= P11_SESSION_IN_USE; *psession = slot->session; return 0; }