如何实现一个电子签章的系统呢 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
matenshi
V2EX    Java

如何实现一个电子签章的系统呢

  •  1
     
  •   matenshi 2021-02-24 16:15:03 +08:00 4547 次点击
    这是一个创建于 1691 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前提是公司要弄一个电子签章的系统,目的是对 pdf 文档签名,然后验签。用户用阅读器查看 pdf 时,也要显示证书的有效性,验证时从场景来看,也不能简单把每个人的证书都加到信任列表中,希望能有个根证书一样的东西来验证。

    我以前对证书加解密这块不是很懂,https 也是用的 Let's Encrypt 。后面补了相关知识,大致上是 CA 机构用自己的私钥加密我的公钥得到证书,然后客户信任并拥有这个 CA 的公钥,这样客户使用公钥解密加密后的证书,并从证书中得到我的公钥。不知道我理解的对不对?

    然后回到 pdf,我想就是私钥签名,公钥验签。

    然后查询了相关资料后,我使用 keytool 来生成证书,用 itext7 来对 pdf 文档签名,以下是步骤:

    1. 创建一个自签名的证书作为根证书(类似 CA?);
    2. 生成一个人员的证书;
    3. 生成该人员证书对应的证书请求文件;
    4. 然后通过步骤 1 生成的根证书并对其签名,得到一个证书文件(发布者就变了);
    5. 通过 itext 来对 pdf 文件进行签名。
    6. 导出第一步的证书(根证书),添加到 pdf 阅读器受信任的证书列表中(也安装在了本地),然后查看 pdf 。

    下面是签名的方法,修改的 itext7 的 demo:

    public class C4_07_ClientServerSigning { public static final String DEST = "/Users/xxx/Downloads/"; public static final String SRC = "/Users/xxx/Downloads/ApplicationForm.pdf"; public static final String CERT = "/Users/xxx/Documents/csr/pdf/aaa.cer"; public static final String KEYSTORE = "/Users/xxx/Documents/csr/pdf/aaa.keystore"; public static final char[] PASSWORD = "123456".toCharArray(); public static final String[] RESULT_FILES = new String[] { "hello_server.pdf" }; public static void main(String[] args) throws GeneralSecurityException, IOException { File file = new File(DEST); file.mkdirs(); CertificateFactory factory = CertificateFactory.getInstance("X.509"); Certificate[] chain = new Certificate[1]; chain[0] = factory.generateCertificate(new FileInputStream(CERT)); new C4_07_ClientServerSigning2().sign(SRC, DEST + RESULT_FILES[0],chain,PdfSigner.CryptoStandard.CMS, "Test", "Ghent"); } public void sign(String src, String dest, Certificate[] chain, PdfSigner.CryptoStandard subfilter, String reason, String location) throws GeneralSecurityException, IOException { PdfReader reader = new PdfReader(src); PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties()); // Create the signature appearance Rectangle rect = new Rectangle(36, 648, 200, 100); PdfSignatureAppearance appearance = signer.getSignatureAppearance(); appearance .setReason(reason) .setLocation(location) .setPageRect(rect) .setPageNumber(1); signer.setFieldName("sig"); IExternalDigest digest = new BouncyCastleDigest(); BouncyCastleProvider provider = new BouncyCastleProvider(); Security.addProvider(provider); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(new FileInputStream(KEYSTORE), PASSWORD); String alias = ks.aliases().nextElement(); PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD); IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider.getName()); // Sign the document using the detached mode, CMS or CAdES equivalent. signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter); } } 

    现在的问题是,查看 pdf 时,阅读器(测试时用的福昕阅读器),还是显示的 “签名有效性未知,签名者身份未知,因为它和父证书都不包含在信任列表中”。

    现在就没有头绪了,我觉得是我想错了,请各位有空帮忙看看,谢谢

    18 条回复    2021-02-25 16:30:35 +08:00
    chixinzei
        1
    chixinzei  
       2021-02-24 17:25:49 +08:00   3
    https 原理再看一遍,CA 证书(含公钥)是直接被各大主流浏览器所信任的,所以客户不需要再次信任,你找 CA 买的证书会通过浏览器自行与 CA 交互认证成功。 你自己签的证书(公钥)客户端并没有对应的 CA 可以验证,所以除非客户手动信任该证书,否则证书都是未知的。
    chixinzei
        2
    chixinzei  
       2021-02-24 17:27:52 +08:00
    补充,浏览器不会自行跟 CA 交互认证,而是根据内置 CA 证书进行算法验证匹配是否合法。
    chinvo
        3
    chinvo  
       2021-02-24 17:30:19 +08:00 via iPhone   1
    PDF 签名需要 Adobe 认证的 CA 签的证书,否则提示不可信
    matenshi
        4
    matenshi  
    OP
       2021-02-24 17:35:05 +08:00
    @chixinzei 是这样,可是我第 6 步把我这个自签的根证书导出来,并手动添加到阅读器的信任列表和安装到本机的受信任证书里了,这样不算吗。。。
    matenshi
        5
    matenshi  
    OP
       2021-02-24 17:36:58 +08:00
    @chinvo 嗯,现在用的不是 adobe reader 看的,不过如果我把通过 ca 的签名过后的用户证书先手动添加到受信任列表里的话,也是可以的,但是业务场景不允许。
    chinvo
        6
    chinvo  
       2021-02-24 17:44:03 +08:00 via iPhone
    如果不能添加自签名证书(通过安装包安装)的话,一般来说只能找受信任的 CA 合作或者买他们的中间证书。
    matenshi
        7
    matenshi  
    OP
       2021-02-24 18:05:40 +08:00
    @chinvo 不说能不能通过安装包安装,目前设想是可以添加自签名证书的(就是让用户电脑都手动添加这个证书)。 以前是买过安政通的电子签章软件,那个是有个专门的客户端来查看 pdf,现在新项目领导说自己弄个功能简单的。
    chinvo
        8
    chinvo  
       2021-02-24 18:12:19 +08:00 via iPhone
    @matenshi #7 那你们也可以自己做个 PDF 阅读器,内置上自己的 CA 就行
    joesonw
        9
    joesonw  
       2021-02-24 18:18:37 +08:00   1
    matenshi
        10
    matenshi  
    OP
       2021-02-24 18:19:41 +08:00
    @chinvo 现在的问题就是这个,我通过 ```keytool -exportcert ```命令把我的自签证书导出为 cer 文件,然后在阅读器上把该证书添加为受信任的根证书,某种意义上也算内置了自己的 CA 了吧。然后还是提示上面那个问题,我查看了经过签名的证书,证书链上的顶层确实是我导出的那个已经加入了受信任的根证书,结果还是这样。
    KuroNekoFan
        11
    KuroNekoFan  
       2021-02-24 20:22:31 +08:00 via iPhone   1
    好像已经有第三方的系统了
    esign.cn
    matenshi
        12
    matenshi  
    OP
       2021-02-24 22:12:54 +08:00
    @KuroNekoFan 谢谢,不过第三方的目前先不做考虑,因为要实现的功能比较简单。
    hysys32
        13
    hysys32  
       2021-02-25 07:45:58 +08:00 via iPhone   1
    Adobe 官方有个 echosign……我们公司各种签名都用它
    teawithlife
        14
    teawithlife  
       2021-02-25 08:54:07 +08:00   1
    @matenshi #5 从 5 楼的描述来说,是不是这样的情况:
    1. 你把 CA 签名过的用户证书加入信任列表,阅读器认证通过
    2. 你把 CA 证书加入信任列表,删去用户证书,阅读器认证失败

    如果是这样的话,问题应该出在第 4 步后少了一步,你要把用户证书和 CA 证书的公钥合并成一个证书文件,这样才能形成一个证书链,阅读器信任这个合并的证书文件后,才能从 CA 开始进行认证。如果有多级 CA,比如 CA1 签名 CA2,CA2 签名 CA3,CA3 签名用户证书,那这四张证书都要合并成一个文件才行

    原理应该就是这样,但是具体的操作你得自己找找
    kikikiabc
        15
    kikikiabc  
       2021-02-25 09:01:49 +08:00 via iPhone   1
    既然 CA 都自己建了,PDF 阅读器也自己搞一个不就行了。操作系统里面的信任关系,其他软件可以自行选择是否使用。比如 Firefox 浏览器或 AdobePdf 这些都自己搞了一套证书信任体系的。

    就像手机上的静音键,理论上是手机操作系统设置了一个应该静音的标记,但 App 是否遵守得靠自觉。
    a1274598858
        16
    a1274598858  
       2021-02-25 09:24:33 +08:00   1
    @chinvo adobe 阅读器信不信任根都不影响..只要 CA 证书是国内有资质的公司颁发的,并且 pdf 验签没有被篡改,这份文件都是有效的
    type
        17
    type  
       2021-02-25 09:36:51 +08:00   3
    楼主目前的方案适合公司内部自用,如果涉及与外部相对方的签名,这个是不具备法律效力的
    matenshi
        18
    matenshi  
    OP
       2021-02-25 16:30:35 +08:00
    解决了,问题有点像#14 楼说的,证书链的问题,不过问题是出在用 itext7 签名的时候。

    看代码我构造的数组长度只为 1,并且就导入了导出的二级证书,应该把根证书也导入进来,顺序的话是根证书在后头,这样就可以了。

    itext 还有另一个方法,就是通过 KeyStore 对象的 getCertificateChain 方法获取证书链,不过这样就需要把签名(正常的请看就是 CA 认证)后的证书(上面第 4 步生成的)导入到密钥库中才行。

    至于电子签章应该有的基本功能如 制章(在我看来就是弄个图片?)、盖章、撤章、验证之类的 itext7 都有提供相关的方法。
    最后这就像#17 楼说的,只能内部玩玩,并且 itext7 是 APGL 协议的。

    谢谢各位!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     854 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 22:23 PVG 06:23 LAX 15:23 JFK 18:23
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86