.Net Core中ECDsa签名SXGs更新请求提示公钥签名无效
问题原因分析
你遇到的签名验证失败,核心原因是**.NET Core生成的签名格式与OpenSSL dgst -sign输出的格式不一致**:
- OpenSSL的
dgst -sign默认输出ASN.1 DER格式的ECDSA签名(包含SEQUENCE包裹的r和s整数) - .NET Core的
ECDsa.SignData默认输出IEEE P1363格式的签名(直接拼接r和s的字节数组)
缓存服务器期望的是OpenSSL兼容的ASN.1 DER格式签名,所以需要对.NET生成的签名做格式转换。
解决方案
修改你的.NET代码,将P1363格式的签名转换为ASN.1 DER格式,具体步骤如下:
1. 添加签名格式转换方法
新增一个方法,将P1363格式的签名字节数组转换为ASN.1 DER格式:
private static byte[] ConvertP1363ToDer(byte[] p1363Signature) { // 对于prime256v1,r和s各32字节 int halfLength = p1363Signature.Length / 2; byte[] r = p1363Signature.Take(halfLength).ToArray(); byte[] s = p1363Signature.Skip(halfLength).ToArray(); // 处理整数的DER编码:去掉前导零,若最高位为1则加0x00前缀 r = PrepareDerInteger(r); s = PrepareDerInteger(s); // 构建SEQUENCE:0x30 + 总长度 + r的DER编码 + s的DER编码 int sequenceLength = 2 + r.Length + 2 + s.Length; using (var ms = new MemoryStream()) { ms.WriteByte(0x30); WriteLength(ms, sequenceLength); ms.WriteByte(0x02); WriteLength(ms, r.Length); ms.Write(r); ms.WriteByte(0x02); WriteLength(ms, s.Length); ms.Write(s); return ms.ToArray(); } } private static byte[] PrepareDerInteger(byte[] data) { // 去掉前导零 int startIndex = 0; while (startIndex < data.Length && data[startIndex] == 0) { startIndex++; } if (startIndex == data.Length) { return new byte[] { 0x00 }; // 表示整数0 } // 如果最高位是1,添加0x00前缀避免被解析为负数 if ((data[startIndex] & 0x80) != 0) { var result = new byte[data.Length - startIndex + 1]; result[0] = 0x00; Buffer.BlockCopy(data, startIndex, result, 1, data.Length - startIndex); return result; } return data.Skip(startIndex).ToArray(); } private static void WriteLength(MemoryStream ms, int length) { if (length < 0x80) { ms.WriteByte((byte)length); } else { // 处理长长度(这里prime256v1的签名不会用到,仅做兼容) byte[] lengthBytes = BitConverter.GetBytes(length).Reverse().ToArray(); ms.WriteByte((byte)(0x80 | lengthBytes.Length)); ms.Write(lengthBytes); } }
2. 修改签名生成逻辑
在生成签名后,调用转换方法将格式转为ASN.1 DER:
string timestamp = ((int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds).ToString(); string message = url + " " + timestamp; string signature = ""; using (ECDsa ecDsa = ECDsa.Create()) { string key = File.ReadAllText(ecprivkeyPath); ecDsa.ImportFromPem(key); byte[] data = Encoding.ASCII.GetBytes(message); byte[] p1363Signature = ecDsa.SignData(data, HashAlgorithmName.SHA256); // 转换为ASN.1 DER格式 byte[] derSignature = ConvertP1363ToDer(p1363Signature); signature = Convert.ToBase64String(derSignature); }
3. 其他验证点
- 确认
url变量与bash脚本中的URL完全一致(包括协议、域名、路径,无多余空格) - 确认私钥文件读取正确,没有额外的换行或空格
- 确认timestamp是UTC时间戳(你的代码已经用了
DateTime.UtcNow,没问题)
测试验证
可以将.NET生成的signature和bash脚本生成的signature对比:
- 用bash脚本生成一个固定timestamp的signature
- 在.NET中手动设置相同的timestamp,生成signature
- 对比两个base64字符串是否一致,一致则说明格式转换正确
内容的提问来源于stack exchange,提问作者Naveed Ahmed
相关产品推荐
相关产品推荐

