2017-05-16 3 views
2

J'essaie de signer des documents PDF en utilisant Pkcs11Interop bibliothèque .net. Je dois utiliser algorithme de chiffrement ECDSA avec algorithme de hachage SHA256. Et j'utilise SoftHSM 2.2.0 pour stocker des clés privées.Signature PDF à partir de Pkcs11Interop pour CKM_ECDSA_SHA256 en utilisant SoftHSM 2.2.0 (ECDSA avec SHA256) C# .net

J'ai trouvé un ENUM CKM, CKM_ECDSA_SHA256, qui je passe tout en créant un objet de mécanisme de classe pour appeler la méthode Signe session.

Je reçois la réponse de la méthode "Signdata", cependant, à l'ouverture des fichiers Pdf générés après la signature, je donne une erreur "Signature invalide". Voici l'extrait de code pour l'appel de méthode Signdata. Je ne reçois aucune erreur ou exception dans le code, cependant, le pdf comme je l'ai mentionné montre la signature invalide.

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]; 
} 
  • S'il vous plaît me dire si SoftHSM 2.2.0 prend en charge ECDSA_P256 avec SHA256 ou non ??
  • Sinon, alors est-il possible d'activer le support?
  • S'il ne prend en charge, s'il vous plaît aidez-moi comment résoudre ce problème?
  • On dirait qu'il veut que je passe ECDSA_Param, Quelqu'un at-il extrait de code pour faire passer la structure ECDSA_Param
+0

Je ne vois aucun problème évident dans le code que vous avez posté donc je suppose que votre problème peut être causé par un autre code dans votre solution telle que le traitement PDF , Bâtiment de structure de CMS etc. – jariq

Répondre

0

Je pense que vous avez besoin de construire ECDSA-Sig-Value et le remplir avec les données de votre variable signedHash.

PKCS#11 v2.20 chapitre 12.3.1:

Aux fins de ces mécanismes, une signature ECDSA est une chaîne octet de même longueur qui est au plus deux fois octets nLen, où nLen est la longueur octets de l'ordre des points de base n. La signature octets correspond à la concaténation des valeurs ECDSA r et s, toutes deux représentées par une chaîne d'octets de longueur égale au plus nLen avec l'octet le plus significatif en premier. Si r et s ont une longueur différente d'octet , la plus courte des deux doit être complétée avec les 0 premiers octets de sorte que les deux aient la même longueur d'octet. Librement parlé, le premier la moitié de la signature est r et la seconde moitié est s. Pour les signatures créées par un jeton, la signature résultante est toujours de longueur 2nLen. Pour les signatures passées à un jeton à des fins de vérification, la signature peut avoir une longueur plus courte mais doit être composée comme indiqué ci-dessus.

RFC5753 chapitre 7.2:

Lorsque vous utilisez ECDSA avec Signées, les signatures ECDSA sont codées à l'aide du type:

ECDSA-Sig-Value ::= SEQUENCE { 
    r INTEGER, 
    s INTEGER } 

ECDSA-Sig-Value est spécifié dans [PKI-ALG ]Dans CMS, ECDSA-Sig-Value est codé en DER et placé dans un champ de signature de SignedData.

suivant la méthode utilise la bibliothèque BouncyCastle à la structure des constructions ECDSA-Sig-Value DER codé:

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(); 
} 
+0

Merci beaucoup @jariq pour votre réponse. Cependant, je ne suis pas sûr de savoir comment utiliser ECDSA-Sig-value. Si vous avez un extrait de code à ce sujet, si ce sera vraiment utile pour moi. Je suis vraiment bloqué à ce stade, j'apprécie vraiment toute aide. Merci d'avance. – Kumar

+0

@Kumar Malheureusement, je ne dispose pas actuellement d'un échantillon de code prêt à l'emploi, mais je vais essayer d'en créer un d'ici la fin de la semaine. – jariq

+0

Merci beaucoup @Jariq pour cela. C'est vraiment très utile. Je ai juste besoin de savoir est la variable signedHash de mon entrée serait l'entrée pour cette méthode et son serait considéré comme la valeur finale et correcte de la variable signedHash? Ai-je besoin d'écrire quelque chose comme ci-dessous ........................................ ....................... return (ConstructEcdsaSigValue (signedHash)); – Kumar

0

Je pensais juste que de partager la solution qui a fonctionné pour moi. Dans l'extrait de code ci-dessus mentionné, j'ai ajouté les choses ci-dessous:

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(); 
    }