When I started working on this question, I thought it would be easy. After half a day of researches (so cool that I'm on vacation), I could finally share the results.
HttpContext.Response.Headers has type of IHeaderDictionary. By default, in ASP.NET Core application on Kestrel, FrameResponseHeaders implementation is used. The main logic resides in FrameHeaders base class. This headers dictionary is highly optimized for seting / getting of frequently used standard http headers. Here is a code snippet that handles setting cookie (AddValueFast method):
if ("Set-Cookie".Equals(key, StringComparison.OrdinalIgnoreCase))
{
    if ((_bits & 67108864L) == 0)
    {
        _bits |= 67108864L;
        _headers._SetCookie = value;
        return true;
    }
    return false;
}
As far as StringComparison.OrdinalIgnoreCase is used for key comparison, you can't set another cookie header that differs only by the case. This makes sense because HTTP headers are case-insensitive.
But let's try to overcome it.
The obvious solution here is to replace implementation of IHeaderDictionary with the case-sensitive one. ASP.NET Core contains a lot of seams and extensibility points for this, starting from IHttpResponseFeature that contains setable Headers property and ending with the possibility to replace implementation of HttpContext.
Unfortunately, all those replacements will not do the trick when running on Kestrel. If you check source code of Frame class that is responsible for writing HTTP response headers, you will see that it creates instance of FrameResponseHeaders by itself and does not respect any other instances set through IHttpResponseFeature or HttpContext.Response.Headers:
protected FrameResponseHeaders FrameResponseHeaders { get; } = new FrameResponseHeaders();
So we should return back to FrameResponseHeaders and its base FrameHeaders classes and try to adjust their behavior.
FrameResponseHeaders class uses fast setting of known headers (see AddValueFast above) but stores all other unknown headers in MaybeUnknown field:
protected Dictionary<string, StringValues> MaybeUnknown;
which is initialized as:
MaybeUnknown = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase);
We could try to bypass fast header setting and add them directly to the MaybeUnknown dictionary. We should however replace the dictionary created with StringComparer.OrdinalIgnoreCase comparer with the default implementation that is case-sensitive.
MaybeUnknown is a protected field and again we can't make Kestrel to use our custom implementation for holding class. That's why we are forced to set this field through reflection.
I've put all this dirty code into extension class over FrameHeaders:
public static class FrameHeadersExtensions
{
    public static void MakeCaseInsensitive(this FrameHeaders target)
    {
        var fieldInfo = GetDictionaryField(target.GetType());
        fieldInfo.SetValue(target, new Dictionary<string, StringValues>());
    }
    public static void AddCaseInsensitiveHeader(this FrameHeaders target, string key, string value)
    {
        var fieldInfo = GetDictionaryField(target.GetType());
        var values = (Dictionary<string, StringValues>)fieldInfo.GetValue(target);
        values.Add(key, value);
    }
    private static FieldInfo GetDictionaryField(Type headersType)
    {
        var fieldInfo = headersType.GetField("MaybeUnknown", BindingFlags.Instance | BindingFlags.NonPublic);
        if (fieldInfo == null)
        {
            throw new InvalidOperationException("Failed to get field info");
        }
        return fieldInfo;
    }
}
MakeCaseInsensitive replaces MaybeUnknown with case-sensitive dictionary.
AddCaseInsensitiveHeader adds header directly to MaybeUnknown dictionary bypassing fast header setting.
Remaining part is only to call these methods in appropriate places in the controller:
[Route("api/[controller]")]
public class TestController : Controller
{
    [NonAction]
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var responseHeaders = (FrameResponseHeaders)HttpContext.Response.Headers;
        responseHeaders.MakeCaseInsensitive();
    }
    // GET api/values
    [HttpGet]
    public string Get()
    {
        var responseHeaders = (FrameResponseHeaders)HttpContext.Response.Headers;
        responseHeaders.AddCaseInsensitiveHeader("Set-Cookie", "Cookies1");
        responseHeaders.AddCaseInsensitiveHeader("SET-COOKIE", "Cookies2");
        return "Hello";
    }
}
Here is result headers set:

Described solution is a very dirty hack. It will work only with Kestrel and things could change with future releases. Everything would be much easier and cleaner if Kestrel fully supports ASP.NET seams. But if you don't have any other choices for this moment, I hope this will help you.