Commit message: ocsp: corrected the comparison of the serial size in OCSP response

Previously the OCSP certificate check wouldn't verify the serial length
and could succeed in cases it shouldn't.

Reported by Stefan Buehler.
CVE: CVE-2016-7444
CWE: CWE-264
Vulnerability description: The gnutls_ocsp_resp_check_crt function in lib/x509/ocsp.c in GnuTLS before 3.4.15 and 3.5.x before 3.5.4 does not verify the serial length of an OCSP response, which might allow remote attackers to bypass an intended certificate validation mechanism via vectors involving trailing bytes left by gnutls_malloc.

Project: gnutls
File: ocsp.c

int gnutls_ocsp_resp_get_version(gnutls_ocsp_resp_t resp)
{
	uint8_t version[8];
	int len, ret;

	if (resp == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	len = sizeof(version);
	ret =
	    asn1_read_value(resp->resp, "tbsResponseData.version", version,
			    &len);
	if (ret != ASN1_SUCCESS) {
		if (ret == ASN1_ELEMENT_NOT_FOUND)
			return 1;	/* the DEFAULT version */
		gnutls_assert();
		return _gnutls_asn2err(ret);
	}

	return (int) version[0] + 1;
}

Project: gnutls
File: ocsp.c

int gnutls_ocsp_resp_get_status(gnutls_ocsp_resp_t resp)
{
	uint8_t str[1];
	int len, ret;

	if (resp == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	len = sizeof(str);
	ret = asn1_read_value(resp->resp, "responseStatus", str, &len);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(ret);
	}

	switch (str[0]) {
	case GNUTLS_OCSP_RESP_SUCCESSFUL:
	case GNUTLS_OCSP_RESP_MALFORMEDREQUEST:
	case GNUTLS_OCSP_RESP_INTERNALERROR:
	case GNUTLS_OCSP_RESP_TRYLATER:
	case GNUTLS_OCSP_RESP_SIGREQUIRED:
	case GNUTLS_OCSP_RESP_UNAUTHORIZED:
		break;
	default:
		return GNUTLS_E_UNEXPECTED_PACKET;
	}

	return (int) str[0];
}

Project: gnutls
File: ocsp.c

int gnutls_ocsp_req_randomize_nonce(gnutls_ocsp_req_t req)
{
	int ret;
	uint8_t rndbuf[23];
	gnutls_datum_t nonce = { rndbuf, sizeof(rndbuf) };

	if (req == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	ret = gnutls_rnd(GNUTLS_RND_NONCE, rndbuf, sizeof(rndbuf));
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	ret = gnutls_ocsp_req_set_nonce(req, 0, &nonce);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

int gnutls_ocsp_resp_get_signature_algorithm(gnutls_ocsp_resp_t resp)
{
	int ret;
	gnutls_datum_t sa;

	ret = _gnutls_x509_read_value(resp->basicresp,
				      "signatureAlgorithm.algorithm", &sa);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	ret = gnutls_oid_to_sign((char *) sa.data);

	_gnutls_free_datum(&sa);

	return ret;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_get_certs(gnutls_ocsp_resp_t resp,
			   gnutls_x509_crt_t ** certs, size_t * ncerts)
{
	int ret;
	size_t ctr = 0, i;
	gnutls_x509_crt_t *tmpcerts = NULL, *tmpcerts2;
	gnutls_datum_t c = { NULL, 0 };

	if (resp == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	tmpcerts = gnutls_malloc(sizeof(*tmpcerts));
	if (tmpcerts == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	for (;;) {
		char name[ASN1_MAX_NAME_SIZE];

		snprintf(name, sizeof(name), "certs.?%u",
			 (unsigned int) (ctr + 1));
		ret =
		    _gnutls_x509_der_encode(resp->basicresp, name, &c, 0);
		if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
			break;
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			goto error;
		}

		tmpcerts2 =
		    gnutls_realloc_fast(tmpcerts,
					(ctr + 2) * sizeof(*tmpcerts));
		if (tmpcerts2 == NULL) {
			gnutls_assert();
			ret = GNUTLS_E_MEMORY_ERROR;
			goto error;
		}
		tmpcerts = tmpcerts2;

		ret = gnutls_x509_crt_init(&tmpcerts[ctr]);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			goto error;
		}
		ctr++;

		ret = gnutls_x509_crt_import(tmpcerts[ctr - 1], &c,
					     GNUTLS_X509_FMT_DER);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			goto error;
		}

		gnutls_free(c.data);
		c.data = NULL;
	}

	tmpcerts[ctr] = NULL;

	if (ncerts)
		*ncerts = ctr;
	if (certs)
		*certs = tmpcerts;
	else {
		/* clean up memory */
		ret = GNUTLS_E_SUCCESS;
		goto error;
	}

	return GNUTLS_E_SUCCESS;

      error:
	gnutls_free(c.data);
	for (i = 0; i < ctr; i++)
		gnutls_x509_crt_deinit(tmpcerts[i]);
	gnutls_free(tmpcerts);
	return ret;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_check_crt(gnutls_ocsp_resp_t resp,
			   unsigned int indx, gnutls_x509_crt_t crt)
{
	int ret;
	gnutls_digest_algorithm_t digest;
	gnutls_datum_t rdn_hash = { NULL, 0 }, rserial = {
	NULL, 0};
	gnutls_datum_t cserial = { NULL, 0 };
	gnutls_datum_t dn = { NULL, 0 };
	uint8_t cdn_hash[MAX_HASH_SIZE];
	size_t t, hash_len;

	ret =
	    gnutls_ocsp_resp_get_single(resp, indx, &digest, &rdn_hash,
					NULL, &rserial, NULL, NULL, NULL,
					NULL, NULL);
	if (ret < 0)
		return gnutls_assert_val(ret);

	if (rserial.size == 0 || digest == GNUTLS_DIG_UNKNOWN) {
		ret = gnutls_assert_val(GNUTLS_E_OCSP_RESPONSE_ERROR);
		goto cleanup;
	}

	hash_len = _gnutls_hash_get_algo_len(hash_to_entry(digest));
	if (hash_len != rdn_hash.size) {
		ret = gnutls_assert_val(GNUTLS_E_OCSP_RESPONSE_ERROR);
		goto cleanup;
	}

	cserial.size = rserial.size;
	cserial.data = gnutls_malloc(cserial.size);
	if (cserial.data == NULL) {
		ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
		goto cleanup;
	}

	t = cserial.size;
	ret = gnutls_x509_crt_get_serial(crt, cserial.data, &t);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}
	cserial.size = t;

	if (rserial.size != cserial.size
	    || memcmp(cserial.data, rserial.data, rserial.size) != 0) {
		ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
		gnutls_assert();
		goto cleanup;
	}

	ret = gnutls_x509_crt_get_raw_issuer_dn(crt, &dn);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = _gnutls_hash_fast(digest, dn.data, dn.size, cdn_hash);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if (memcmp(cdn_hash, rdn_hash.data, hash_len) != 0) {
		ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
		gnutls_assert();
		goto cleanup;
	}

	ret = 0;

      cleanup:
	gnutls_free(rdn_hash.data);
	gnutls_free(rserial.data);
	gnutls_free(cserial.data);
	gnutls_free(dn.data);

	return ret;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_import(gnutls_ocsp_resp_t resp,
			const gnutls_datum_t * data)
{
	int ret = 0;

	if (resp == NULL || data == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if (resp->init != 0) {
		/* Any earlier _asn1_strict_der_decode will modify the ASN.1
		   structure, so we need to replace it with a fresh
		   structure. */
		asn1_delete_structure(&resp->resp);
		if (resp->basicresp)
			asn1_delete_structure(&resp->basicresp);

		ret = asn1_create_element(_gnutls_get_pkix(),
					  "PKIX1.OCSPResponse",
					  &resp->resp);
		if (ret != ASN1_SUCCESS) {
			gnutls_assert();
			return _gnutls_asn2err(ret);
		}

		ret = asn1_create_element(_gnutls_get_pkix(),
					  "PKIX1.BasicOCSPResponse",
					  &resp->basicresp);
		if (ret != ASN1_SUCCESS) {
			gnutls_assert();
			return _gnutls_asn2err(ret);
		}

		gnutls_free(resp->der.data);
		resp->der.data = NULL;
	}

	resp->init = 1;
	ret = _asn1_strict_der_decode(&resp->resp, data->data, data->size, NULL);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(ret);
	}

	if (gnutls_ocsp_resp_get_status(resp) !=
	    GNUTLS_OCSP_RESP_SUCCESSFUL)
		return GNUTLS_E_SUCCESS;

	ret =
	    _gnutls_x509_read_value(resp->resp,
				    "responseBytes.responseType",
				    &resp->response_type_oid);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}
#define OCSP_BASIC "1.3.6.1.5.5.7.48.1.1"

	if (resp->response_type_oid.size == sizeof(OCSP_BASIC)
	    && memcmp(resp->response_type_oid.data, OCSP_BASIC,
		      resp->response_type_oid.size) == 0) {

		ret =
		    _gnutls_x509_read_value(resp->resp,
					    "responseBytes.response", &resp->der);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		ret =
		    _asn1_strict_der_decode(&resp->basicresp, resp->der.data, resp->der.size,
				      NULL);
		if (ret != ASN1_SUCCESS) {
			gnutls_assert();
			return _gnutls_asn2err(ret);
		}
	} else {
		asn1_delete_structure(&resp->basicresp);
		resp->basicresp = NULL;
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_get_responder_raw_id(gnutls_ocsp_resp_t resp,
				      unsigned type,
				      gnutls_datum_t * raw)
{
	int ret;

	if (resp == NULL || raw == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if (type == GNUTLS_OCSP_RESP_ID_KEY)
		ret = _gnutls_x509_read_value(resp->basicresp, "tbsResponseData.responderID.byKey", raw);
	else {
		gnutls_datum_t tmp;

		/* simply reading a CHOICE of CHOICE value doesn't work in libtasn1 */
		ret = _gnutls_x509_get_raw_field2(resp->basicresp, &resp->der,
					  "tbsResponseData.responderID.byName",
					  &tmp);
		if (ret >= 0) {
			int real;
			/* skip the tag */
			if (tmp.size < 2) {
				gnutls_assert();
				ret = GNUTLS_E_ASN1_GENERIC_ERROR;
				goto fail;
			}

			tmp.data++;
			tmp.size--;

			ret = asn1_get_length_der(tmp.data, tmp.size, &real);
			if (ret < 0) {
				gnutls_assert();
				ret = GNUTLS_E_ASN1_GENERIC_ERROR;
				goto fail;
			}

			if (tmp.size < (unsigned)real) {
				gnutls_assert();
				ret = GNUTLS_E_ASN1_GENERIC_ERROR;
				goto fail;
			}

			tmp.data+=real;
			tmp.size-=real;

			ret = _gnutls_set_datum(raw, tmp.data, tmp.size);
		}
	}

	if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND || ret == GNUTLS_E_ASN1_VALUE_NOT_FOUND)
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;

 fail:
	return ret;
}

Project: gnutls
File: ocsp.c

int gnutls_ocsp_resp_export(gnutls_ocsp_resp_t resp, gnutls_datum_t * data)
{
	if (resp == NULL || data == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	return _gnutls_x509_get_raw_field(resp->resp, "", data);
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_get_response(gnutls_ocsp_resp_t resp,
			      gnutls_datum_t * response_type_oid,
			      gnutls_datum_t * response)
{
	int ret;

	if (resp == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if (response_type_oid != NULL) {
		ret =
		    _gnutls_x509_read_value(resp->resp,
					    "responseBytes.responseType",
					    response_type_oid);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}
	}

	if (response != NULL) {
		ret =
		    _gnutls_x509_read_value(resp->resp,
					    "responseBytes.response",
					    response);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

static inline unsigned int vstatus_to_ocsp_status(unsigned int status)
{
	unsigned int ostatus;

	if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
		ostatus = GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM;
	else if (status & GNUTLS_CERT_NOT_ACTIVATED)
		ostatus = GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED;
	else if (status & GNUTLS_CERT_EXPIRED)
		ostatus = GNUTLS_OCSP_VERIFY_CERT_EXPIRED;
	else
		ostatus = GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER;

	return ostatus;
}

Project: gnutls
File: ocsp.c

int gnutls_ocsp_req_export(gnutls_ocsp_req_t req, gnutls_datum_t * data)
{
	int ret;

	if (req == NULL || data == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	/* XXX remove when we support these fields */
	asn1_write_value(req->req, "tbsRequest.requestorName", NULL, 0);
	asn1_write_value(req->req, "optionalSignature", NULL, 0);

	/* prune extension field if we don't have any extension */
	ret = gnutls_ocsp_req_get_extension(req, 0, NULL, NULL, NULL);
	if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
		asn1_write_value(req->req, "tbsRequest.requestExtensions",
				 NULL, 0);

	return _gnutls_x509_get_raw_field(req->req, "", data);
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_req_add_cert(gnutls_ocsp_req_t req,
			 gnutls_digest_algorithm_t digest,
			 gnutls_x509_crt_t issuer, gnutls_x509_crt_t cert)
{
	int ret;
	gnutls_datum_t sn, tmp, inh, ikh;
	uint8_t inh_buf[MAX_HASH_SIZE];
	uint8_t ikh_buf[MAX_HASH_SIZE];
	size_t inhlen = MAX_HASH_SIZE;
	size_t ikhlen = MAX_HASH_SIZE;

	if (req == NULL || issuer == NULL || cert == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	ret = _gnutls_x509_der_encode(cert->cert,
				      "tbsCertificate.issuer.rdnSequence",
				      &tmp, 0);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	ret = gnutls_fingerprint(digest, &tmp, inh_buf, &inhlen);
	gnutls_free(tmp.data);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}
	inh.size = inhlen;
	inh.data = inh_buf;

	ret = _gnutls_x509_read_value
	    (issuer->cert,
	     "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", &tmp);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	ret = gnutls_fingerprint(digest, &tmp, ikh_buf, &ikhlen);
	gnutls_free(tmp.data);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}
	ikh.size = ikhlen;
	ikh.data = ikh_buf;

	ret =
	    _gnutls_x509_read_value(cert->cert,
				    "tbsCertificate.serialNumber", &sn);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	ret = gnutls_ocsp_req_add_cert_id(req, digest, &inh, &ikh, &sn);
	gnutls_free(sn.data);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

void gnutls_ocsp_req_deinit(gnutls_ocsp_req_t req)
{
	if (!req)
		return;

	if (req->req)
		asn1_delete_structure(&req->req);

	req->req = NULL;
	gnutls_free(req);
}

Project: gnutls
File: ocsp.c

static int check_ocsp_purpose(gnutls_x509_crt_t signercert)
{
	char oidtmp[MAX_OID_SIZE];
	size_t oidsize;
	int indx, rc;

	for (indx = 0;; indx++) {
		oidsize = sizeof(oidtmp);
		rc = gnutls_x509_crt_get_key_purpose_oid(signercert, indx,
							 oidtmp, &oidsize,
							 NULL);

		if (rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
			gnutls_assert();
			return rc;
		} else if (rc == GNUTLS_E_SHORT_MEMORY_BUFFER) {
			gnutls_assert();
			continue;
		} else if (rc != GNUTLS_E_SUCCESS) {
			return gnutls_assert_val(rc);
		}

		if (memcmp(oidtmp, GNUTLS_KP_OCSP_SIGNING, oidsize) != 0) {
			gnutls_assert();
			continue;
		}
		break;
	}

	return 0;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_get_responder(gnutls_ocsp_resp_t resp,
			       gnutls_datum_t * dn)
{
	int ret;
	size_t l = 0;

	if (resp == NULL || dn == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	dn->data = NULL;
	dn->size = 0;

	ret = _gnutls_x509_parse_dn
	    (resp->basicresp, "tbsResponseData.responderID.byName",
	     NULL, &l);
	if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
			return 0; /* for backwards compatibility */
		gnutls_assert();
		return ret;
	}

	dn->data = gnutls_malloc(l);
	if (dn->data == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	ret = _gnutls_x509_parse_dn
	    (resp->basicresp, "tbsResponseData.responderID.byName",
	     (char *) dn->data, &l);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	dn->size = l;

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_verify_direct(gnutls_ocsp_resp_t resp,
			       gnutls_x509_crt_t issuer,
			       unsigned int *verify, unsigned int flags)
{
	gnutls_x509_crt_t signercert;
	int rc;

	if (resp == NULL || issuer == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	signercert = find_signercert(resp);
	if (!signercert) {
		signercert = issuer;
	} else if (!gnutls_x509_crt_equals(signercert, issuer)) {

		/* response contains a signer. Verify him */

		unsigned int vtmp;

		rc = gnutls_x509_crt_verify(signercert, &issuer, 1, 0,
					    &vtmp);
		if (rc != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			goto done;
		}

		if (vtmp != 0) {
			*verify = vstatus_to_ocsp_status(vtmp);
			gnutls_assert();
			rc = GNUTLS_E_SUCCESS;
			goto done;
		}

		rc = check_ocsp_purpose(signercert);
		if (rc < 0) {
			gnutls_assert();
			*verify = GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR;
			rc = GNUTLS_E_SUCCESS;
			goto done;
		}
	}

	rc = _ocsp_resp_verify_direct(resp, signercert, verify, flags);

      done:
	if (signercert != issuer)
		gnutls_x509_crt_deinit(signercert);

	return rc;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_get_single(gnutls_ocsp_resp_t resp,
			    unsigned indx,
			    gnutls_digest_algorithm_t * digest,
			    gnutls_datum_t * issuer_name_hash,
			    gnutls_datum_t * issuer_key_hash,
			    gnutls_datum_t * serial_number,
			    unsigned int *cert_status,
			    time_t * this_update,
			    time_t * next_update,
			    time_t * revocation_time,
			    unsigned int *revocation_reason)
{
	gnutls_datum_t sa;
	char name[ASN1_MAX_NAME_SIZE];
	int ret;

	snprintf(name, sizeof(name),
		 "tbsResponseData.responses.?%u.certID.hashAlgorithm.algorithm",
		 indx + 1);
	ret = _gnutls_x509_read_value(resp->basicresp, name, &sa);
	if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	else if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	ret = gnutls_oid_to_digest((char *) sa.data);
	_gnutls_free_datum(&sa);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	if (digest)
		*digest = ret;

	if (issuer_name_hash) {
		snprintf(name, sizeof(name),
			 "tbsResponseData.responses.?%u.certID.issuerNameHash",
			 indx + 1);
		ret = _gnutls_x509_read_value(resp->basicresp, name,
					      issuer_name_hash);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			return ret;
		}
	}

	if (issuer_key_hash) {
		snprintf(name, sizeof(name),
			 "tbsResponseData.responses.?%u.certID.issuerKeyHash",
			 indx + 1);
		ret = _gnutls_x509_read_value(resp->basicresp, name,
					      issuer_key_hash);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			if (issuer_name_hash)
				gnutls_free(issuer_name_hash->data);
			return ret;
		}
	}

	if (serial_number) {
		snprintf(name, sizeof(name),
			 "tbsResponseData.responses.?%u.certID.serialNumber",
			 indx + 1);
		ret = _gnutls_x509_read_value(resp->basicresp, name,
					      serial_number);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			if (issuer_name_hash)
				gnutls_free(issuer_name_hash->data);
			if (issuer_key_hash)
				gnutls_free(issuer_key_hash->data);
			return ret;
		}
	}

	if (cert_status) {
		snprintf(name, sizeof(name),
			 "tbsResponseData.responses.?%u.certStatus",
			 indx + 1);
		ret = _gnutls_x509_read_value(resp->basicresp, name, &sa);
		if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
			return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
		else if (ret < 0) {
			gnutls_assert();
			return ret;
		}
		if (sa.size == 5 && memcmp(sa.data, "good", sa.size) == 0)
			*cert_status = GNUTLS_OCSP_CERT_GOOD;
		else if (sa.size == 8
			 && memcmp(sa.data, "revoked", sa.size) == 0)
			*cert_status = GNUTLS_OCSP_CERT_REVOKED;
		else if (sa.size == 8
			 && memcmp(sa.data, "unknown", sa.size) == 0)
			*cert_status = GNUTLS_OCSP_CERT_UNKNOWN;
		else {
			gnutls_assert();
			gnutls_free(sa.data);
			return GNUTLS_E_ASN1_DER_ERROR;
		}
		gnutls_free(sa.data);
	}

	if (this_update) {
		char ttime[MAX_TIME];
		int len;

		snprintf(name, sizeof(name),
			 "tbsResponseData.responses.?%u.thisUpdate",
			 indx + 1);
		len = sizeof(ttime) - 1;
		ret = asn1_read_value(resp->basicresp, name, ttime, &len);
		if (ret != ASN1_SUCCESS) {
			gnutls_assert();
			return GNUTLS_E_ASN1_DER_ERROR;
		} else {
			*this_update =
			    _gnutls_x509_generalTime2gtime(ttime);
		}
	}

	if (next_update) {
		char ttime[MAX_TIME];
		int len;

		snprintf(name, sizeof(name),
			 "tbsResponseData.responses.?%u.nextUpdate",
			 indx + 1);
		len = sizeof(ttime) - 1;
		ret = asn1_read_value(resp->basicresp, name, ttime, &len);
		if (ret != ASN1_SUCCESS) {
			gnutls_assert();
			*next_update = (time_t) (-1);
		} else
			*next_update =
			    _gnutls_x509_generalTime2gtime(ttime);
	}

	if (revocation_time) {
		char ttime[MAX_TIME];
		int len;

		snprintf(name, sizeof(name),
			 "tbsResponseData.responses.?%u.certStatus."
			 "revoked.revocationTime", indx + 1);
		len = sizeof(ttime) - 1;
		ret = asn1_read_value(resp->basicresp, name, ttime, &len);
		if (ret != ASN1_SUCCESS) {
			gnutls_assert();
			*revocation_time = (time_t) (-1);
		} else
			*revocation_time =
			    _gnutls_x509_generalTime2gtime(ttime);
	}

	/* revocation_reason */
	if (revocation_reason) {
		snprintf(name, sizeof(name),
			 "tbsResponseData.responses.?%u.certStatus."
			 "revoked.revocationReason", indx + 1);

		ret = _gnutls_x509_read_uint(resp->basicresp, name,
					     revocation_reason);
		if (ret < 0)
			*revocation_reason =
			    GNUTLS_X509_CRLREASON_UNSPECIFIED;
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

int gnutls_ocsp_resp_init(gnutls_ocsp_resp_t * resp)
{
	gnutls_ocsp_resp_t tmp =
	    gnutls_calloc(1, sizeof(gnutls_ocsp_resp_int));
	int ret;

	if (!tmp)
		return GNUTLS_E_MEMORY_ERROR;

	ret = asn1_create_element(_gnutls_get_pkix(),
				  "PKIX1.OCSPResponse", &tmp->resp);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		gnutls_free(tmp);
		return _gnutls_asn2err(ret);
	}

	ret = asn1_create_element(_gnutls_get_pkix(),
				  "PKIX1.BasicOCSPResponse",
				  &tmp->basicresp);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		asn1_delete_structure(&tmp->resp);
		gnutls_free(tmp);
		return _gnutls_asn2err(ret);
	}

	*resp = tmp;

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_req_import(gnutls_ocsp_req_t req, const gnutls_datum_t * data)
{
	int ret = 0;

	if (req == NULL || data == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if (req->init) {
		/* Any earlier _asn1_strict_der_decode will modify the ASN.1
		   structure, so we need to replace it with a fresh
		   structure. */
		asn1_delete_structure(&req->req);

		ret = asn1_create_element(_gnutls_get_pkix(),
					  "PKIX1.OCSPRequest", &req->req);
		if (ret != ASN1_SUCCESS) {
			gnutls_assert();
			return _gnutls_asn2err(ret);
		}
	}
	req->init = 1;

	ret = _asn1_strict_der_decode(&req->req, data->data, data->size, NULL);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(ret);
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

void gnutls_ocsp_resp_deinit(gnutls_ocsp_resp_t resp)
{
	if (!resp)
		return;

	if (resp->resp)
		asn1_delete_structure(&resp->resp);
	gnutls_free(resp->response_type_oid.data);
	if (resp->basicresp)
		asn1_delete_structure(&resp->basicresp);

	resp->resp = NULL;
	resp->response_type_oid.data = NULL;
	resp->basicresp = NULL;

	gnutls_free(resp->der.data);
	gnutls_free(resp);
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_req_get_nonce(gnutls_ocsp_req_t req,
			  unsigned int *critical, gnutls_datum_t * nonce)
{
	int ret;
	gnutls_datum_t tmp;

	if (req == NULL || nonce == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	ret = _gnutls_get_extension(req->req, "tbsRequest.requestExtensions",
			    GNUTLS_OCSP_NONCE, 0, &tmp, critical);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	ret =
	    _gnutls_x509_decode_string(ASN1_ETYPE_OCTET_STRING, tmp.data,
				       (size_t) tmp.size, nonce, 0);
	if (ret < 0) {
		gnutls_assert();
		gnutls_free(tmp.data);
		return ret;
	}

	gnutls_free(tmp.data);

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_get_extension(gnutls_ocsp_resp_t resp,
			       unsigned indx,
			       gnutls_datum_t * oid,
			       unsigned int *critical,
			       gnutls_datum_t * data)
{
	int ret;
	char str_critical[10];
	char name[ASN1_MAX_NAME_SIZE];
	int len;

	if (!resp) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	snprintf(name, sizeof(name),
		 "tbsResponseData.responseExtensions.?%u.critical",
		 indx + 1);
	len = sizeof(str_critical);
	ret = asn1_read_value(resp->basicresp, name, str_critical, &len);
	if (ret == ASN1_ELEMENT_NOT_FOUND)
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	else if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(ret);
	}

	if (critical) {
		if (str_critical[0] == 'T')
			*critical = 1;
		else
			*critical = 0;
	}

	if (oid) {
		snprintf(name, sizeof(name),
			 "tbsResponseData.responseExtensions.?%u.extnID",
			 indx + 1);
		ret = _gnutls_x509_read_value(resp->basicresp, name, oid);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			return ret;
		}
	}

	if (data) {
		snprintf(name, sizeof(name),
			 "tbsResponseData.responseExtensions.?%u.extnValue",
			 indx + 1);
		ret = _gnutls_x509_read_value(resp->basicresp, name, data);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			if (oid)
				gnutls_free(oid->data);
			return ret;
		}
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_req_get_cert_id(gnutls_ocsp_req_t req,
			    unsigned indx,
			    gnutls_digest_algorithm_t * digest,
			    gnutls_datum_t * issuer_name_hash,
			    gnutls_datum_t * issuer_key_hash,
			    gnutls_datum_t * serial_number)
{
	gnutls_datum_t sa;
	char name[ASN1_MAX_NAME_SIZE];
	int ret;

	if (req == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	snprintf(name, sizeof(name),
		 "tbsRequest.requestList.?%u.reqCert.hashAlgorithm.algorithm",
		 indx + 1);
	ret = _gnutls_x509_read_value(req->req, name, &sa);
	if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	else if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	ret = gnutls_oid_to_digest((char *) sa.data);
	_gnutls_free_datum(&sa);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	if (digest)
		*digest = ret;

	if (issuer_name_hash) {
		snprintf(name, sizeof(name),
			 "tbsRequest.requestList.?%u.reqCert.issuerNameHash",
			 indx + 1);
		ret =
		    _gnutls_x509_read_value(req->req, name,
					    issuer_name_hash);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			return ret;
		}
	}

	if (issuer_key_hash) {
		snprintf(name, sizeof(name),
			 "tbsRequest.requestList.?%u.reqCert.issuerKeyHash",
			 indx + 1);
		ret =
		    _gnutls_x509_read_value(req->req, name,
					    issuer_key_hash);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			if (issuer_name_hash)
				gnutls_free(issuer_name_hash->data);
			return ret;
		}
	}

	if (serial_number) {
		snprintf(name, sizeof(name),
			 "tbsRequest.requestList.?%u.reqCert.serialNumber",
			 indx + 1);
		ret =
		    _gnutls_x509_read_value(req->req, name, serial_number);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			if (issuer_name_hash)
				gnutls_free(issuer_name_hash->data);
			if (issuer_key_hash)
				gnutls_free(issuer_key_hash->data);
			return ret;
		}
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

_ocsp_resp_verify_direct(gnutls_ocsp_resp_t resp,
			 gnutls_x509_crt_t signercert,
			 unsigned int *verify, unsigned int flags)
{
	gnutls_datum_t sig = { NULL };
	gnutls_datum_t data = { NULL };
	gnutls_pubkey_t pubkey = NULL;
	int sigalg;
	int rc;

	if (resp == NULL || signercert == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	rc = gnutls_ocsp_resp_get_signature_algorithm(resp);
	if (rc < 0) {
		gnutls_assert();
		goto done;
	}
	sigalg = rc;

	rc = _gnutls_x509_get_raw_field2(resp->basicresp, &resp->der, "tbsResponseData", &data);
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		goto done;
	}

	rc = gnutls_pubkey_init(&pubkey);
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		goto done;
	}

	rc = gnutls_pubkey_import_x509(pubkey, signercert, 0);
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		goto done;
	}

	rc = gnutls_ocsp_resp_get_signature(resp, &sig);
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		goto done;
	}

	rc = gnutls_pubkey_verify_data2(pubkey, sigalg, 0, &data, &sig);
	if (rc == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
		gnutls_assert();
		*verify = GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE;
	} else if (rc < 0) {
		gnutls_assert();
		goto done;
	} else
		*verify = 0;

	rc = GNUTLS_E_SUCCESS;

      done:
	gnutls_free(sig.data);
	gnutls_pubkey_deinit(pubkey);

	return rc;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_req_set_extension(gnutls_ocsp_req_t req,
			      const char *oid,
			      unsigned int critical,
			      const gnutls_datum_t * data)
{
	if (req == NULL || oid == NULL || data == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	return _gnutls_set_extension(req->req, "tbsRequest.requestExtensions", oid,
			     data, critical);
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_req_set_nonce(gnutls_ocsp_req_t req,
			  unsigned int critical,
			  const gnutls_datum_t * nonce)
{
	int ret;
	gnutls_datum_t dernonce;
	unsigned char temp[SIZEOF_UNSIGNED_LONG_INT + 1];
	int len;

	if (req == NULL || nonce == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	asn1_length_der(nonce->size, temp, &len);

	dernonce.size = 1 + len + nonce->size;
	dernonce.data = gnutls_malloc(dernonce.size);
	if (dernonce.data == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	dernonce.data[0] = '\x04';
	memcpy(dernonce.data + 1, temp, len);
	memcpy(dernonce.data + 1 + len, nonce->data, nonce->size);

	ret = _gnutls_set_extension(req->req, "tbsRequest.requestExtensions",
			    GNUTLS_OCSP_NONCE, &dernonce, critical);
	gnutls_free(dernonce.data);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	return ret;
}

Project: gnutls
File: ocsp.c

time_t gnutls_ocsp_resp_get_produced(gnutls_ocsp_resp_t resp)
{
	char ttime[MAX_TIME];
	int len, ret;
	time_t c_time;

	if (resp == NULL || resp->basicresp == NULL) {
		gnutls_assert();
		return (time_t) (-1);
	}

	len = sizeof(ttime) - 1;
	ret =
	    asn1_read_value(resp->basicresp, "tbsResponseData.producedAt",
			    ttime, &len);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		return (time_t) (-1);
	}

	c_time = _gnutls_x509_generalTime2gtime(ttime);

	return c_time;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_req_add_cert_id(gnutls_ocsp_req_t req,
			    gnutls_digest_algorithm_t digest,
			    const gnutls_datum_t * issuer_name_hash,
			    const gnutls_datum_t * issuer_key_hash,
			    const gnutls_datum_t * serial_number)
{
	int result;
	const char *oid;

	if (req == NULL || issuer_name_hash == NULL
	    || issuer_key_hash == NULL || serial_number == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	oid = _gnutls_x509_digest_to_oid(hash_to_entry(digest));
	if (oid == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	result =
	    asn1_write_value(req->req, "tbsRequest.requestList", "NEW", 1);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	result = asn1_write_value
	    (req->req,
	     "tbsRequest.requestList.?LAST.reqCert.hashAlgorithm.algorithm",
	     oid, 1);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	/* XXX we don't support any algorithm with parameters */
	result = asn1_write_value
	    (req->req,
	     "tbsRequest.requestList.?LAST.reqCert.hashAlgorithm.parameters",
	     ASN1_NULL, ASN1_NULL_SIZE);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	result = asn1_write_value
	    (req->req,
	     "tbsRequest.requestList.?LAST.reqCert.issuerNameHash",
	     issuer_name_hash->data, issuer_name_hash->size);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	result = asn1_write_value
	    (req->req,
	     "tbsRequest.requestList.?LAST.reqCert.issuerKeyHash",
	     issuer_key_hash->data, issuer_key_hash->size);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	result = asn1_write_value
	    (req->req, "tbsRequest.requestList.?LAST.reqCert.serialNumber",
	     serial_number->data, serial_number->size);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	/* XXX add separate function that can add extensions too */
	result = asn1_write_value
	    (req->req,
	     "tbsRequest.requestList.?LAST.singleRequestExtensions", NULL,
	     0);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_get_nonce(gnutls_ocsp_resp_t resp,
			   unsigned int *critical, gnutls_datum_t * nonce)
{
	int ret;
	gnutls_datum_t tmp;

	ret =
	    _gnutls_get_extension(resp->basicresp,
			  "tbsResponseData.responseExtensions",
			  GNUTLS_OCSP_NONCE, 0, &tmp, critical);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	ret =
	    _gnutls_x509_decode_string(ASN1_ETYPE_OCTET_STRING, tmp.data,
				       (size_t) tmp.size, nonce, 0);
	if (ret < 0) {
		gnutls_assert();
		gnutls_free(tmp.data);
		return ret;
	}

	gnutls_free(tmp.data);

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

int gnutls_ocsp_req_init(gnutls_ocsp_req_t * req)
{
	gnutls_ocsp_req_t tmp =
	    gnutls_calloc(1, sizeof(gnutls_ocsp_req_int));
	int ret;

	if (!tmp)
		return GNUTLS_E_MEMORY_ERROR;

	ret = asn1_create_element(_gnutls_get_pkix(), "PKIX1.OCSPRequest",
				  &tmp->req);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		gnutls_free(tmp);
		return _gnutls_asn2err(ret);
	}

	*req = tmp;

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_req_get_extension(gnutls_ocsp_req_t req,
			      unsigned indx,
			      gnutls_datum_t * oid,
			      unsigned int *critical,
			      gnutls_datum_t * data)
{
	int ret;
	char str_critical[10];
	char name[ASN1_MAX_NAME_SIZE];
	int len;

	if (!req) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	snprintf(name, sizeof(name),
		 "tbsRequest.requestExtensions.?%u.critical", indx + 1);
	len = sizeof(str_critical);
	ret = asn1_read_value(req->req, name, str_critical, &len);
	if (ret == ASN1_ELEMENT_NOT_FOUND)
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	else if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(ret);
	}

	if (critical) {
		if (str_critical[0] == 'T')
			*critical = 1;
		else
			*critical = 0;
	}

	if (oid) {
		snprintf(name, sizeof(name),
			 "tbsRequest.requestExtensions.?%u.extnID",
			 indx + 1);
		ret = _gnutls_x509_read_value(req->req, name, oid);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			return ret;
		}
	}

	if (data) {
		snprintf(name, sizeof(name),
			 "tbsRequest.requestExtensions.?%u.extnValue",
			 indx + 1);
		ret = _gnutls_x509_read_value(req->req, name, data);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			if (oid)
				gnutls_free(oid->data);
			return ret;
		}
	}

	return GNUTLS_E_SUCCESS;
}

Project: gnutls
File: ocsp.c

int gnutls_ocsp_req_get_version(gnutls_ocsp_req_t req)
{
	uint8_t version[8];
	int len, ret;

	if (req == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	len = sizeof(version);
	ret =
	    asn1_read_value(req->req, "tbsRequest.version", version, &len);
	if (ret != ASN1_SUCCESS) {
		if (ret == ASN1_ELEMENT_NOT_FOUND)
			return 1;	/* the DEFAULT version */
		gnutls_assert();
		return _gnutls_asn2err(ret);
	}

	return (int) version[0] + 1;
}

Project: gnutls
File: ocsp.c

static gnutls_x509_crt_t find_signercert(gnutls_ocsp_resp_t resp)
{
	int rc;
	gnutls_x509_crt_t *certs = NULL;
	size_t ncerts = 0, i;
	gnutls_datum_t riddn = {NULL, 0};
	gnutls_datum_t keyid = {NULL, 0};
	gnutls_x509_crt_t signercert = NULL;

	rc = gnutls_ocsp_resp_get_responder_raw_id(resp, GNUTLS_OCSP_RESP_ID_DN, &riddn);
	if (rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
		gnutls_assert();
		rc = gnutls_ocsp_resp_get_responder_raw_id(resp, GNUTLS_OCSP_RESP_ID_KEY, &keyid);
	}
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return NULL;
	}

	rc = gnutls_ocsp_resp_get_certs(resp, &certs, &ncerts);
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		signercert = NULL;
		goto quit;
	}

	for (i = 0; i < ncerts; i++) {
		if (keyid.data != NULL) {
			uint8_t digest[20];
			gnutls_datum_t spki;

			rc = _gnutls_x509_get_raw_field2(certs[i]->cert, &certs[i]->der,
					  "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey",
					  &spki);
			if (rc < 0 || spki.size < 6) {
				signercert = NULL;
				goto quit;
			}

			/* For some reason the protocol requires we skip the
			 * tag, length and number of unused bits.
			 */
			spki.data += 5;
			spki.size -= 5;
			rc = gnutls_hash_fast(GNUTLS_DIG_SHA1, spki.data, spki.size, digest);
			if (rc < 0) {
				gnutls_assert();
				signercert = NULL;
				goto quit;
			}

			if ((20 == keyid.size) &&
				memcmp(keyid.data, digest, 20) == 0) {
				signercert = certs[i];
				goto quit;
			}
		} else {
			if ((certs[i]->raw_dn.size == riddn.size)
			    && memcmp(riddn.data, certs[i]->raw_dn.data, riddn.size) == 0) {
				signercert = certs[i];
				goto quit;
			}
		}
	}

	gnutls_assert();
	signercert = NULL;

      quit:
	gnutls_free(riddn.data);
	gnutls_free(keyid.data);
	for (i = 0; i < ncerts; i++)
		if (certs[i] != signercert)
			gnutls_x509_crt_deinit(certs[i]);
	gnutls_free(certs);
	return signercert;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_verify(gnutls_ocsp_resp_t resp,
			gnutls_x509_trust_list_t trustlist,
			unsigned int *verify, unsigned int flags)
{
	gnutls_x509_crt_t signercert = NULL;
	int rc;

	/* Algorithm:
	   1. Find signer cert.
	   1a. Search in OCSP response Certificate field for responderID.
	   1b. Verify that signer cert is trusted.
	   2a. It is in trustlist?
	   2b. It has OCSP key usage and directly signed by a CA in trustlist?
	   3. Verify signature of Basic Response using public key from signer cert.
	 */

	signercert = find_signercert(resp);
	if (!signercert) {
		gnutls_datum_t dn;

		rc = gnutls_ocsp_resp_get_responder_raw_id(resp, GNUTLS_OCSP_RESP_ID_DN, &dn);
		if (rc < 0) {
			gnutls_assert();
			*verify = GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND;
			rc = GNUTLS_E_SUCCESS;
			goto done;
		}

		rc = gnutls_x509_trust_list_get_issuer_by_dn(trustlist, &dn, &signercert, 0);
		gnutls_free(dn.data);

		if (rc < 0) {
			gnutls_assert();
			*verify = GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND;
			rc = GNUTLS_E_SUCCESS;
			goto done;
		}
	} else {
		/* Either the signer is directly trusted (i.e., in trustlist) or it
		   is directly signed by something in trustlist and has proper OCSP
		   extkeyusage. */
		rc = _gnutls_trustlist_inlist(trustlist, signercert);
		if (rc == 0) {
			/* not in trustlist, need to verify signature and bits */
			unsigned vtmp;
			gnutls_typed_vdata_st vdata;

			vdata.type = GNUTLS_DT_KEY_PURPOSE_OID;
			vdata.data = (void*)GNUTLS_KP_OCSP_SIGNING;
			vdata.size = 0;

			gnutls_assert();

			rc = gnutls_x509_trust_list_verify_crt2(trustlist,
								&signercert, 1,
								&vdata, 1,
								0, &vtmp, NULL);
			if (rc != GNUTLS_E_SUCCESS) {
				gnutls_assert();
				goto done;
			}

			if (vtmp != 0) {
				*verify = vstatus_to_ocsp_status(vtmp);
				gnutls_assert();
				rc = GNUTLS_E_SUCCESS;
				goto done;
			}
		}
	}

	rc = check_ocsp_purpose(signercert);
	if (rc < 0) {
		gnutls_assert();
		*verify = GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR;
		rc = GNUTLS_E_SUCCESS;
		goto done;
	}

	rc = _ocsp_resp_verify_direct(resp, signercert, verify, flags);

      done:
	gnutls_x509_crt_deinit(signercert);

	return rc;
}

Project: gnutls
File: ocsp.c

gnutls_ocsp_resp_get_signature(gnutls_ocsp_resp_t resp,
			       gnutls_datum_t * sig)
{
	int ret;

	if (resp == NULL || sig == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	ret = _gnutls_x509_read_value(resp->basicresp, "signature", sig);
	if (ret != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		return ret;
	}

	return GNUTLS_E_SUCCESS;
}