Beispiel #1
0
static int
Time2string(const Time *T, char **str)
{
    time_t t;
    char *s;
    struct tm *tm;

    *str = NULL;
    t = _hx509_Time2time_t(T);
    tm = gmtime (&t);
    s = malloc(30);
    if (s == NULL)
	return ENOMEM;
    strftime(s, 30, "%Y-%m-%d %H:%M:%S", tm);
    *str = s;
    return 0;
}
Beispiel #2
0
int
hx509_revoke_verify(hx509_context context,
		    hx509_revoke_ctx ctx,
		    hx509_certs certs,
		    time_t now,
		    hx509_cert cert,
		    hx509_cert parent_cert)
{
    const Certificate *c = _hx509_get_cert(cert);
    const Certificate *p = _hx509_get_cert(parent_cert);
    unsigned long i, j, k;
    int ret;

    hx509_clear_error_string(context);

    for (i = 0; i < ctx->ocsps.len; i++) {
	struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
	struct stat sb;

	/* check this ocsp apply to this cert */

	/* check if there is a newer version of the file */
	ret = stat(ocsp->path, &sb);
	if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
	    ret = load_ocsp(context, ocsp);
	    if (ret)
		continue;
	}

	/* verify signature in ocsp if not already done */
	if (ocsp->signer == NULL) {
	    ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
	    if (ret)
		continue;
	}

	for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
	    heim_octet_string os;

	    ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
				   &c->tbsCertificate.serialNumber);
	    if (ret != 0)
		continue;

	    /* verify issuer hashes hash */
	    ret = _hx509_verify_signature(context,
					  NULL,
					  &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
					  &c->tbsCertificate.issuer._save,
					  &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
	    if (ret != 0)
		continue;

	    os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
	    os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;

	    ret = _hx509_verify_signature(context,
					  NULL,
					  &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
					  &os,
					  &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
	    if (ret != 0)
		continue;

	    switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
	    case choice_OCSPCertStatus_good:
		break;
	    case choice_OCSPCertStatus_revoked:
		hx509_set_error_string(context, 0,
				       HX509_CERT_REVOKED,
				       "Certificate revoked by issuer in OCSP");
		return HX509_CERT_REVOKED;
	    case choice_OCSPCertStatus_unknown:
		continue;
	    }

	    /* don't allow the update to be in the future */
	    if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate >
		now + context->ocsp_time_diff)
		continue;

	    /* don't allow the next update to be in the past */
	    if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
		if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
		    continue;
	    } /* else should force a refetch, but can we ? */

	    return 0;
	}
    }

    for (i = 0; i < ctx->crls.len; i++) {
	struct revoke_crl *crl = &ctx->crls.val[i];
	struct stat sb;
	int diff;

	/* check if cert.issuer == crls.val[i].crl.issuer */
	ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
			      &crl->crl.tbsCertList.issuer, &diff);
	if (ret || diff)
	    continue;

	ret = stat(crl->path, &sb);
	if (ret == 0 && crl->last_modfied != sb.st_mtime) {
	    CRLCertificateList cl;

	    ret = load_crl(crl->path, &crl->last_modfied, &cl);
	    if (ret == 0) {
		free_CRLCertificateList(&crl->crl);
		crl->crl = cl;
		crl->verified = 0;
		crl->failed_verify = 0;
	    }
	}
	if (crl->failed_verify)
	    continue;

	/* verify signature in crl if not already done */
	if (crl->verified == 0) {
	    ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
	    if (ret) {
		crl->failed_verify = 1;
		continue;
	    }
	    crl->verified = 1;
	}

	if (crl->crl.tbsCertList.crlExtensions) {
	    for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
		if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
		    hx509_set_error_string(context, 0,
					   HX509_CRL_UNKNOWN_EXTENSION,
					   "Unknown CRL extension");
		    return HX509_CRL_UNKNOWN_EXTENSION;
		}
	    }
	}

	if (crl->crl.tbsCertList.revokedCertificates == NULL)
	    return 0;

	/* check if cert is in crl */
	for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
	    time_t t;

	    ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
				       &c->tbsCertificate.serialNumber);
	    if (ret != 0)
		continue;

	    t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
	    if (t > now)
		continue;

	    if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
		for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
		    if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
			return HX509_CRL_UNKNOWN_EXTENSION;

	    hx509_set_error_string(context, 0,
				   HX509_CERT_REVOKED,
				   "Certificate revoked by issuer in CRL");
	    return HX509_CERT_REVOKED;
	}

	return 0;
    }


    if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
	return 0;
    hx509_set_error_string(context, HX509_ERROR_APPEND,
			   HX509_REVOKE_STATUS_MISSING,
			   "No revoke status found for "
			   "certificates");
    return HX509_REVOKE_STATUS_MISSING;
}
Beispiel #3
0
static int
verify_crl(hx509_context context,
	   hx509_revoke_ctx ctx,
	   CRLCertificateList *crl,
	   time_t time_now,
	   hx509_certs certs,
	   hx509_cert parent)
{
    hx509_cert signer;
    hx509_query q;
    time_t t;
    int ret;

    t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
    if (t > time_now) {
	hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
			       "CRL used before time");
	return HX509_CRL_USED_BEFORE_TIME;
    }

    if (crl->tbsCertList.nextUpdate == NULL) {
	hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
			       "CRL missing nextUpdate");
	return HX509_CRL_INVALID_FORMAT;
    }

    t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
    if (t < time_now) {
	hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
			       "CRL used after time");
	return HX509_CRL_USED_AFTER_TIME;
    }

    _hx509_query_clear(&q);

    /*
     * If it's the signer have CRLSIGN bit set, use that as the signer
     * cert for the certificate, otherwise, search for a certificate.
     */
    if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
	signer = hx509_cert_ref(parent);
    } else {
	q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
	q.match |= HX509_QUERY_KU_CRLSIGN;
	q.subject_name = &crl->tbsCertList.issuer;

	ret = hx509_certs_find(context, certs, &q, &signer);
	if (ret) {
	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
				   "Failed to find certificate for CRL");
	    return ret;
	}
    }

    ret = _hx509_verify_signature_bitstring(context,
					    signer,
					    &crl->signatureAlgorithm,
					    &crl->tbsCertList._save,
					    &crl->signatureValue);
    if (ret) {
	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
			       "CRL signature invalid");
	goto out;
    }

    /*
     * If signer is not CA cert, need to check revoke status of this
     * CRL signing cert too, this include all parent CRL signer cert
     * up to the root *sigh*, assume root at least hve CERTSIGN flag
     * set.
     */
    while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
	hx509_cert crl_parent;

	_hx509_query_clear(&q);

	q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
	q.match |= HX509_QUERY_KU_CRLSIGN;
	q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;

	ret = hx509_certs_find(context, certs, &q, &crl_parent);
	if (ret) {
	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
				   "Failed to find parent of CRL signer");
	    goto out;
	}

	ret = hx509_revoke_verify(context,
				  ctx,
				  certs,
				  time_now,
				  signer,
				  crl_parent);
	hx509_cert_free(signer);
	signer = crl_parent;
	if (ret) {
	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
				   "Failed to verify revoke "
				   "status of CRL signer");
	    goto out;
	}
    }

out:
    hx509_cert_free(signer);

    return ret;
}