int x509_cert_build_create_ca_signed_certificate()

in core/asn1/x509_cert_build.c [718:875]


int x509_cert_build_create_ca_signed_certificate (const struct x509_engine *engine,
	struct x509_certificate *cert, const uint8_t *key, size_t key_length, const uint8_t *serial_num,
	size_t serial_length, const char *name, int type, const uint8_t *ca_priv_key,
	size_t ca_key_length, enum hash_type sig_hash, const struct x509_certificate *ca_cert,
	const struct x509_extension_builder *const *extra_extensions, size_t ext_count)
{
	const struct x509_engine_cert_build *x509 = (const struct x509_engine_cert_build*) engine;
	DERBuilderContext *der;
	DERBuilderContext *ca_ctx;
	struct ecc_public_key auth_pub_key;
	uint8_t *auth_key_der;
	size_t auth_key_der_len;
	const uint8_t *auth_key;
	uint8_t auth_key_digest[SHA1_DIGEST_LENGTH];
	struct ecc_public_key subject_pub_key;
	const uint8_t *subject_key_der = key;
	size_t subject_key_der_len = key_length;
	const uint8_t *subject_key;
	size_t subject_key_len;
	uint8_t subject_key_digest[SHA1_DIGEST_LENGTH];
	const int *sig_oid;
	char *issuer = NULL;
	int status;

	if ((x509 == NULL) || (cert == NULL) || (key == NULL) || (key_length == 0) ||
		(serial_num == NULL) || (serial_length == 0) || (name == NULL) || (ca_priv_key == NULL) ||
		(ca_key_length == 0) || (ca_cert == NULL)) {
		return X509_ENGINE_INVALID_ARGUMENT;
	}

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

	switch (sig_hash) {
		case HASH_TYPE_SHA256:
			sig_oid = ecdsaWithSHA256OID;
			break;

		case HASH_TYPE_SHA384:
			sig_oid = ecdsaWithSHA384OID;
			break;

		case HASH_TYPE_SHA512:
			sig_oid = ecdsaWithSHA512OID;
			break;

		default:
			return X509_ENGINE_UNSUPPORTED_SIG_HASH;
	}

	status = x509_cert_build_check_serial_number (serial_num, serial_length);
	if (status != 0) {
		return status;
	}

	cert->context = NULL;
	ca_ctx = (DERBuilderContext*) ca_cert->context;

	status = x509->ecc->init_key_pair (x509->ecc, ca_priv_key, ca_key_length, NULL, &auth_pub_key);
	if (status != 0) {
		return status;
	}

	status = x509->ecc->get_public_key_der (x509->ecc, &auth_pub_key, &auth_key_der,
		&auth_key_der_len);
	if (status != 0) {
		goto err_free_key;
	}

	status = ecc_der_decode_public_key_no_copy (auth_key_der, auth_key_der_len, &auth_key);
	if (ROT_IS_ERROR (status)) {
		/* This is highly unlikely since the encoded DER just came from the ECC engine. */
		goto err_free_key;
	}

	status = x509->hash->calculate_sha1 (x509->hash, auth_key, status, auth_key_digest,
		sizeof (auth_key_digest));
	if (status != 0) {
		goto err_free_key_der;
	}

	status = DERDECGetPubKey (&subject_key, &subject_key_len, key, key_length);
	if (status != 0) {
		/* The key data does not contain a public key.  Get the public key from the private key. */
		status = x509->ecc->init_key_pair (x509->ecc, key, key_length, NULL, &subject_pub_key);
		if (status != 0) {
			goto err_free_key_der;
		}

		status = x509->ecc->get_public_key_der (x509->ecc, &subject_pub_key,
			(uint8_t**) &subject_key_der, &subject_key_der_len);
		x509->ecc->release_key_pair (x509->ecc, NULL, &subject_pub_key);
		if (status != 0) {
			goto err_free_key_der;
		}

		status = ecc_der_decode_public_key_no_copy (subject_key_der, subject_key_der_len,
			&subject_key);
		if (ROT_IS_ERROR (status)) {
			/* This is highly unlikely since the encoded DER just came from the ECC engine. */
			goto err_free_key_der;
		}

		subject_key_len = status;
	}

	status = x509->hash->calculate_sha1 (x509->hash, subject_key, subject_key_len,
		subject_key_digest, sizeof (subject_key_digest));
	if (status != 0) {
		goto err_free_key_der;
	}

	status = DERDECGetSubjectName (&issuer, ca_ctx->Buffer, DERGetEncodedLength (ca_ctx));
	if (status != RIOT_SUCCESS) {
		status = X509_ENGINE_CA_SIGNED_FAILED;
		goto err_free_key_der;
	}

	der = x509_cert_build_new_cert (x509);
	if (der == NULL) {
		status = X509_ENGINE_NO_MEMORY;
		goto err_free_name;
	}

	status = x509_cert_build_build_certificate_tbs_data (der, issuer, auth_key_digest, name,
		subject_key_digest, serial_num, serial_length, subject_key_der, subject_key_der_len,
		sig_oid, type, extra_extensions, ext_count);
	if (status != 0) {
		status = (status == -1) ? X509_ENGINE_CA_SIGNED_FAILED : status;
		goto err_free_cert;
	}

	status = x509_cert_build_sign_certificate (der, ca_priv_key, ca_key_length, x509->ecc,
		x509->hash, sig_hash, sig_oid);
	if (status == -1) {
		status = X509_ENGINE_CA_SIGNED_FAILED;
	}

err_free_cert:
	if (status == 0) {
		cert->context = der;
	}
	else {
		x509_cert_build_free_cert (der);
	}
err_free_name:
	platform_free (issuer);
err_free_key_der:
	platform_free (auth_key_der);
	if (subject_key_der != key) {
		platform_free ((void*) subject_key_der);
	}
err_free_key:
	x509->ecc->release_key_pair (x509->ecc, NULL, &auth_pub_key);

	return status;
}