Esempio n. 1
0
ssize_t
dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len)
{
	uint8_t		 sig[EVP_MAX_MD_SIZE];
	unsigned int	 siglen = sizeof(sig);
	uint8_t		*ptr = buf;
	size_t		 off = 0;

	if (dsa->dsa_hmac) {
		if (!HMAC_Final(dsa->dsa_ctx, sig, &siglen))
			return (-1);
		if (siglen != len || memcmp(buf, sig, siglen) != 0)
			return (-1);
	} else {
		if ((off = _dsa_verify_offset(dsa, ptr)) >= len)
			return (-1);
		if (EVP_VerifyFinal(dsa->dsa_ctx, ptr + off, len - off,
		    dsa->dsa_key) != 1) {
			ca_sslerror(__func__);
			return (-1);
		}
	}

	return (0);
}
Esempio n. 2
0
/* validate the certifcate stored in 'data' by querying the ocsp-responder */
int
ocsp_validate_cert(struct iked *env, struct iked_static_id *id,
    void *data, size_t len, struct iked_sahdr sh, uint8_t type)
{
	struct iked_ocsp_entry	*ioe;
	struct iked_ocsp	*ocsp;
	BIO			*rawcert = NULL, *bissuer = NULL;
	X509			*cert = NULL, *issuer = NULL;

	if ((ioe = calloc(1, sizeof(*ioe))) == NULL)
		return (-1);
	if ((ocsp = calloc(1, sizeof(*ocsp))) == NULL) {
		free(ioe);
		return (-1);
	}

	ocsp->ocsp_env = env;
	ocsp->ocsp_sh = sh;
	ocsp->ocsp_type = type;

	if ((rawcert = BIO_new_mem_buf(data, len)) == NULL ||
	    (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
	    (bissuer = BIO_new_file(IKED_OCSP_ISSUER, "r")) == NULL ||
	    (issuer = PEM_read_bio_X509(bissuer, NULL, NULL, NULL)) == NULL ||
	    (ocsp->ocsp_cbio = BIO_new(BIO_s_socket())) == NULL ||
	    (ocsp->ocsp_req = OCSP_REQUEST_new()) == NULL ||
	    !(ocsp->ocsp_id = OCSP_cert_to_id(NULL, cert, issuer)) ||
	    !OCSP_request_add0_id(ocsp->ocsp_req, ocsp->ocsp_id))
		goto err;

	BIO_free(rawcert);
	BIO_free(bissuer);
	X509_free(cert);
	X509_free(issuer);

	ioe->ioe_ocsp = ocsp;
	TAILQ_INSERT_TAIL(&env->sc_ocsp, ioe, ioe_entry);

	/* request connection to ocsp-responder */
	proc_compose_imsg(&env->sc_ps, PROC_PARENT, -1,
	    IMSG_OCSP_FD, -1, NULL, 0);
	return (0);

 err:
	ca_sslerror(__func__);
	free(ioe);
	if (rawcert != NULL)
		BIO_free(rawcert);
	if (cert != NULL)
		X509_free(cert);
	if (bissuer != NULL)
		BIO_free(bissuer);
	if (issuer != NULL)
		X509_free(issuer);
	ocsp_validate_finish(ocsp, 0);	/* failed */
	return (-1);
}
Esempio n. 3
0
void
cipher_final(struct iked_cipher *encr, void *out, size_t *outlen)
{
	int	 olen;

	olen = 0;
	if (!EVP_CipherFinal_ex(encr->encr_ctx, out, &olen)) {
		ca_sslerror(__func__);
		*outlen = 0;
		return;
	}
	*outlen = (size_t)olen;
}
Esempio n. 4
0
void
cipher_update(struct iked_cipher *encr, void *in, size_t inlen,
    void *out, size_t *outlen)
{
	int	 olen;

	olen = 0;
	if (!EVP_CipherUpdate(encr->encr_ctx, out, &olen, in, inlen)) {
		ca_sslerror(__func__);
		*outlen = 0;
		return;
	}
	*outlen = (size_t)olen;
}
Esempio n. 5
0
/* load a stack of x509 certificates */
STACK_OF(X509)*
ocsp_load_certs(const char *file)
{
	BIO			*bio = NULL;
	STACK_OF(X509)		*certs = NULL;
	STACK_OF(X509_INFO)	*xis = NULL;
	X509_INFO		*xi;
	int			 i;

	if ((bio = BIO_new_file(file, "r")) == NULL) {
		log_warn("%s: BIO_new_file failed for %s",
		    __func__, file);
		return (NULL);
	}
	if ((xis = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL)) == NULL) {
		ca_sslerror(__func__);
		goto done;
	}
	if ((certs = sk_X509_new_null()) == NULL) {
		log_debug("%s: sk_X509_new_null failed for %s", __func__, file);
		goto done;
	}
	for (i = 0; i < sk_X509_INFO_num(xis); i++) {
		xi = sk_X509_INFO_value(xis, i);
		if (xi->x509) {
			if (!sk_X509_push(certs, xi->x509))
				goto done;
			xi->x509 = NULL;
		}
	}

 done:
	if (bio)
		BIO_free(bio);
	if (xis)
		sk_X509_INFO_pop_free(xis, X509_INFO_free);
	if (certs && sk_X509_num(certs) <= 0) {
		sk_X509_pop_free(certs, X509_free);
		certs = NULL;
	}
	return (certs);
}
Esempio n. 6
0
struct ibuf *
dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type)
{
	BIO		*rawcert = NULL;
	X509		*cert = NULL;
	RSA		*rsa = NULL;
	EVP_PKEY	*pkey = NULL;

	ibuf_release(dsa->dsa_keydata);
	if ((dsa->dsa_keydata = ibuf_new(key, keylen)) == NULL) {
		log_debug("%s: alloc signature key", __func__);
		return (NULL);
	}

	if ((rawcert = BIO_new_mem_buf(key, keylen)) == NULL)
		goto err;

	switch (type) {
	case IKEV2_CERT_X509_CERT:
		if ((cert = d2i_X509_bio(rawcert, NULL)) == NULL)
			goto sslerr;
		if ((pkey = X509_get_pubkey(cert)) == NULL)
			goto sslerr;
		dsa->dsa_cert = cert;
		dsa->dsa_key = pkey;
		break;
	case IKEV2_CERT_RSA_KEY:
		if (dsa->dsa_sign) {
			if ((rsa = d2i_RSAPrivateKey_bio(rawcert,
			    NULL)) == NULL)
				goto sslerr;
		} else {
			if ((rsa = d2i_RSAPublicKey_bio(rawcert,
			    NULL)) == NULL)
				goto sslerr;
		}

		if ((pkey = EVP_PKEY_new()) == NULL)
			goto sslerr;
		if (!EVP_PKEY_set1_RSA(pkey, rsa))
			goto sslerr;

		RSA_free(rsa);	/* pkey now has the reference */
		dsa->dsa_cert = NULL;
		dsa->dsa_key = pkey;
		break;
	default:
		if (dsa->dsa_hmac)
			break;
		log_debug("%s: unsupported key type", __func__);
		goto err;
	}

	return (dsa->dsa_keydata);

 sslerr:
	ca_sslerror(__func__);
 err:
	log_debug("%s: error", __func__);

	if (rsa != NULL)
		RSA_free(rsa);
	if (pkey != NULL)
		EVP_PKEY_free(pkey);
	if (cert != NULL)
		X509_free(cert);
	if (rawcert != NULL)
		BIO_free(rawcert);
	ibuf_release(dsa->dsa_keydata);
	return (NULL);
}
Esempio n. 7
0
/*
 * Parse an X509 subject name where 'subject' is in the format
 *    /type0=value0/type1=value1/type2=...
 * where characters may be escaped by '\'.
 * See lib/libssl/src/apps/apps.c:parse_name()
 */
void *
ca_x509_name_parse(char *subject)
{
	char		*cp, *value = NULL, *type = NULL;
	size_t		 maxlen;
	X509_NAME	*name = NULL;

	if (*subject != '/') {
		log_warnx("%s: leading '/' missing in '%s'", __func__, subject);
		goto err;
	}

	/* length of subject is upper bound for unescaped type/value */
	maxlen = strlen(subject) + 1;

	if ((type = calloc(1, maxlen)) == NULL ||
	    (value = calloc(1, maxlen)) == NULL ||
	    (name = X509_NAME_new()) == NULL)
		goto err;

	cp = subject + 1;
	while (*cp) {
		/* unescape type, terminated by '=' */
		cp = ca_x509_name_unescape(cp, type, '=');
		if (cp == NULL) {
			log_warnx("%s: could not parse type", __func__);
			goto err;
		}
		if (!*cp) {
			log_warnx("%s: missing value", __func__);
			goto err;
		}
		/* unescape value, terminated by '/' */
		cp = ca_x509_name_unescape(cp, value, '/');
		if (cp == NULL) {
			log_warnx("%s: could not parse value", __func__);
			goto err;
		}
		if (!*type || !*value) {
			log_warnx("%s: empty type or value", __func__);
			goto err;
		}
		log_debug("%s: setting '%s' to '%s'", __func__, type, value);
		if (!X509_NAME_add_entry_by_txt(name, type, MBSTRING_ASC,
		    value, -1, -1, 0)) {
			log_warnx("%s: setting '%s' to '%s' failed", __func__,
			    type, value);
			ca_sslerror(__func__);
			goto err;
		}
	}
	free(type);
	free(value);
	return (name);

err:
	X509_NAME_free(name);
	free(type);
	free(value);
	return (NULL);
}
Esempio n. 8
0
int
ca_reload(struct iked *env)
{
	struct ca_store		*store = env->sc_priv;
	uint8_t			 md[EVP_MAX_MD_SIZE];
	char			 file[PATH_MAX];
	struct iovec		 iov[2];
	struct dirent		*entry;
	STACK_OF(X509_OBJECT)	*h;
	X509_OBJECT		*xo;
	X509			*x509;
	DIR			*dir;
	int			 i, len, iovcnt = 0;

	/*
	 * Load CAs
	 */
	if ((dir = opendir(IKED_CA_DIR)) == NULL)
		return (-1);

	while ((entry = readdir(dir)) != NULL) {
		if ((entry->d_type != DT_REG) &&
		    (entry->d_type != DT_LNK))
			continue;

		if (snprintf(file, sizeof(file), "%s%s",
		    IKED_CA_DIR, entry->d_name) == -1)
			continue;

		if (!X509_load_cert_file(store->ca_calookup, file,
		    X509_FILETYPE_PEM)) {
			log_warn("%s: failed to load ca file %s", __func__,
			    entry->d_name);
			ca_sslerror(__func__);
			continue;
		}
		log_debug("%s: loaded ca file %s", __func__, entry->d_name);
	}
	closedir(dir);

	/*
	 * Load CRLs for the CAs
	 */
	if ((dir = opendir(IKED_CRL_DIR)) == NULL)
		return (-1);

	while ((entry = readdir(dir)) != NULL) {
		if ((entry->d_type != DT_REG) &&
		    (entry->d_type != DT_LNK))
			continue;

		if (snprintf(file, sizeof(file), "%s%s",
		    IKED_CRL_DIR, entry->d_name) == -1)
			continue;

		if (!X509_load_crl_file(store->ca_calookup, file,
		    X509_FILETYPE_PEM)) {
			log_warn("%s: failed to load crl file %s", __func__,
			    entry->d_name);
			ca_sslerror(__func__);
			continue;
		}

		/* Only enable CRL checks if we actually loaded a CRL */
		X509_STORE_set_flags(store->ca_cas, X509_V_FLAG_CRL_CHECK);

		log_debug("%s: loaded crl file %s", __func__, entry->d_name);
	}
	closedir(dir);

	/*
	 * Save CAs signatures for the IKEv2 CERTREQ
	 */
	ibuf_release(env->sc_certreq);
	if ((env->sc_certreq = ibuf_new(NULL, 0)) == NULL)
		return (-1);

	h = store->ca_cas->objs;
	for (i = 0; i < sk_X509_OBJECT_num(h); i++) {
		xo = sk_X509_OBJECT_value(h, i);
		if (xo->type != X509_LU_X509)
			continue;

		x509 = xo->data.x509;
		len = sizeof(md);
		ca_subjectpubkey_digest(x509, md, &len);
		log_debug("%s: %s", __func__, x509->name);

		if (ibuf_add(env->sc_certreq, md, len) != 0) {
			ibuf_release(env->sc_certreq);
			return (-1);
		}
	}

	if (ibuf_length(env->sc_certreq)) {
		env->sc_certreqtype = IKEV2_CERT_X509_CERT;
		iov[0].iov_base = &env->sc_certreqtype;
		iov[0].iov_len = sizeof(env->sc_certreqtype);
		iovcnt++;
		iov[1].iov_base = ibuf_data(env->sc_certreq);
		iov[1].iov_len = ibuf_length(env->sc_certreq);
		iovcnt++;

		log_debug("%s: loaded %zu ca certificate%s", __func__,
		    ibuf_length(env->sc_certreq) / SHA_DIGEST_LENGTH,
		    ibuf_length(env->sc_certreq) == SHA_DIGEST_LENGTH ?
		    "" : "s");

		(void)proc_composev(&env->sc_ps, PROC_IKEV2, IMSG_CERTREQ,
		    iov, iovcnt);
	}

	/*
	 * Load certificates
	 */
	if ((dir = opendir(IKED_CERT_DIR)) == NULL)
		return (-1);

	while ((entry = readdir(dir)) != NULL) {
		if ((entry->d_type != DT_REG) &&
		    (entry->d_type != DT_LNK))
			continue;

		if (snprintf(file, sizeof(file), "%s%s",
		    IKED_CERT_DIR, entry->d_name) == -1)
			continue;

		if (!X509_load_cert_file(store->ca_certlookup, file,
		    X509_FILETYPE_PEM)) {
			log_warn("%s: failed to load cert file %s", __func__,
			    entry->d_name);
			ca_sslerror(__func__);
			continue;
		}
		log_debug("%s: loaded cert file %s", __func__, entry->d_name);
	}
	closedir(dir);

	h = store->ca_certs->objs;
	for (i = 0; i < sk_X509_OBJECT_num(h); i++) {
		xo = sk_X509_OBJECT_value(h, i);
		if (xo->type != X509_LU_X509)
			continue;

		x509 = xo->data.x509;

		(void)ca_validate_cert(env, NULL, x509, 0);
	}

	if (!env->sc_certreqtype)
		env->sc_certreqtype = store->ca_pubkey.id_type;

	log_debug("%s: local cert type %s", __func__,
	    print_map(env->sc_certreqtype, ikev2_cert_map));

	iov[0].iov_base = &env->sc_certreqtype;
	iov[0].iov_len = sizeof(env->sc_certreqtype);
	if (iovcnt == 0)
		iovcnt++;
	(void)proc_composev(&env->sc_ps, PROC_IKEV2, IMSG_CERTREQ, iov, iovcnt);

	return (0);
}
Esempio n. 9
0
int
ca_validate_pubkey(struct iked *env, struct iked_static_id *id,
    void *data, size_t len)
{
	BIO		*rawcert = NULL;
	RSA		*peerrsa = NULL, *localrsa = NULL;
	EVP_PKEY	*peerkey = NULL, *localkey = NULL;
	int		 ret = -1;
	FILE		*fp = NULL;
	char		 idstr[IKED_ID_SIZE];
	char		 file[PATH_MAX];
	struct iked_id	 idp;

	if (len == 0 && data == NULL)
		return (-1);

	switch (id->id_type) {
	case IKEV2_ID_IPV4:
	case IKEV2_ID_FQDN:
	case IKEV2_ID_UFQDN:
	case IKEV2_ID_IPV6:
		break;
	default:
		/* Some types like ASN1_DN will not be mapped to file names */
		return (-1);
	}

	bzero(&idp, sizeof(idp));
	if ((idp.id_buf = ibuf_new(id->id_data, id->id_length)) == NULL)
		goto done;

	idp.id_type = id->id_type;
	idp.id_offset = id->id_offset;
	if (ikev2_print_id(&idp, idstr, sizeof(idstr)) == -1)
		goto done;

	if (len == 0) {
		/* Data is already an public key */
		peerkey = (EVP_PKEY *)data;
	} else {
		if ((rawcert = BIO_new_mem_buf(data, len)) == NULL)
			goto done;

		if ((peerrsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL)
			goto sslerr;
		if ((peerkey = EVP_PKEY_new()) == NULL)
			goto sslerr;
		if (!EVP_PKEY_set1_RSA(peerkey, peerrsa))
			goto sslerr;
	}

	lc_string(idstr);
	if (strlcpy(file, IKED_PUBKEY_DIR, sizeof(file)) >= sizeof(file) ||
	    strlcat(file, idstr, sizeof(file)) >= sizeof(file))
		goto done;

	if ((fp = fopen(file, "r")) == NULL)
		goto done;
	localkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
	if (localkey == NULL) {
		/* reading PKCS #8 failed, try PEM */
		rewind(fp);
		localrsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
		fclose(fp);
		if (localrsa == NULL)
			goto sslerr;
		if ((localkey = EVP_PKEY_new()) == NULL)
			goto sslerr;
		if (!EVP_PKEY_set1_RSA(localkey, localrsa))
			goto sslerr;
	} else {
		fclose(fp);
	}
	if (localkey == NULL)
		goto sslerr;

	if (!EVP_PKEY_cmp(peerkey, localkey))
		goto done;

	log_debug("%s: valid public key in file %s", __func__, file);

	ret = 0;
 sslerr:
	if (ret != 0)
		ca_sslerror(__func__);
 done:
	ibuf_release(idp.id_buf);
	if (peerkey != NULL)
		EVP_PKEY_free(peerkey);
	if (localkey != NULL)
		EVP_PKEY_free(localkey);
	if (peerrsa != NULL)
		RSA_free(peerrsa);
	if (localrsa != NULL)
		RSA_free(localrsa);
	if (rawcert != NULL)
		BIO_free(rawcert);

	return (ret);
}
Esempio n. 10
0
/* parse the actual OCSP response */
void
ocsp_parse_response(struct iked_ocsp *ocsp, OCSP_RESPONSE *resp)
{
	int status;
	X509_STORE *store = NULL;
	STACK_OF(X509) *verify_other = NULL;
	OCSP_BASICRESP *bs = NULL;
	int verify_flags = 0;
	ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
	int reason = 0;
	int error = 1;

	if (!resp) {
		log_warnx("%s: error querying OCSP responder", __func__);
		goto done;
	}

	status = OCSP_response_status(resp);
	if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
		log_warnx("%s: responder error: %s (%i)\n", __func__,
		    OCSP_response_status_str(status), status);
		goto done;
	}

	verify_other = ocsp_load_certs(IKED_OCSP_RESPCERT);
	verify_flags |= OCSP_TRUSTOTHER;
	if (!verify_other)
		goto done;

	bs = OCSP_response_get1_basic(resp);
	if (!bs) {
		log_warnx("%s: error parsing response", __func__);
		goto done;
	}

	status = OCSP_check_nonce(ocsp->ocsp_req, bs);
	if (status <= 0) {
		if (status == -1)
			log_warnx("%s: no nonce in response", __func__);
		else {
			log_warnx("%s: nonce verify error", __func__);
			goto done;
		}
	}

	store = X509_STORE_new();
	status = OCSP_basic_verify(bs, verify_other, store, verify_flags);
	if (status < 0)
		status = OCSP_basic_verify(bs, NULL, store, 0);

	if (status <= 0) {
		ca_sslerror(__func__);
		log_warnx("%s: response verify failure", __func__);
		goto done;
	} else
		log_debug("%s: response verify ok", __func__);

	if (!OCSP_resp_find_status(bs, ocsp->ocsp_id, &status, &reason,
	    &rev, &thisupd, &nextupd)) {
		log_warnx("%s: no status found", __func__);
		goto done;
	}
	log_debug("%s: status: %s", __func__, OCSP_cert_status_str(status));

	if (status == V_OCSP_CERTSTATUS_GOOD)
		error = 0;

 done:
	if (store)
		X509_STORE_free(store);
	if (verify_other)
		sk_X509_pop_free(verify_other, X509_free);
	if (resp)
		OCSP_RESPONSE_free(resp);
	if (bs)
		OCSP_BASICRESP_free(bs);

	ocsp_validate_finish(ocsp, error == 0);
}