- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正尝试在 Web 应用程序中实现数字签名,如 Bruno Lowagie 在白皮书中提供的示例。
4.3.3 使用在客户端创建的签名在服务器上签署文档
预签名——客户端向服务器请求哈希。
后签名——客户端将签名的字节发送到服务器。
在此示例中一切正常,但是当我们在签名后尝试打开 pdf 时它在签名验证期间出现错误错误。验证时遇到错误:内部加密库错误。错误代码:0x2726
这是我的代码:
客户:
KeyStore eks = loadKeyStoreFromSmartCard("abc@123");
// Check if X.509 certification chain is available
Certificate[] certChain = new X509Certificate[1];
certChain[0] = getcert_eToken(null, eks);
String strCertificate = encodeX509CertChainToBase64(certChain);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(8192);
PrintWriter out = new PrintWriter(byteStream, true);
String postData = "certChain=" + strCertificate;
try {
HttpURLConnection connection = null;
URL dataURL = null;
dataURL = new URL("http://localhost:8085/Digital-Server/PreSignservlet");
connection = (HttpURLConnection) dataURL.openConnection();
connection.setRequestProperty("User-Agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000)");
connection.setFollowRedirects(true);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setAllowUserInteraction(false);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Language", "en-US");
connection.setRequestProperty("Cookie", cookie);
connection.connect();
out.print(postData);
out.flush();
out.close();
byteStream.writeTo(connection.getOutputStream());
InputStream in = connection.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read;
byte[] data = new byte[256];
while ((read = in.read(data)) != -1) {
baos.write(data, 0, read);
}
byte[] hash = baos.toByteArray();
PrivateKey privateKey = getprivate_eToken(null, eks);
// we sign the bytes received from the server
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey);
sig.update(hash);
data = sig.sign();
// --------------------------------------------
connection.disconnect();
in.close();
//Calling Post Sign Servelet
dataURL = new URL("http://localhost:8085/Digital-Server/PostSignservlet");
connection = (HttpURLConnection) dataURL.openConnection();
connection.setRequestProperty("User-Agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000)");
connection.setFollowRedirects(true);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setAllowUserInteraction(false);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Language", "en-US");
connection.setRequestProperty("Cookie", cookie);
connection.connect();
out.flush();
out.close();
byteStream.writeTo(connection.getOutputStream());
byteStream.write(data);
in = connection.getInputStream();
OutputStream outputStream = new FileOutputStream(
"D:\\Digital Signature\\Digital-Server\\WebContent\\WEB-INF\\result\\jaihanuman.pdf");
// int read = 0;
byte[] bytes = new byte[8192];
while ((read = in.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
System.out.println("Done!");
预签名 servlet:
Certificate[] chain = decodeX509CertChainToBase64(cert);
// we create a reader and a stamper
ServletContext context = getServletContext();
String fullPath = context.getRealPath("/WEB-INF/result/hello.pdf");
PdfReader reader = new PdfReader(fullPath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
// we create the signature appearance
PdfSignatureAppearance sap = stamper.getSignatureAppearance();
sap.setReason("Test");
sap.setLocation("On a server!");
sap.setVisibleSignature(new Rectangle(72,737,400,780), 1, "sig");
sap.setCertificate(chain[0]);
// we create the signature infrastructure
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE,PdfName.ADBE_PKCS7_DETACHED);
dic.setReason(sap.getReason());
dic.setLocation(sap.getLocation());
dic.setContact(sap.getContact());
dic.setDate(new PdfDate(sap.getSignDate()));
sap.setCryptoDictionary(dic);
HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
sap.preClose(exc);
ExternalDigest externaldigest =new ExternalDigest() {
public MessageDigest getMessageDigest(String hashAlgorithm)
throws GeneralSecurityException {
return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
}
};
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, externaldigest, false);
InputStream data = sap.getRangeStream();
byte hash[] = DigestAlgorithms.digest(data, externaldigest.getMessageDigest("SHA256"));
Calendar cal = Calendar.getInstance();
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
// We store the objects we'll need for post signing in a session
HttpSession session = req.getSession(true);
session.setAttribute("sgn", sgn);
session.setAttribute("hash", hash);
session.setAttribute("cal", cal);
session.setAttribute("sap", sap);
session.setAttribute("baos", baos);
// we write the hash that needs to be signed to the HttpResponse output
OutputStream os = resp.getOutputStream();
os.write(sh, 0, sh.length);
os.flush();
os.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
System.out.println("end of pre sign servelet---------------");
后签名 servlet:
try
{
// we get the objects we need for postsigning from the session
System.out.println("call post servelet1");
HttpSession session = req.getSession(false);
PdfPKCS7 sgn = (PdfPKCS7)session.getAttribute("sgn");
byte[] hash = (byte[])session.getAttribute("hash");
Calendar cal = (Calendar)session.getAttribute("cal");
PdfSignatureAppearance sap =(PdfSignatureAppearance) session.getAttribute("sap");
ByteArrayOutputStream os =(ByteArrayOutputStream) session.getAttribute("baos");
session.invalidate();
// we read the signed bytes
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = req.getInputStream();
int read;
byte[] data = new byte[256];
while ((read = is.read(data, 0, data.length)) != -1) {
baos.write(data, 0, read);
}
// we complete the PDF signing process
sgn.setExternalDigest(baos.toByteArray(), null, "RSA");
byte[] encodedSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CADES);
byte[] paddedSig = new byte[8192];
System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);
PdfDictionary dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
sap.close(dic2);
// we write the signed document to the HttpResponse output stream
// let's write the file in memory to a file anyway
ServletContext context = getServletContext();
String fullPath = context.getRealPath("/WEB-INF/result/sign.pdf");
byte[] pdf = os.toByteArray();
OutputStream sos = resp.getOutputStream();
sos.write(pdf, 0, pdf.length);
sos.flush();
sos.close();
/*OutputStream sos = new FileOutputStream(fullPath);
os.writeTo(sos);
sos.flush();
sos.close();*/
}
catch(Exception ex)
{
ex.printStackTrace();
}
System.out.println("call post servelet2");
这里我做了一件额外的事情,我在发送之前将证书链编码为 base64预签名servlet。
最佳答案
您的代码有些困惑:
客户端代码在 certChain
中检索仅签署者证书的证书链,将其进行 base64 编码到 strCertificate
中,在其前面加上“certChain=”前缀并将该字符串放入进入 postData
。然后它打开一个到 PreSignservlet
的连接,并使用中介 ByteArrayOutputStream byteStream
以复杂的方式发送数据以发布(你为什么不简单地写 postData. getBytes()
到 connection.getOutputStream()
)。
不幸的是,您既没有关闭输出流也没有添加内容长度 header 。因此,servlet 可能难以识别输入结束。但这似乎不是当前的问题。
现在您按原样(即不解码)获取 servlet 返回的数据并将其提供给签名创建。然后您打开到 PostSignservlet
的连接以将签名字节发送到。
到目前为止它是有道理的。
但是您现在发送的不是签名数据,而是您之前已发送的信息(编码证书)到该 servlet,然后将签名添加到本地 byteStream
!
为什么不直接将data
中的签名写到connection.getOutputStream()
中呢?
最终您检索 servlet 的输出作为结果 PDF。
您将证书而不是实际签名写入 PostSignservlet
将解释为什么结果 PDF 中的 CMS 签名容器 SignerInfo 包含一个“签名”值,看起来像这样“certChain=MIIDKT.. ”,即像您的 base64 编码证书。
关于java - 在客户端/Web 服务器架构中实现数字签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22189077/
谁能解释一下 Server.MapPath(".")、Server.MapPath("~")、Server.MapPath(@"之间的区别\") 和 Server.MapPath("/")? 最佳答案
我不知道,为什么我们要使用 Server.UrlEncode() & Server.UrlDecode()?!在 QueryString 中我们看到 URL 中的任何内容,那么为什么我们要对它们进行编
我已经通过 WHM 在我的一个域上安装了 ssl 证书。网站正在使用 https://xyz.com . 但是它不适用于 https://www.xyz.com .我已经检查了证书,它也适用于 www
我已经使用 WMI 检测操作系统上是否存在防病毒软件,itz 正常工作并通过使用命名空间向我显示防病毒信息,例如 win xp 和 window7 上的名称和实例 ID:\root\SecurityC
我们有 hive 0.10 版本,我们想知道是否应该使用 Hive Server 1 或 Hive Server2。另一个问题是连接到在端口 10000 上运行的 Hive 服务器,使用 3rd 方工
我想在 C++ 中使用 Windows Server API 设置一个 HTTPS 服务器,我使用了示例代码,它在 HTTP 上工作正常,但我就是不能让它在 HTTPS 上工作。 (我不想要客户端 S
我写了一个非常基本的类来发送电子邮件。我用 smtp 服务器对其进行了测试,它工作正常,但是当我尝试使用我公司的交换服务器时,它给出了这个异常: SMTP 服务器需要安全连接或客户端未通过身份验证。服
我的应用程序包含一个“网关”DataSnap REST 服务器,它是所有客户端的第一个访问点。根据客户端在请求中传递的用户名(基本身份验证),请求需要重定向到另一个 DataSnap 服务器。我的问题
我有一个 Tomcat 服务器和一个 Glassfish4 服务器。我的 Servlet 在 Tomcat 服务器上启动得很好,但在 Glassfish4 服务器上给我一个“HTTP Status 4
我在 vmware 上创建了一个 ubuntu 服务器。我用它作为文件服务器。如果我通过托管虚拟机的计算机进行连接,则可以访问它。我无法从同一网络上的其他计算机执行此操作。提前致谢! 最佳答案 首先确
如何重启 Rails 服务器?我从 开始 rails server -d 所以服务器是分离的 我知道的唯一方法就是去做ps 辅助 | grep rails 并 kill -9关于过程#但是像这样杀死进
我实际上正在尝试找到编写一个简单的 XMPP 服务器的最佳方法,或者找到一个占用空间非常小的服务器。我只关心XMPP的核心功能(状态、消息传递、群组消息传递)。目前还在学习 XMPP 协议(proto
我实际上正在尝试找到编写简单 XMPP 服务器的最佳方法,或者找到一个占用空间非常小的方法。我只关心 XMPP 的核心功能(统计、消息、组消息)。目前也在学习 XMPP 协议(protocol),所以
我们正在尝试从 Java JAX-RS 适配器访问 SOAP 1.1 Web 服务。 我们正在使用从 WSDL 生成的 SOAP 客户端。 但是当解码 SOAP 故障时,我们得到以下异常: ... C
目前,我和许多其他人正在多个平台(Windows、OS X 和可能的 Linux)上使用 Python HTTP 服务器。我们正在使用 Python HTTP 服务器来测试 JavaScript 游戏
我有一个连续运行的服务器程序(C#/.NET 2.0 on Linux with mono),我想从 PHP 脚本连接到它以在网站上显示状态信息。 目的是创建一个(某种)实时浏览器游戏(无 Flash
所以我有一个单页客户端应用程序。 正常流程: 应用程序 -> OAuth2 服务器 -> 应用程序 我们有自己的 OAuth2 服务器,因此人们可以登录应用程序并获取与用户实体关联的 access_t
我们刚刚将测试 Web 服务器从 Server 2008 升级到 Server 2012 R2。我们有一个部署我们网站的批处理脚本。当它将站点推送到服务器时,它现在失败了。奇怪的是,我可以使用相同的发
建议一些加载SpagoBI服务器的方法,我尝试了所有方法来解析spagobi服务器。在 Catalina 中,错误是 - * SEVERE: Unable to process Jar entry [
当我们点击应用程序服务器(apache tomcat)时,它会创建一个线程来处理我们的请求并与 tomcat 连接,建立连接,tomcat 创建另一个线程来处理请求并将其传递给连接,连接线程将其传递给
我是一名优秀的程序员,十分优秀!