static int x509_openssl_create_certificate()

in projects/linux/asn1/x509_openssl.c [555:752]


static int x509_openssl_create_certificate (struct x509_certificate *cert, EVP_PKEY *cert_key,
	enum hash_type sig_hash, const uint8_t *serial_num, size_t serial_length, const char *name,
	int type, EVP_PKEY *ca_key, const struct x509_certificate *ca_cert,
	const struct x509_extension_builder *const *extra_extensions, size_t ext_count)
{
	X509 *x509;
	X509 *ca_x509;
	BIGNUM *serial;
	X509_NAME *subject;
	ASN1_TIME *validity;
	const EVP_MD *hash_algo;
	char *key_usage;
	size_t i;
	int status;

	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 ();

	x509 = X509_new ();
	if (x509 == NULL) {
		status = -ERR_get_error ();
		goto err_cert;
	}

	if (ca_key) {
		ca_x509 = (X509*) ca_cert->context;
	}
	else {
		ca_x509 = x509;
	}

	status = X509_set_pubkey (x509, cert_key);
	if (status == 0) {
		status = -ERR_get_error ();
		goto err_req_key;
	}

	status = X509_set_version (x509, 2);
	if (status == 0) {
		status = -ERR_get_error ();
		goto err_req_key;
	}

	serial = BN_bin2bn (serial_num, serial_length, NULL);
	if (serial == NULL) {
		status = -ERR_get_error ();
		goto err_serial;
	}

	if (BN_is_zero (serial)) {
		status = X509_ENGINE_INVALID_SERIAL_NUM;
		goto err_serial;
	}

	if (BN_to_ASN1_INTEGER (serial, X509_get_serialNumber (x509)) == NULL) {
		status = -ERR_get_error ();
		goto err_serial;
	}

	subject = X509_get_subject_name (x509);
	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_serial;
	}

	subject = X509_get_subject_name (ca_x509);
	status = X509_set_issuer_name (x509, subject);
	if (status == 0) {
		status = -ERR_get_error ();
		goto err_serial;
	}

	validity = X509_get_notBefore (x509);
	status = ASN1_TIME_set_string (validity, "180101000000Z");
	if (status == 0) {
		status = -ERR_get_error ();
		goto err_serial;
	}

	validity = X509_get_notAfter (x509);
	status = ASN1_TIME_set_string (validity, "99991231235959Z");
	if (status == 0) {
		status = -ERR_get_error ();
		goto err_serial;
	}

	status = x509_openssl_add_standard_v3_extension (x509, ca_x509, NID_subject_key_identifier,
		"hash");
	if (status != 0) {
		goto err_serial;
	}

	status = x509_openssl_add_standard_v3_extension (x509, ca_x509,
		NID_authority_key_identifier, "keyid:always");
	if (status != 0) {
		goto err_serial;
	}

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

	status = x509_openssl_add_standard_v3_extension (x509, ca_x509, NID_key_usage, key_usage);
	if (status != 0) {
		goto err_serial;
	}

	if (type == X509_CERT_END_ENTITY) {
		status = x509_openssl_add_standard_v3_extension (x509, ca_x509, NID_ext_key_usage,
			"critical,clientAuth");
		if (status != 0) {
			goto err_serial;
		}
	}

	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_v3_extension (x509, ca_x509, NID_basic_constraints,
			constraint);
		if (status != 0) {
			goto err_serial;
		}
	}

	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_serial;
			}

			status = x509_openssl_add_custom_v3_extension (x509, ext, ext_data);
			if (status != 0) {
				goto err_serial;
			}
		}
	}

	if (ca_key) {
		status = X509_sign (x509, ca_key, hash_algo);
	}
	else {
		status = X509_sign (x509, cert_key, hash_algo);
	}

	if (status == 0) {
		status = -ERR_get_error ();
		goto err_serial;
	}

	cert->context = x509;
	status = 0;

err_serial:
	BN_free (serial);
err_req_key:
	if (status != 0) {
		X509_free (x509);
	}
err_cert:
	return status;
}