示例#1
0
文件: ks_file.c 项目: gojdic/samba
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;
}
示例#2
0
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;
}