您当前的位置:   首页 > 新闻中心
使用Luna HSM对PDF文档进行数字签名或认证
发布时间:2020-01-12 20:28:52   阅读次数:

使用Luna HSM对PDF文档进行数字签名或认证(图1)

揽阁备注:此文档是以SafeNet Luna SA为参考编写,最新版本为SafeNet Luna Network HSM或SafeNet Luna PCIe HSM


硬件安全模块(HSM)和eTokens是专用,经过强化和防篡改的计算设备,旨在安全地管理,处理和存储数字密钥。这些设备直接连接到计算机或网络服务器。


Adobe Experience Manager Forms可以使用存储在HSM或etoken上的凭据来进行eSign签名或将服务器端数字签名应用于文档。要将HSM或etoken设备与AEM表单一起使用:

  1. 启用DocAssurance服务。

  2. 为阅读器扩展设置证书。

  3. 在AEM Web控制台中为HSM或etoken设备创建别名。

  4. 使用DocAssurance服务API通过存储在设备上的数字密钥对文档进行签名或认证。


在使用AEM表单配置HSM或etoken设备之前

  • 安装AEM 6.2和安装AEM 6.2窗体附加组件包。

  • 在与AEM 6.2服务器相同的计算机上安装和配置HSM或etoken客户端软件。需要客户端软件才能与HSM和etoken设备进行通信。

  • (仅限Microsoft Windows)将JAVA_HOME_32环境变量设置为指向安装32位版本的Java 8 Development Kit(JDK 8)的目录。该目录的默认路径是C:\ Program Files(x86)\ Java \ jdk <version>

  • (仅OSGi上的AEM表单)将根证书安装在信任库中。需要验证签名的PDF

注意:

在Microsoft Windows上,仅支持32位LunaSA或EToken客户端。


启用DocAssurance服务

默认情况下,不启用DocAssurance服务。执行以下步骤以启用服务:

  1. 停止AEM Forms环境的Author实例。

  2. 打开[AEM_root] \ crx-quickstart \ conf \ sling.properties文件进行编辑。

    注意:

    如果使用[AEM_root] \ crx-quickstart \ bin \ start.bat文件启动AEM实例,则打开[AEM_root] \ crx-quickstart \ sling.properties文件进行编辑。  


  3. 在sling.properties文件中添加或替换以下属性:

  4. sling.bootdelegation.sun=sun.*,com.sun.*,sun.misc.*
    sling.bootdelegation.ibm=com.ibm.xml.*,com.ibm.*
    sling.bootdelegation.class.com.rsa.jsafe.provider.JsafeJCE=com.rsa.*
    sling.bootdelegation.class.org.bouncycastle.jce.provider.BouncyCastleProvider=org.bouncycastle.*
  5. 保存并关闭sling.properties文件。

  6. 重新启动AEM实例。


设置阅读器扩展的证书

执行以下步骤来设置证书:

  1. 以管理员身份登录到AEM作者实例。

  2. 单击全局导航栏上的Adobe Experience Manager。转到工具 >  安全性 > 用户。  

  3. 单击用户帐户的名称字段。将打开“ 编辑用户设置”页面。  

  4. 在AEM作者实例上,证书位于密钥库中。如果您之前尚未创建密钥库,请单击创建密钥库,然后为密钥库设置新密码。如果服务器已经包含密钥库,请跳过此步骤。

  5. 在“ 编辑用户设置”页面上,单击管理密钥库。

  6. 在“密钥库管理”对话框中,展开“ 从密钥库文件添加私钥”选项并提供别名。别名用于执行Reader Extensions操作。

  7. 要上载证书文件,请单击“ 选择密钥存储文件”,然后上载<filename> .pfx文件。 

  8. 将与证书关联的密钥存储密码,私钥密码和私钥别名添加到各个字段。点击提交。

注意:

要确定证书的私有密钥别名,可以使用Java keytool命令:keytool -list -v -keystore [keystore-file] -storetype pkcs12


注意:

在“ 密钥存储密码”和“ 私钥密码”字段中,指定证书文件随附的密码。  


注意:

对于OSGi上的AEM表单,要验证签名的PDF,即安装在信任存储中的根证书。


注意:

在转到生产环境时,请用生产凭据替换评估凭据。在更新过期或评估凭证之前,请确保删除旧的Reader Extensions凭证。


为设备创建别名

别名包含HSM或etoken所需的所有参数。执行以下说明,为eSign或Digital Signatures使用的每个HSM或etoken凭证创建别名:

  1. 打开AEM控制台。AEM控制台的默认URL为http:// <主机>:<端口> / system / console / configMgr

  2. 打开“ HSM凭据配置服务”,并为以下字段指定值:

    • 凭据别名:指定用于标识别名的字符串。此值用作某些数字签名操作(例如“签名签名字段”操作)的属性。 

    • DLL路径:指定服务器上HSM或etoken客户端库的标准路径。例如,C:\ Program Files \ LunaSA \ cryptoki.dll。在群集环境中,该路径对于群集中的所有服务器必须相同。

    • HSM密码:指定访问设备密钥所需的密码。 

    • HSM Slot ID:指定整数类型的插槽标识符。Slot ID是逐个客户端设置的。如果将第二台计算机注册到其他分区(例如,同一HSM设备上的HSMPART2),则Slot 1与客户端的HSMPART2分区关联。

    • 注意: 在配置Etoken时,请为HSM插槽ID字段指定一个数值。要使签名操作正常运行,需要一个数字值。

    • 证书SHA1:为所使用的证书指定公共密钥(.cer)文件的SHA1值(缩略图)。确保SHA1值中没有使用空格。如果使用的是物理证书,则不需要。

    • HSM设备类型:选择HSM(Luna或其他)或eToken设备的制造商。  

点击保存。硬件安全模块已配置用于AEM表单。现在,您可以将硬件安全模块与AEM表单一起使用,以对文档进行签名或认证。


使用DocAssurance服务API通过存储在设备上的数字密钥对文档进行签名或认证 

以下示例代码使用HSM或令牌进行签名或认证。


/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * ___________________
 *
 *  Copyright 2014 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are proteCTEd by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package com.adobe.docassurance.samples;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.resource.JcrResourceResolverFactory;

import com.adobe.aemfd.docmanager.Document;
import com.adobe.fd.docassurance.client.api.DocAssuranceException;
import com.adobe.fd.docassurance.client.api.DocAssuranceService;
import com.adobe.fd.docassurance.client.api.DocAssuranceServiceOperationTypes;
import com.adobe.fd.docassurance.client.api.SignatureOptions;
import com.adobe.fd.signatures.client.types.exceptions.InvalidArgumentException;
import com.adobe.fd.signatures.pdf.inputs.CredentialContext;
import com.adobe.fd.signatures.pdf.inputs.DSSPreferences;
import com.adobe.fd.signatures.pdf.inputs.DSSPreferencesImpl;
import com.adobe.fd.signatures.pdf.inputs.PDFSignatureAppearenceOptions;
import com.adobe.fd.signatures.pdf.inputs.UnlockOptions;
import com.adobe.fd.signatures.pdf.inputs.PDFSignatureAppearenceOptions.PDFSignatureAppearanceType;
import com.adobe.fd.signatures.pdf.inputs.PDFSignatureAppearenceOptions.TextDirection;
import com.adobe.fd.signatures.pki.client.types.common.HashAlgorithm;
import com.adobe.fd.signatures.pki.client.types.common.RevocationCheckStyle;
import com.adobe.fd.signatures.pki.client.types.prefs.CRLPreferences;
import com.adobe.fd.signatures.pki.client.types.prefs.CRLPreferencesImpl;
import com.adobe.fd.signatures.pki.client.types.prefs.GeneralPreferencesImpl;
import com.adobe.fd.signatures.pki.client.types.prefs.PKIPreferences;
import com.adobe.fd.signatures.pki.client.types.prefs.PKIPreferencesImpl;
import com.adobe.fd.signatures.pki.client.types.prefs.PathValidationPreferences;
import com.adobe.fd.signatures.pki.client.types.prefs.PathValidationPreferencesImpl;

/**
 * Digital signatures can be applied to PDF documents to provide a level of security. Digital signatures, like handwritten signatures, provide a means by which signers 
 * identify themselves and make statements about a document. The technology used to digitally sign documents helps to ensure that both the signer and recipients are clear 
 * about what was signed and confident that the document was not altered since it was signed.
 * 
 * PDF documents are signed by means of public-key technology. A signer has two keys: a public key and a private key. The private key is stored in a user's credential that 
 * must be available at the time of signing. The public key is stored in the user's certificate that must be available to recipients to validate the signature. Information
 * about revoked certificates is found in certificate revocation lists (CRLs) and Online Certificate Status Protocol (OCSP) responses distributed by Certificate Authorities (CAs). 
 * The time of signing can be obtained from a trusted source known as a Timestamping Authority.
 * 
 * The following Java code example digitally signs a PDF document that is based on a PDF file. 
 * The alias that is specified for the security credential is secure, and revocation checking is performed. 
 * Because no CRL or OCSP server information is specified, the server information is obtained from the certificate used to 
 * digitally sign the PDF document
 * 
 * PreRequisites - Digital certificate for signing the document has to be uploaded on Granite Key Store
 */

@Component
@Service(value=Sign.class)
public class Sign{
	@Reference
	private DocAssuranceService docAssuranceService;
	
	@Reference
    private SlingRepository slingRepository;
	
	@Reference
    private JcrResourceResolverFactory jcrResourceResolverFactory ;
	
	
	/**
	 * 
	 * @param inputFile - path to the pdf document stored at JCR node 
	 * @param outputFile - path to the pdf document where the output needs to be stored
	 * @throws IOException
	 * @throws RepositoryException
	 * @throws InvalidArgumentException
	 * @throws DocAssuranceException
	 */
	public void signExtend(String inputFile, String outputFile, String alias) throws IOException, RepositoryException, InvalidArgumentException, DocAssuranceException{
		
		Document inDoc = new Document(inputFile);
		Document outDoc = null;
		
		Session adminSession = null;
        ResourceResolver resourceResolver = null;
        try {
        	 
        	 /** resourceResolver with admin privileges to be passed to SignatureServiceAPI and Reader Extensions
        	 the resource resolver for signature options has to be corresponding to the user who has the signing certificate in his granite key store
        	 the resource resolver for signature options has to be corresponding to the user who has the credential for reader extension in his granite key store
        	 here we are using the same resource resolver
        	 */
        	 adminSession = slingRepository.loginAdministrative(null);
             resourceResolver = jcrResourceResolverFactory.getResourceResolver(adminSession);
             
             //retrieve specifications for each of the services, you may pass null if you don't want to use that service
             //as we don't want encryption in this case, passing null for Encryption Options
             //for encrypted document pass Unlock Options - see the method getUnlockOptions() below
			 outDoc = docAssuranceService.secureDocument(inDoc, null, getSignatureOptions(alias,resourceResolver),null,null);
        }
		catch(Exception e){
			e.printStackTrace();
		}
        finally{
            /**
             * always close the PDFDocument object after your processing is done.
             */
            if(inDoc != null){
                inDoc.close();
            }
            if(adminSession != null && adminSession.isLive()){
                if(resourceResolver != null){
                    resourceResolver.close();
                }
                adminSession.logout();
            }
        }
        
        //flush the output document contents to JCR Node
		flush(outDoc, outputFile);
		
		
	}
	
	/**
	 * 
	 * @param rr resource resolver corresponding to the user with the access to signing credential for the 
	 * given alias "allcertificatesanypolicytest11ee_new" in this case
	 * @return SignatureOptions
	 */
	private SignatureOptions getSignatureOptions(String alias, ResourceResolver rr){
		
		//create an instance of SignatureOptions
		SignatureOptions signatureOptions = SignatureOptions.getInstance();
		
		//set the operation you want to perform - SIGN/CERTIFY
		signatureOptions.setOperationType(DocAssuranceServiceOperationTypes.SIGN);
		
		//field to sign
		String fieldName = "Signature1" ;
		
		
        
        //Hash Algo to be used to compute digest the PDF document
        HashAlgorithm algo = HashAlgorithm.SHA384;
        
        //Reason for signing/certifying
        String reason = "Test Reason";
        
        //location of the signer
        String location = "Test Location";
        
        //contact info of the signer
        String contactInfo = "Test Contact";
        
        //Create a PDFSignatureAppearanceOptions object 
        //and show date information
        PDFSignatureAppearenceOptions appOptions = new PDFSignatureAppearenceOptions(
                PDFSignatureAppearanceType.NAME, null, 1.0d, null, true, true,
                true, true, true, true, true, TextDirection.AUTO);
        
        signatureOptions.setSignatureFieldName(fieldName);
        signatureOptions.setAlgo(algo);
        signatureOptions.setContactInfo(contactInfo);
        signatureOptions.setLocation(location);
        signatureOptions.setSigAppearence(appOptions);
        signatureOptions.setReason(reason);
        signatureOptions.setDssPref(getDSSPreferences(rr));
        signatureOptions.setCredential(new CredentialContext(alias, rr, true));
		return signatureOptions;
	}
	
	private DSSPreferences getDSSPreferences(ResourceResolver rr){
		//sets the DSS Preferences
        DSSPreferencesImpl prefs = DSSPreferencesImpl.getInstance();
        prefs.setPKIPreferences(getPKIPreferences());
        GeneralPreferencesImpl gp = (GeneralPreferencesImpl) prefs.getPKIPreferences().getGeneralPreferences();
        gp.setDisableCache(true);
        return prefs;
    }
    
    private PKIPreferences getPKIPreferences(){
    	//sets the PKI Preferences
        PKIPreferences pkiPref = new PKIPreferencesImpl();
        pkiPref.setCRLPreferences(getCRLPreferences());
        pkiPref.setPathPreferences(getPathValidationPreferences());
        return pkiPref;
    }
    
    private CRLPreferences getCRLPreferences(){
        //specifies the CRL Preferences
        CRLPreferencesImpl crlPrefs = new CRLPreferencesImpl();
        crlPrefs.setRevocationCheck(RevocationCheckStyle.CheckIfAvailable);
        crlPrefs.setGoOnline(true);
        return crlPrefs;
    }
    
    private PathValidationPreferences getPathValidationPreferences(){
    	//sets the path validation preferences
        PathValidationPreferencesImpl pathPref = new PathValidationPreferencesImpl();
        pathPref.setDoValidation(false);
        return pathPref;
        
    }
    
    /**
     * sets Unlock Options for encrypted PDF
     */
    private UnlockOptions getUnlockOptions(){
        UnlockOptions unlockOptions = new UnlockOptions();
        //sets the Open Password for password encrypted PDF
        unlockOptions.setPassword("OpenPassword");
        
        //for Certificate Encrypted Document, set the alias of the credential uploaded in the user's key store
        //and corresponding resource resolver
        
        return unlockOptions;
        
    }
    /**
     * This method copies the data from {@code Document}, to the specified file at the given resourcePath.
     * @param doc
     * @param resourcePath
     * @throws IOException
     */
    private void flush(Document doc, String resourcePath) throws IOException {
 		//extracts the byte data from Document
 		byte[] output = doc.getInlineData();
 		Binary opBin;
 		Session adminSession = null;
 	    try {
 	     	 adminSession = slingRepository.loginAdministrative(null);
 	     	 
 	     	 //get access to the specific node
 	     	 //here we are assuming that node exists
 	         Node node = adminSession.getNode(resourcePath); 
 	        
 	         //convert byte[] to Binary
 	         opBin = adminSession.getValueFactory().createBinary((InputStream)new ByteArrayInputStream(output));
 			 
 	         //set the Binary data value to node's jcr:data
 	         node.getNode("jcr:content").getProperty("jcr:data").setValue(opBin);
 	    } catch (RepositoryException e) {

 	    }
 	    finally{
 	    	
     		if(adminSession != null && adminSession.isLive()){
     			try {
 					adminSession.save();
 					adminSession.logout();
 				} catch (RepositoryException e) {
 					
 				}
             	
             }
 	    }
 		
 	}
}



如果您是从AEM 6.0表单或AEM 6.1表单升级的,并且您使用的是先前版本的DocAssurance服务,则:

  • 要在没有HSM或etoken设备的情况下使用DocAssurance服务,请继续使用现有代码。

  • 要将DocAssurance服务与HSM或etoken设备一起使用,请使用下面列出的API替换现有的CredentialContext对象代码。


/**
	 * 
	 * @param credentialAlias alias of the PKI Credential stored in CQ Key Store or 
	 * 		  the alias of the HSM Credential configured using HSM Credentials Configuration Service.			  	
	 * @param resourceResolver corresponding to the user with the access to the key store and trust store.
	 * @param isHSMCredential if the alias is corresponding to HSM Credential. 
	 */
	public CredentialContext(String credentialAlias, ResourceResolver resourceResolver, boolean isHSMCredential);



揽阁信息可提供的部分安全产品和解决方案信息

联系揽阁信息,您可以获取到更多满足全球合规性要求的信息安全产品资料,以及相关的整体解决方案的相关资料。如:


您还可以得到揽阁信息所提供的优质服务。

揽阁信息 · 值得您信赖的信息安全顾问!


相关阅读

购买咨询电话
021-54410609