mirror of
https://github.com/239573049/FastGateway.git
synced 2026-10-16 21:10:58 +08:00
fix(acme): 修复挑战验证阶段匿名 {} 载荷在 AOT 下无 JsonTypeInfo 崩溃
ChallengeContext.Validate 使用 new {} 作为空对象载荷,Native AOT 下
CertesJsonContext.GetTypeInfo(匿名类型) 返回 null,JwsSigner.Sign 调用
JsonSerializer.Serialize(payload, null) 抛出 ArgumentNullException,
导致证书申请在挑战验证阶段失败。
- 新增已注册的 EmptyObject 载荷类型,序列化为 {}(RFC 8555 §7.5.1)
- JwsSigner.Sign 对无法解析元数据的载荷抛出可诊断的 InvalidOperationException,
而非深层 STJ 的裸 ArgumentNullException
- 保留 null 载荷 -> 空串(POST-as-GET)语义
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Certes.Acme.Resource;
|
||||
using Certes.Jws;
|
||||
|
||||
namespace Certes.Acme
|
||||
{
|
||||
@@ -60,7 +61,10 @@ namespace Certes.Acme
|
||||
/// </returns>
|
||||
public async Task<Challenge> Validate()
|
||||
{
|
||||
var resp = await Context.HttpClient.Post<Challenge>(Context, Location, new {}, true);
|
||||
// RFC 8555 §7.5.1: the challenge-trigger POST carries an empty JSON object.
|
||||
// Must be a concrete, source-gen-registered type (EmptyObject) — an anonymous
|
||||
// `new {}` has no JsonTypeInfo under Native AOT and throws in JwsSigner.Sign.
|
||||
var resp = await Context.HttpClient.Post<Challenge>(Context, Location, new EmptyObject(), true);
|
||||
return resp.Resource;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Certes.Json
|
||||
[JsonSerializable(typeof(EcJsonWebKey))]
|
||||
[JsonSerializable(typeof(RsaJsonWebKey))]
|
||||
[JsonSerializable(typeof(KeyChangePayload))]
|
||||
[JsonSerializable(typeof(EmptyObject))]
|
||||
[JsonSerializable(typeof(ExternalAccountBinding))]
|
||||
[JsonSerializable(typeof(ExternalAccountBindingHeader))]
|
||||
// ACME resources
|
||||
|
||||
@@ -45,6 +45,16 @@ namespace Certes.Jws
|
||||
public object OldKey { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An empty JWS payload that serializes to <c>{}</c>. Used for requests whose body
|
||||
/// is an empty JSON object (e.g. the RFC 8555 §7.5.1 challenge-validation trigger).
|
||||
/// A concrete, source-gen-registered type is required so serialization is AOT-safe;
|
||||
/// an anonymous <c>new {}</c> has no JsonTypeInfo and throws under Native AOT.
|
||||
/// </summary>
|
||||
internal class EmptyObject
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// External account binding JWS, embedded into the new-account request.
|
||||
/// </summary>
|
||||
|
||||
@@ -62,9 +62,28 @@ namespace Certes.Jws
|
||||
Url = url,
|
||||
};
|
||||
|
||||
var entityJson = payload == null
|
||||
? ""
|
||||
: JsonSerializer.Serialize(payload, CertesJsonContext.Default.GetTypeInfo(payload.GetType()));
|
||||
string entityJson;
|
||||
if (payload == null)
|
||||
{
|
||||
// POST-as-GET: RFC 8555 §6.3 requires an empty (not "{}") payload.
|
||||
entityJson = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
var payloadType = payload.GetType();
|
||||
var typeInfo = CertesJsonContext.Default.GetTypeInfo(payloadType);
|
||||
if (typeInfo == null)
|
||||
{
|
||||
// Anonymous/unregistered types have no source-generated metadata and
|
||||
// would otherwise surface as an opaque ArgumentNullException from
|
||||
// System.Text.Json under Native AOT. Point at the real cause instead.
|
||||
throw new InvalidOperationException(
|
||||
$"No JSON metadata for payload type '{payloadType}'. Add it to " +
|
||||
$"{nameof(CertesJsonContext)} (anonymous types are not supported under AOT).");
|
||||
}
|
||||
|
||||
entityJson = JsonSerializer.Serialize(payload, typeInfo);
|
||||
}
|
||||
var protectedHeaderJson = JsonSerializer.Serialize(protectedHeader, CertesJsonContext.Default.JwsHeader);
|
||||
|
||||
var payloadEncoded = JwsConvert.ToBase64String(Encoding.UTF8.GetBytes(entityJson));
|
||||
|
||||
Reference in New Issue
Block a user