我有wcf网络服务,当我的网站提出请求时签署pdf文件。在开发过程中,一切都在本地工作,试图签署少量文档。
一旦我的代码部署到生产环境,它工作正常几个小时但突然我开始收到错误n 48后跟n 224.
消息:错误n。 48 资料来源:NCryptoki 堆栈跟踪:在Cryptware.NCryptoki.Session.Sign(字节[]数据) 在iTextSharp.text.pdf.security.MakeSignature.SignDetached(PdfSignatureAppearance sap,IExternalSignature externalSignature,ICollection
1 chain, ICollection
1 crlList,IOcspClient ocspClient,ITSAClient tsaClient,Int32 estimatedSize,CryptoStandard sigtype)消息:错误n。 224 资料来源:NCryptoki 堆栈跟踪:在Cryptware.NCryptoki.Session.Sign(字节[]数据) 在iTextSharp.text.pdf.security.MakeSignature.SignDetached(PdfSignatureAppearance sap,IExternalSignature externalSignature,ICollection
1 chain, ICollection
1 crlList,IOcspClient ocspClient,ITSAClient tsaClient,Int32 estimatedSize,CryptoStandard sigtype)
我努力了解可能发生的事情以及如何在本地复制此问题,以便我可以尝试修复它。我认为这可能是加载问题,但根据日志服务器只签署了每分钟4-5个请求。
以下是我的签名代码的摘要。
1)WCF SOAP Action
public void TestSignPDF()
{
string fileName = Guid.NewGuid().ToString();
String src = @"C:\tmp\singlepage.pdf";
String DEST = string.Format(@"C:\tmp\{0}.pdf", fileName);
MemoryStream ms = new MemoryStream();
FileStream file = new FileStream(src, FileMode.Open, FileAccess.Read);
byte[] bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
ms.Write(bytes, 0, (int)file.Length);
file.Close();
ms.Seek(0, SeekOrigin.Begin);
HSMSignDocument x = new HSMSignDocument();
Stream result = x.SignDocument(ms, "334", fileName);
if (result != null)
{
FileStream file2 = new FileStream(DEST, FileMode.Create, System.IO.FileAccess.Write);
byte[] bytes2 = new byte[result.Length];
result.Read(bytes2, 0, (int)result.Length);
file2.Write(bytes2, 0, bytes2.Length);
file2.Close();
result.Close();
}
ms.Close();
}
2。)HSMSignDocument类(静态)
public class HSMSignDocument : IDisposable
{
private static Cryptoki cryptoki = null;
private static Session session = null;
private static NLogger LOGGER = new NLogger();
private static readonly string HSMPartitionPwd = ConfigurationManager.AppSettings["HSMPartitionPassword"];
private string TIME_STAMPING_SERVER_URL = "xx";
private string TIME_STAMPING_SERVER_ACCOUNT = "xx";
private string TIME_STAMPING_SERVER_PASSWORD = "xx";
static HSMSignDocument()
{
Cryptoki.Licensee = "xxx";
Cryptoki.ProductKey = "xxx";
if (cryptoki == null)
{
cryptoki = new Cryptoki();
cryptoki.Attach(@"C:\Program Files\SafeNet\LunaClient\cryptoki.dll");
cryptoki.Initialize();
}
if (session == null)
{
// Reads the set of slots containing a token
SlotList slots = cryptoki.Slots;
if (slots.Count == 0)
{
LOGGER.Error("slots.Count == 0, no slots available");
return;
}
// Gets the first slot available
Slot slot = slots[0];
if (!slot.IsTokenPresent)
{
LOGGER.Error("!slot.IsTokenPresent, no tokens present");
return;;
}
// Gets the first token available
Token token = slot.Token;
// Opens a read/write serial session
session = token.OpenSession(Session.CKF_SERIAL_SESSION | Session.CKF_RW_SESSION, null, null);
int nRes = session.Login(Session.CKU_USER, HSMPartitionPwd);
if (nRes != 0)
{
LOGGER.Error("Could not login to Session");
}
}
}
private IList<Org.BouncyCastle.X509.X509Certificate> GetKeyChain()
{
//Private key pointers have been installed in
X509Store x509Store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
x509Store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificates = x509Store.Certificates;
IList<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>();
X509Certificate2 pk = null;
string HSMCertSerialNumber = ConfigurationManager.AppSettings["HSMCertificateSerialNumber"];
if (certificates.Count > 0)
{
foreach (X509Certificate2 mCert in x509Store.Certificates)
{
//GETS THE KEY WE ARE LOOKING - Private key for HSM
if (String.Compare(mCert.SerialNumber, HSMCertSerialNumber, true) == 0)
{
pk = mCert;
break;
}
}
X509Chain x509chain = new X509Chain();
x509chain.Build(pk);
foreach (X509ChainElement x509ChainElement in x509chain.ChainElements)
{
// Build up root chain
chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
}
}
x509Store.Close();
return chain;
}
public bool ApplySignatureDetails(Session session, String alias, Stream inputFile, string tempWorkingFile)
{
IList<Org.BouncyCastle.X509.X509Certificate> chain = GetKeyChain();
// creates a TSA client(Time Stampingserver)
ITSAClient timeStampingClient = new TSAClientBouncyCastle(TIME_STAMPING_SERVER_URL, TIME_STAMPING_SERVER_ACCOUNT, TIME_STAMPING_SERVER_PASSWORD);
IOcspClient ocspClient = new OcspClientBouncyCastle(); // Online Certificate Status Protocol - adobe requirement
List<ICrlClient> crlList = new List<ICrlClient>(); //revocation list - adobe requirement
crlList.Add(new CrlClientOnline(chain));
return PKCS11Signer.Sign(inputFile, String.Format(tempWorkingFile, alias), chain, session, alias, DigestAlgorithms.SHA256, CryptoStandard.CMS, "Doc Signed", "My Company", crlList, ocspClient, timeStampingClient, 0);
}
void IDisposable.Dispose()
{
if (session != null)
{
session.Logout();
session.Close();
session = null;
}
if (cryptoki != null)
{
cryptoki.Finalize(IntPtr.Zero);
cryptoki = null;
}
}
}
3。)PKCS11Signer Class
class PKCS11Signer
{
private static NLogger LOGGER = new NLogger();
private static Semaphore Bouncer { get; set; }
public static bool Sign(Stream inputFile, String dest, ICollection<Org.BouncyCastle.X509.X509Certificate> chain, Session session, String alias,
String digestAlgorithm, CryptoStandard subfilter, String reason, String location,
ICollection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize)
{
// Creating the reader and the stamper
PdfReader reader = null;
PdfStamper stamper = null;
FileStream outputStream = null;
try
{
if (Bouncer == null)
{
Bouncer = new Semaphore(1, 1);
}
Bouncer.WaitOne();
LOGGER.Info("Start Actual Signing");
reader = new PdfReader(inputFile);
outputStream = new FileStream(dest, FileMode.Create, FileAccess.Write);
stamper = PdfStamper.CreateSignature(reader, outputStream, '\0');
LOGGER.Info("PDFStamper Created");
// Creating the appearance
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
LOGGER.Info("PdfSignatureAppearance Created");
appearance.Reason = reason;
appearance.Location = location;
//Uncomment to show signiture text
//appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(56, 128, 164, 160), 1, "signature");
appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;
LOGGER.Info("PdfSignatureAppearance Created");
// Creating the signature
IExternalSignature pks = new PrivateKeySignature(session, alias);
LOGGER.Info("Encryption algorithm " + pks.GetEncryptionAlgorithm());
LOGGER.Info("Hash algorithm " + pks.GetHashAlgorithm());
LOGGER.Info("Hash code " + pks.GetHashCode());
LOGGER.Info("pks : " + pks.ToString());
LOGGER.Info("IExternalSignature Created perform sign");
MakeSignature.SignDetached(appearance, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
//System.Threading.Thread.Sleep(1000); //Globalsign requirement
LOGGER.Info("MakeSignature.SignDetached Completed");
}
catch (Exception ex)
{
LOGGER.Error(ex);
throw ex;
}
finally
{
Bouncer.Release();
if (stamper != null)
stamper.Close();
if (reader != null)
reader.Close();
if (outputStream != null)
outputStream.Close();
if (inputFile != null)
inputFile.Close();
}
return true;
}
}
}
4.)PrivateKeySignature Class
class PrivateKeySignature : IExternalSignature
{
private static NLogger LOGGER = new NLogger();
private static ObjectCache cache = MemoryCache.Default;
private readonly Session session;
RSAPrivateKey privateKey;
public PrivateKeySignature(Session session, String alias)
{
string HSMPrivateKeyCertReq = ConfigurationManager.AppSettings["HSMPrivateKeyCertReq"];
this.session = session;
LOGGER.Info("Starting to get PrivateKeySignature");
CryptokiCollection pkobjects = findTarget(session, HSMPrivateKeyCertReq);
LOGGER.Info("Search session for private key using template");
foreach(var keyObject in pkobjects)
{
LOGGER.Info("RSA/CertReq:" + HSMPrivateKeyCertReq);
privateKey = (RSAPrivateKey)keyObject;
}
if (privateKey == null)
{
throw new Exception("privateKey not found");
}
LOGGER.Info("Private Key Found");
}
public String GetHashAlgorithm()
{
return "SHA1";
}
public String GetEncryptionAlgorithm()
{
return "RSA";
}
public byte[] Sign(byte[] message)
{
LOGGER.Info("Start apply Private Key");
session.SignInit(Mechanism.SHA1_RSA_PKCS, privateKey);
LOGGER.Info("End apply Private Key");
return session.Sign(message);
}
public CryptokiCollection findTarget(Session session, string label)
{
if (cache.Contains(label))
{
return (CryptokiCollection)cache.Get(label);
}
else
{
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, label));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_KEY_TYPE, Key.CKK_RSA));
var pk = session.Objects.Find(template, 1);
// Store data in the cache
CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
cacheItemPolicy.SlidingExpiration = TimeSpan.FromHours(4);
cache.Add(label, pk, cacheItemPolicy);
return pk;
}
}
}
}
答案 0 :(得分:1)
NCryptoki返回底层PKCS#11模块的错误。
此处提供了PKCS#11错误列表:
http://wiki.ncryptoki.com/How-NCryptoki-manages-PKCS-11-errors.ashx
在你的情况下48(0x30)表示: CKR_DEVICE_ERROR
而224(0xE0)表示: CKR_TOKEN_NOT_PRESENT
似乎您的生产HSM存在配置问题