[BACK]Return to crl.c CVS log [TXT][DIR] Up to [local] / src / usr.sbin / rpki-client

File: [local] / src / usr.sbin / rpki-client / crl.c (download)

Revision 1.34, Sun Apr 21 19:27:44 2024 UTC (5 weeks, 6 days ago) by claudio
Branch: MAIN
Changes since 1.33: +2 -2 lines

P-256 support is experimental so require -x to enable it.

Also clean up the externs a little bit by moving experimental and noop
to extern.h.
Reminded by and OK tb@

/*	$OpenBSD: crl.c,v 1.34 2024/04/21 19:27:44 claudio Exp $ */
/*
 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <openssl/x509.h>

#include "extern.h"

struct crl *
crl_parse(const char *fn, const unsigned char *der, size_t len)
{
	const unsigned char	*oder;
	struct crl		*crl;
	const X509_ALGOR	*palg;
	const ASN1_OBJECT	*cobj;
	const ASN1_TIME		*at;
	int			 count, nid, rc = 0;

	/* just fail for empty buffers, the warning was printed elsewhere */
	if (der == NULL)
		return NULL;

	if ((crl = calloc(1, sizeof(*crl))) == NULL)
		err(1, NULL);

	oder = der;
	if ((crl->x509_crl = d2i_X509_CRL(NULL, &der, len)) == NULL) {
		warnx("%s: d2i_X509_CRL", fn);
		goto out;
	}
	if (der != oder + len) {
		warnx("%s: %td bytes trailing garbage", fn, oder + len - der);
		goto out;
	}

	if (X509_CRL_get_version(crl->x509_crl) != 1) {
		warnx("%s: RFC 6487 section 5: version 2 expected", fn);
		goto out;
	}

	X509_CRL_get0_signature(crl->x509_crl, NULL, &palg);
	if (palg == NULL) {
		warnx("%s: X509_CRL_get0_signature", fn);
		goto out;
	}
	X509_ALGOR_get0(&cobj, NULL, NULL, palg);
	nid = OBJ_obj2nid(cobj);
	if (experimental && nid == NID_ecdsa_with_SHA256) {
		if (verbose)
			warnx("%s: P-256 support is experimental", fn);
	} else if (nid != NID_sha256WithRSAEncryption) {
		warnx("%s: RFC 7935: wrong signature algorithm %s, want %s",
		    fn, nid2str(nid), LN_sha256WithRSAEncryption);
		goto out;
	}

	/*
	 * RFC 6487, section 5: AKI and crlNumber MUST be present, no other
	 * CRL extensions are allowed.
	 */
	if ((crl->aki = x509_crl_get_aki(crl->x509_crl, fn)) == NULL) {
		warnx("%s: x509_crl_get_aki failed", fn);
		goto out;
	}
	if ((crl->number = x509_crl_get_number(crl->x509_crl, fn)) == NULL) {
		warnx("%s: x509_crl_get_number failed", fn);
		goto out;
	}
	if ((count = X509_CRL_get_ext_count(crl->x509_crl)) != 2) {
		warnx("%s: RFC 6487 section 5: unexpected number of extensions "
		    "%d != 2", fn, count);
		goto out;
	}

	at = X509_CRL_get0_lastUpdate(crl->x509_crl);
	if (at == NULL) {
		warnx("%s: X509_CRL_get0_lastUpdate failed", fn);
		goto out;
	}
	if (!x509_get_time(at, &crl->thisupdate)) {
		warnx("%s: ASN1_TIME_to_tm failed", fn);
		goto out;
	}

	at = X509_CRL_get0_nextUpdate(crl->x509_crl);
	if (at == NULL) {
		warnx("%s: X509_CRL_get0_nextUpdate failed", fn);
		goto out;
	}
	if (!x509_get_time(at, &crl->nextupdate)) {
		warnx("%s: ASN1_TIME_to_tm failed", fn);
		goto out;
	}

	rc = 1;
 out:
	if (rc == 0) {
		crl_free(crl);
		crl = NULL;
	}
	return crl;
}

static inline int
crlcmp(struct crl *a, struct crl *b)
{
	int	 cmp;

	cmp = strcmp(a->aki, b->aki);
	if (cmp > 0)
		return 1;
	if (cmp < 0)
		return -1;

	/*
	 * In filemode the mftpath cannot be determined easily,
	 * but it is always set in normal top-down validation.
	 */
	if (a->mftpath == NULL || b->mftpath == NULL)
		return 0;

	cmp = strcmp(a->mftpath, b->mftpath);
	if (cmp > 0)
		return 1;
	if (cmp < 0)
		return -1;

	return 0;
}

RB_GENERATE_STATIC(crl_tree, crl, entry, crlcmp);

/*
 * Find a CRL based on the auth SKI value.
 */
struct crl *
crl_get(struct crl_tree *crlt, const struct auth *a)
{
	struct crl	find;

	if (a == NULL)
		return NULL;

	find.aki = a->cert->ski;
	find.mftpath = a->cert->mft;

	return RB_FIND(crl_tree, crlt, &find);
}

int
crl_insert(struct crl_tree *crlt, struct crl *crl)
{
	return RB_INSERT(crl_tree, crlt, crl) == NULL;
}

void
crl_free(struct crl *crl)
{
	if (crl == NULL)
		return;
	free(crl->aki);
	free(crl->mftpath);
	free(crl->number);
	X509_CRL_free(crl->x509_crl);
	free(crl);
}

void
crl_tree_free(struct crl_tree *crlt)
{
	struct crl	*crl, *tcrl;

	RB_FOREACH_SAFE(crl, crl_tree, crlt, tcrl) {
		RB_REMOVE(crl_tree, crlt, crl);
		crl_free(crl);
	}
}