使用SoftHSM 2.2.0(带SHA256的ECDSA)C#net从Pkcs11Interop为CKM_ECDSA_SHA256签署PDF

使用SoftHSM 2.2.0(带SHA256的ECDSA)C#net从Pkcs11Interop为CKM_ECDSA_SHA256签署PDF,c#,pkcs#11,ecdsa,softhsm,pkcs11interop,C#,Pkcs#11,Ecdsa,Softhsm,Pkcs11interop,我正在尝试使用Pkcs11Interop.net库对Pdf文档进行签名。 我需要将ECDSA加密算法与SHA256哈希算法一起使用。 我正在使用SoftHSM 2.2.0来存储私钥 我找到了一个CKM枚举,CKM_ECDSA_SHA256,我在创建一个类对象机制以调用会话的Sign方法时传递了它 我从“Signdata”方法得到响应,但是,打开签名后生成的Pdf文件时,会出现错误“签名无效”。 下面是Signdata方法调用的代码片段。 我没有在代码中得到任何错误或异常,但是,我提到的pdf显示

我正在尝试使用Pkcs11Interop.net库对Pdf文档进行签名。 我需要将ECDSA加密算法与SHA256哈希算法一起使用。 我正在使用SoftHSM 2.2.0来存储私钥

我找到了一个CKM枚举,CKM_ECDSA_SHA256,我在创建一个类对象机制以调用会话的Sign方法时传递了它

我从“Signdata”方法得到响应,但是,打开签名后生成的Pdf文件时,会出现错误“签名无效”。 下面是Signdata方法调用的代码片段。 我没有在代码中得到任何错误或异常,但是,我提到的pdf显示签名无效

private Pkcs11 _pkcs11;
private Slot _slot;
private Session _session;

try
{
   _pkcs11 = new Pkcs11(hsmCryptoApi, true);
}
catch (Pkcs11Exception ex)
{
   if (ex.RV == CKR.CKR_CANT_LOCK)
      _pkcs11 = new Pkcs11(hsmCryptoApi, false);
   else
       throw ex;
}

_slot = FindSlot(_pkcs11, _certificateInformation.TokenLabel);
_session = _slot.OpenSession(true);

using (Mechanism mechanism = new Mechanism(CKM.CKM_ECDSA_SHA256))
{
  _session.Login(CKU.CKU_USER, passowrd);
  byte[] signedHash = _session.Sign(mechanism, GetPrivateKeyHandle(), message);
  _session.Logout();
  return signedHash;
}

private ObjectHandle GetPrivateKeyHandle()
{
  string keyLabel = _certificateInformation.KeyLabel;
  List<ObjectAttribute> searchTemplate = new List<ObjectAttribute>();
  searchTemplate.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
  searchTemplate.Add(new ObjectAttribute(CKA.CKA_LABEL, keyLabel));
  List<ObjectHandle> foundObjects = _session.FindAllObjects(searchTemplate);
  return foundObjects[0]; 
}
private Pkcs11\u Pkcs11;
专用槽(u槽),;
非公开会议;
尝试
{
_pkcs11=新的pkcs11(hsmCryptoApi,true);
}
捕获(PKCS11Ex异常)
{
如果(ex.RV==CKR.CKR\u CANT\u LOCK)
_pkcs11=新的pkcs11(hsmCryptoApi,false);
其他的
掷骰子;
}
_slot=FindSlot(_pkcs11,_certificateInformation.TokenLabel);
_session=\u slot.OpenSession(true);
使用(机制=新机制(CKM.CKM_ECDSA_SHA256))
{
_登录(CKU.CKU_用户,passowrd);
字节[]signedHash=_session.Sign(机制,GetPrivateKeyHandle(),消息);
_session.Logout();
返回signedHash;
}
私有对象句柄GetPrivateKeyHandle()
{
字符串keyLabel=\u certificateInformation.keyLabel;
列表搜索模板=新列表();
添加(新的ObjectAttribute(CKA.CKA_类,CKO.CKO_私钥));
添加(新的ObjectAttribute(CKA.CKA_标签,keyLabel));
List foundObjects=_session.FindAllObjects(searchTemplate);
返回foundObjects[0];
}
  • 请告诉我SoftHSM 2.2.0是否支持带有SHA256的ECDSA_P256
  • 如果没有,那么有没有办法启用支持
  • 如果它确实支持,请帮助我如何修复此
  • 看起来它想让我传递ECDSA_参数,有人有任何传递ECDSA_参数的代码片段吗

我认为您需要构造
ECDSA Sig Value
结构,并用
signedHash
变量中的数据填充它

第12.3.1章:

出于这些机制的目的,ECDSA签名是八位字节 长度为偶数的字符串,最多为nLen八位字节的两倍,其中 nLen是基点顺序n的长度(以八位字节为单位)。签名 八位字节对应于ECDSA值r和s的串联, 两者都表示为长度相等的八位字节字符串,最多为nLen 以最高有效字节开头。如果r和s有不同的八位组 长度,两者中较短的必须用前导零八位字节填充 使两者具有相同的八位组长度。粗略地说,第一个 签名的一半是r,另一半是s。签名 由令牌创建,结果签名的长度始终为2nLen。 对于传递给令牌进行验证的签名,签名可以 长度较短,但必须按照之前的规定进行组合

第7.2章:

将ECDSA与SignedData一起使用时,ECDSA签名使用 类型:

ECDSA-Sig-Value ::= SEQUENCE {
    r INTEGER,
    s INTEGER }
ECDSA Sig值在[PKI-ALG]中指定。在CMS内, ECDSA Sig值是DER编码的,并放置在的签名字段中 签名数据

以下方法使用库构造DER编码的ECDSA Sig值结构:

public static byte[] ConstructEcdsaSigValue(byte[] rs)
{
    if (rs == null)
        throw new ArgumentNullException(nameof(rs));

    if (rs.Length < 2 || rs.Length % 2 != 0)
        throw new ArgumentException("Invalid length", nameof(rs));

    int halfLen = rs.Length / 2;

    byte[] half1 = new byte[halfLen];
    Array.Copy(rs, 0, half1, 0, halfLen);
    var r = new Org.BouncyCastle.Math.BigInteger(1, half1);

    byte[] half2 = new byte[halfLen];
    Array.Copy(rs, halfLen, half2, 0, halfLen);
    var s = new Org.BouncyCastle.Math.BigInteger(1, half2);

    var derSequence = new Org.BouncyCastle.Asn1.DerSequence(
        new Org.BouncyCastle.Asn1.DerInteger(r),
        new Org.BouncyCastle.Asn1.DerInteger(s));

    return derSequence.GetDerEncoded();
}
publicstaticbyte[]constructedsasigvalue(byte[]rs)
{
如果(rs==null)
抛出新的ArgumentNullException(nameof(rs));
如果(相对长度<2 | |相对长度%2!=0)
抛出新ArgumentException(“无效长度”,nameof(rs));
int halfLen=相对长度/2;
byte[]half1=新字节[halfLen];
数组.Copy(rs,0,half1,0,halfLen);
var r=neworg.BouncyCastle.Math.BigInteger(1,half1);
字节[]半字节2=新字节[半字节];
数组.Copy(rs,halfLen,half2,0,halfLen);
var s=new Org.BouncyCastle.Math.BigInteger(1,2);
var derSequence=new Org.bounchycastle.Asn1.derSequence(
新建Org.BouncyCastle.Asn1.DerInteger(r),
新的Org.BouncyCastle.Asn1.DerInteger(s));
返回derSequence.getDeRecoded();
}

刚刚想到分享对我有效的解决方案。在上述代码片段中,我添加了以下内容:

   using (Mechanism mechanism = new Mechanism(CKM.CKM_ECDSA))
        {
          _session.Login(CKU.CKU_USER, passowrd);
          byte[] signedHash = _session.Sign(mechanism, GetPrivateKeyHandle(), GetMessageDigest(message));
          _session.Logout();
          return ConstructEcdsaSigValue(signedHash);
        }

    private byte[] GetMessageDigest(byte[] message)
    {
       using (Mechanism mechanism = new Mechanism(CKM_SHA256))
       {
         return _session.Digest(mechanism, message);
        }
    }

    public static byte[] ConstructEcdsaSigValue(byte[] rs)
    {
        if (rs == null)
            throw new ArgumentNullException(nameof(rs));

        if (rs.Length < 2 || rs.Length % 2 != 0)
            throw new ArgumentException("Invalid length", nameof(rs));

        int halfLen = rs.Length / 2;

        byte[] half1 = new byte[halfLen];
        Array.Copy(rs, 0, half1, 0, halfLen);
        var r = new Org.BouncyCastle.Math.BigInteger(1, half1);

        byte[] half2 = new byte[halfLen];
        Array.Copy(rs, halfLen, half2, 0, halfLen);
        var s = new Org.BouncyCastle.Math.BigInteger(1, half2);

        var derSequence = new Org.BouncyCastle.Asn1.DerSequence(
            new Org.BouncyCastle.Asn1.DerInteger(r),
            new Org.BouncyCastle.Asn1.DerInteger(s));

        return derSequence.GetDerEncoded();
    }
使用(机制=新机制(CKM.CKM_ECDSA))
{
_登录(CKU.CKU_用户,passowrd);
字节[]signedHash=_session.Sign(机制,GetPrivateKeyHandle(),GetMessageDigest(消息));
_session.Logout();
返回ConstructEcdsaSigValue(signedHash);
}
专用字节[]GetMessageDigest(字节[]消息)
{
使用(机制=新机制(CKM_SHA256))
{
返回会话摘要(机制、消息);
}
}
公共静态字节[]constructedSasigValue(字节[]rs)
{
如果(rs==null)
抛出新的ArgumentNullException(nameof(rs));
如果(相对长度<2 | |相对长度%2!=0)
抛出新ArgumentException(“无效长度”,nameof(rs));
int halfLen=相对长度/2;
byte[]half1=新字节[halfLen];
数组.Copy(rs,0,half1,0,halfLen);
var r=neworg.BouncyCastle.Math.BigInteger(1,half1);
字节[]半字节2=新字节[半字节];
数组.Copy(rs,halfLen,half2,0,halfLen);
var s=new Org.BouncyCastle.Math.BigInteger(1,2);
var derSequence=new Org.bounchycastle.Asn1.derSequence(
新建Org.BouncyCastle.Asn1.DerInteger(r),
新的Org.BouncyCastle.Asn1.DerInteger(s));
返回derSequence.getDeRecoded();
}

我发现您发布的代码中没有明显的问题,因此我猜测您的问题可能是由解决方案中的其他代码(如PDF processin)引起的