仅在 Docker 容器中:ec_key_simple_check_key:invalid 私钥

Only in Docker container: ec_key_simple_check_key:invalid private key

我使用 BouncyCastle.Crypto 1.8.5.0 创建一个 SecurityKey 以针对 Apple 的 APNS HTTP/2 端点进行身份验证。在 MacOS Mojave 上调试时它工作得很好,但是当我在 Docker 容器中部署时,出现以下异常:

Interop+Crypto+OpenSslCryptographicException: error:1010207B:elliptic curve routines:ec_key_simple_check_key:invalid private key
    at System.Security.Cryptography.ECOpenSsl.ImportParameters(ECParameters parameters)
    at System.Security.Cryptography.ECDsa.Create(ECParameters parameters)

阅读 this 后,我尝试通过设置环境变量 CLR_OPENSSL_VERSION_OVERRIDE=1.1 并确保在 Docker 文件中安装了最新的 openssl 来强制使用 OpenSSL 1.1,但没有修复.

读取私钥文件并初始化SecurityKey的代码:

using (var reader = System.IO.File.OpenText (PathToApnsKeyFile)) {
    var ecPrivateKeyParameters = (ECPrivateKeyParameters)new PemReader (reader).ReadObject ();
    var x = ecPrivateKeyParameters.Parameters.G.AffineXCoord.GetEncoded ();
    var y = ecPrivateKeyParameters.Parameters.G.AffineYCoord.GetEncoded ();
    var d = ecPrivateKeyParameters.D.ToByteArrayUnsigned ();
    // Convert the BouncyCastle key to a Native Key.
    var msEcp = new ECParameters { Curve = ECCurve.NamedCurves.nistP256, Q = { X = x, Y = y }, D = d };
    jwtPrivateKey = new ECDsaSecurityKey (ECDsa.Create (msEcp));
}

Docker文件:

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-bionic AS build-env
WORKDIR /app

# copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out -r linux-x64

# build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-bionic AS runtime
RUN apt-get update && apt-get -y install openssl
WORKDIR /app
COPY --from=build-env /app/out ./
ENTRYPOINT ["dotnet", "helloapple.dll"]

更新

我的 MacOS 似乎正在使用 LibreSSL 2.6.5。 apt-get拉取的openssl版本为1.1.1-1ubuntu2.1~18.04.7.

我终于找到了答案。原来问题出在曲线参数的实现上,这在平台之间是不同的。上面的代码适用于 Windows 和 Mac,但显然不适用于 Linux。正确的计算是:

var q = ecPrivateKeyParameters.Parameters.G.Multiply (ecPrivateKeyParameters.D).Normalize ();
var x = q.AffineXCoord.GetEncoded ();
var y = q.AffineYCoord.GetEncoded ();
var d = ecPrivateKeyParameters.D.ToByteArrayUnsigned ();
// Convert the BouncyCastle key to a Native Key.
var msEcp = new ECParameters { Curve = ECCurve.NamedCurves.nistP256, Q = { X = x, Y = y }, D = d };

在 github 的以下评论中找到了解决方案:

https://github.com/dotnet/core/issues/2037#issuecomment-436340605