int x509_openssl_create_csr()

in projects/linux/asn1/x509_openssl.c [270:467]


int x509_openssl_create_csr (const struct x509_engine *engine, const uint8_t *priv_key,
	size_t key_length, enum hash_type sig_hash, const char *name, int type, const uint8_t *eku,
	size_t eku_length, const struct x509_extension_builder *const *extra_extensions,
	size_t ext_count, uint8_t **csr, size_t *csr_length)
{
	X509_REQ *request;
	EVP_PKEY *req_key;
	X509_NAME *subject;
	STACK_OF (X509_EXTENSION) *extensions;
	const EVP_MD *hash_algo;
	char *key_usage;
	size_t i;
	int status;

	if (csr == NULL) {
		return X509_ENGINE_INVALID_ARGUMENT;
	}

	*csr = NULL;
	if ((engine == NULL) || (priv_key == NULL) || (name == NULL) || (csr_length == NULL) ||
		(key_length == 0)) {
		return X509_ENGINE_INVALID_ARGUMENT;
	}

	if ((eku_length != 0) && (eku == NULL)) {
		return X509_ENGINE_INVALID_ARGUMENT;
	}

	if ((ext_count != 0) && (extra_extensions == NULL)) {
		return X509_ENGINE_INVALID_ARGUMENT;
	}

	if ((type == X509_CERT_END_ENTITY) && (eku != NULL)) {
		return X509_ENGINE_NOT_CA_CERT;
	}

	switch (sig_hash) {
		case HASH_TYPE_SHA256:
			hash_algo = EVP_sha256 ();
			break;

#ifdef HASH_ENABLE_SHA384
		case HASH_TYPE_SHA384:
			hash_algo = EVP_sha384 ();
			break;
#endif

#ifdef HASH_ENABLE_SHA512
		case HASH_TYPE_SHA512:
			hash_algo = EVP_sha512 ();
			break;
#endif

		default:
			return X509_ENGINE_UNSUPPORTED_SIG_HASH;
	}

	ERR_clear_error ();

	request = X509_REQ_new ();
	if (request == NULL) {
		status = -ERR_get_error ();
		goto err_req;
	}

	status = x509_openssl_load_key (&req_key, priv_key, key_length, true);
	if (status != 0) {
		goto err_key;
	}

	status = X509_REQ_set_pubkey (request, req_key);
	if (status == 0) {
		status = -ERR_get_error ();
		goto err_req_key;
	}

	subject = X509_REQ_get_subject_name (request);
	status = X509_NAME_add_entry_by_txt (subject, "CN", MBSTRING_ASC, (unsigned char*) name,
		-1, -1, 0);
	if (status == 0) {
		status = -ERR_get_error ();
		goto err_req_key;
	}

	extensions = sk_X509_EXTENSION_new_null ();
	if (extensions == NULL) {
		status = X509_ENGINE_NO_MEMORY;
		goto err_req_key;
	}

	if (type) {
		key_usage = "critical,keyCertSign";
	}
	else {
		key_usage = "critical,digitalSignature,keyAgreement";
	}

	status = x509_openssl_add_standard_csr_extension (request, extensions, NID_key_usage,
		key_usage);
	if (status != 0) {
		goto err_ext;
	}

	if (type == X509_CERT_END_ENTITY) {
		status = x509_openssl_add_standard_csr_extension (request, extensions, NID_ext_key_usage,
			"critical,clientAuth");
		if (status != 0) {
			goto err_ext;
		}
	}

	if (eku != NULL) {
		ASN1_OBJECT *oid;
		char oid_str[256];

		status = x509_openssl_parse_encoded_oid (eku, eku_length, &oid);
		if (status != 0) {
			goto err_ext;
		}

		status = OBJ_obj2txt (oid_str, sizeof (oid_str), oid, 1);
		ASN1_OBJECT_free (oid);
		if (status > (int) sizeof (oid_str)) {
			status = X509_ENGINE_LONG_OID;
			goto err_ext;
		}

		status = x509_openssl_add_standard_csr_extension (request, extensions, NID_ext_key_usage,
			oid_str);
		if (status != 0) {
			goto err_ext;
		}
	}

	if (type) {
		char constraint[35];

		if (X509_CERT_PATHLEN (type) <= X509_CERT_MAX_PATHLEN) {
			sprintf (constraint, "critical,CA:TRUE,pathlen:%d", X509_CERT_PATHLEN (type));
		}
		else {
			strcpy (constraint, "critical,CA:TRUE");
		}

		status = x509_openssl_add_standard_csr_extension (request, extensions,
			NID_basic_constraints, constraint);
		if (status != 0) {
			goto err_ext;
		}
	}

	for (i = 0; i < ext_count; i++) {
		X509_EXTENSION *ext;
		ASN1_OCTET_STRING *ext_data;

		if (extra_extensions[i] != NULL) {
			status = x509_openssl_create_custom_extension (extra_extensions[i], &ext, &ext_data);
			if (status != 0) {
				goto err_ext;
			}

			status = x509_openssl_add_custom_csr_extension (request, extensions, ext, ext_data);
			if (status != 0) {
				goto err_ext;
			}
		}
	}

	status = X509_REQ_add_extensions (request, extensions);
	if (status == 0) {
		status = -ERR_get_error ();
		goto err_ext;
	}

	status = X509_REQ_sign (request, req_key, hash_algo);
	if (status == 0) {
		status = -ERR_get_error ();
		goto err_ext;
	}

	status = i2d_X509_REQ (request, csr);
	if (status >= 0) {
		*csr_length = status;
		status = 0;
	}
	else {
		status = -ERR_get_error ();
	}

err_ext:
	sk_X509_EXTENSION_pop_free (extensions, X509_EXTENSION_free);
err_req_key:
	EVP_PKEY_free (req_key);
err_key:
	X509_REQ_free (request);
err_req:
	return status;
}