CEF Esig DSS Cookbook
Total Page:16
File Type:pdf, Size:1020Kb
DIGIT Unit B1
DSS Cookbook
CEF eSignature Building Block
Date: 05/03/2015 Doc. Version: V2.7
PM² Template v2.1.0 (Oct.2013)
Commission européenne, B-1049 Bruxelles / Europese Commissie, B-1049 Brussel - Belgium. Telephone: (32-2) 299 11 11. Office: 05/45. Telephone: direct line (32-2) 2999659.
Commission Européenne, L-2920 Luxembourg. Telephone: (352) 43 01-1. CEF eSignature Building Block DSS Cookbook
Document Control Information Settings Value Document Title: DSS Cookbook Project Title: CEF eSignature Building Block Document Author: Mr. Nicolas Pirard Project Owners: Mr. Andrea Servida, DG CNECT Project Manager: Mr. Philippe Schneider, DIGIT Doc. Version: V2.7 Sensitivity: High Date: 05/03/2015
Document Approver(s) and Reviewer(s): NOTE: All Approvers are required. Records of each approver must be maintained. All Reviewers in the list are considered required unless explicitly listed as Optional. Name DG Role Action Date Mr. Philippe Schneider DIGIT.A.3 Information Systems Architect / ISIP Review
Document history: The Document Author is authorized to make the following types of changes to the document without requiring that the document be re-approved: Editorial, formatting, and spelling Clarification
To request a change to this document, contact the Document Author or Owner. Changes to this document are summarized in the following table in reverse chronological order (latest version first). Revision Date Created by Short Description of Changes 0.01 17/12/2012 Robert Bielecki Version sent for Review Alignment following the comments of the European 0.05 13/02/2013 Robert Bielecki Commission 1.00 20/02/2013 Frank Meyer Version sent for Acceptance Alignment for publication following the comments of 1.01 19/03/2013 Robert Bielecki the European Commission 1.03 28/03/2013 Robert Bielecki Addressed further comments 1.04 09/04/2013 Robert Bielecki Aligned with DSS version 2.0/2.0.1 1.05 11/03/2013 Robert Bielecki Addressed further comments General update after implementation of the new 2.00 27/11/2013 Robert Bielecki validation process based on “ETSI TS 102 853” standard and incorporation of baseline profiles. 2.01 24/01/2014 Robert Bielecki Incorporation of WS and PdfBox Update of cookbook’s classes. XAdES: Managing 2.02 03/03/2014 Robert Bielecki different versions. - Performance optimisation: multi-threaded retrieval of validation data 2.1 08/06/2014 Robert Bielecki - Validation of non ADES signatures Information on the scope of the signatures
Date: 05/03/2015 2 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
2.2 16/07/2014 Robert Bielecki Update of test classes 2.3 15/09/2014 Vincent Bouckaert Alignment with version 4.2.0-RC 2.4 13/11/2014 Robert Bielecki Code sample updated 2.5 15/12/2014 Robert Bielecki Code sample updated 2.6 30/01/2014 Robert Bielecki Code sample updated 0.01 17/12/2012 Robert Bielecki Version sent for Review Alignment following the comments of the European 0.05 13/02/2013 Robert Bielecki Commission 1.00 20/02/2013 Frank Meyer Version sent for Acceptance Alignment for publication following the comments of 1.01 19/03/2013 Robert Bielecki the European Commission 1.03 28/03/2013 Robert Bielecki Addressed further comments 1.04 09/04/2013 Robert Bielecki Aligned with DSS version 2.0/2.0.1 1.05 11/03/2013 Robert Bielecki Addressed further comments General update after implementation of the new 2.00 27/11/2013 Robert Bielecki validation process based on “ETSI TS 102 853” standard and incorporation of baseline profiles. 2.01 24/01/2014 Robert Bielecki Incorporation of WS and PdfBox Update of cookbook’s classes. XAdES: Managing 2.02 03/03/2014 Robert Bielecki different versions. - Performance optimisation: multi-threaded retrieval of validation data 2.1 08/06/2014 Robert Bielecki - Validation of non ADES signatures - Information on the scope of the signatures 2.2 16/07/2014 Robert Bielecki Update of test classes 2.3 15/09/2014 Vincent Bouckaert Alignment with version 4.2.0-RC 2.4 13/11/2014 Robert Bielecki Code sample updated 2.5 15/12/2014 Robert Bielecki Code sample updated 2.6 30/01/2014 Robert Bielecki Code sample updated 2.7 05/03/2015 Nicolas Pirard - Aligned with DSS version 4.4.RC1 - Document migrated to CEF eSig template.
Date: 05/03/2015 3 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
REFERENCE AND APPLICABLE DOCUMENTS This section contains the lists of all references and applicable documents. When referring to any of the documents below, the bracketed reference will be used in the text, such as [R01].
Reference and applicable documents: Ref. Title Reference Version Date R01 DSS - Functional Analysis DSS4-FAD 2.02 24/01/2014 R02 DSS - Software Architecture DSS4-SAD 2.01 24/01/2014 R03 DSS - Design Model DSS2-DM 2.00 20/01/2012 R04 XAdES Specifications ETSI TS 101 903 1.4.2 12/2010 R05 CAdES Specifications ETSI TS 101 733 2.2.1 04/2013 R06 PAdES Specification ETSI TS 102 778 part 1-6 1.x.x 07/2010 Internet X.509 Public Key Infrastructure Certificate R07 and Certificate Revocation IETF RFC 5280 N/A May 2008 List (CRL) Profile R08 OCSP RFC 6960 N/A June 2013 TC Security - Electronic Signatures R09 and Infrastructures (ESI); ETSI TR 102 038 1.1.1 2002-04 XML format for signature policies Document management - Portable document R10 format - Part 1: ISO 32000-1 1 2008 PDF 1.7 Electronic Signatures and Infrastructures; Associated Signature Containers R11 ETSI TS 119 164-2 1.1.1 2012-03 Testing Compliance & Interoperability; Test Suite for ASiC interoperability test events Electronic Signatures and Infrastructures; R12 ETSI TS 102 918 1.1.1 2011-04 Associated Signature Containers Directive 1999/93/EC of the European Parliament R13 and of the Council of 13 December 1999 on a DIRECTIVE 1999/93/EC N/A 13/12/1999 Community framework for electronic signatures. Internet X.509 Public Key Infrastructure R14 RFC 3161 N/A 08/2001 Time-Stamp Protocol (TSP) Electronic Signatures and Infrastructures; R15 ETSI TS 102 853 1.1.1 2012-07 Signature verification procedures and policies Policy Requirements for Time-Stamping R16 RFC 3628 N/A 11/2003 Authorities (TSAs) R17 XAdES Baseline profiles ETSI TS 103 171 2.1.1 2012-03 R18 CAdES Baseline profiles ETSI TS 103 173 2.2.1 2013-04 R19 PAdES Baseline profiles ETSI TS 103 172 2.1.1 2012-03 R20 ASiC Baseline profiles ETSI TS 103 174 2.1.1 2012-03 DSS3-QTM4-Signature Validation Policy and R21 Report Simplification Analysis-v1.00.doc
Abbreviations and Acronyms: Code Description AdES Advanced Electronic Signature API Application Programming Interface ASiC Associated Signature Containers BB Building Block (CEF) CA Certificate authority
Date: 05/03/2015 4 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
CAdES CMS Advanced Electronic Signatures CD Commission Decision CEF Connecting Europe Facility CMS Cryptographic Message Syntax CRL Certificate Revocation List CSP Core Service Platform (CEF) CSP Cryptographic Service Provider DER Distinguished Encoding Rules DSA Digital Signature Algorithm - an algorithm for public-key cryptography DSI Digital Service Infrastructure (CEF) DSS Digital Signature Service EC European Commission eID Electronic Identity Card EJB Enterprise Java Beans ESI Electronic Signatures and Infrastructures ETSI European Telecommunications Standards Institute EUPL European Union Public License FAT Factory Acceptance Testing FSF Free Software Foundation GS Generic Service (CEF) GUI Graphical User Interface HSM Hardware Security Modules HTTP Hypertext Transfer Protocol I18N Internationalisation Is an open source library that allows you to create and manipulate PDF documents: iText http://itextpdf.com/ Java EE Java Enterprise Edition JavaDoc is developed by Sun Microsystems to create API documentation in HTML format from the JavaDoc comments in the source code. JavaDoc is an industrial standard for documenting Java classes. JAXB Java Architecture for XML Binding JCA Java Cryptographic Architecture JCE Java Cryptography Extension JDBC Java DataBase Connectivity LGPL Lesser General Public License LOTL List of Trusted List or List of the Lists LSP Large Scale Pilot MIT Massachusetts Institute of Technology MOCCA Austrian Modular Open Citizen Card Architecture; implemented in Java MS / Member State EUMS MS CAPI Microsoft Cryptographic Application Programming Interface OCF OEBPS Container Format OCSP Online Certificate Status Protocol ODF Open Document Format ODT Open Document Text OEBPS Open eBook Publication Structure OID Object Identifier OOXML Office Open XML OSI Open Source Initiative OSS Open Source Software PAdES PDF Advanced Electronic Signatures PAO Project and Architecture Office (CEF)
Date: 05/03/2015 5 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
PC/SC Personal computer/Smart Card PDF Portable Document Format PDFBox Apache PDFBox - A Java PDF Library: http://pdfbox.apache.org/ PKCS Public Key Cryptographic Standards It defines a file format commonly used to store X.509 private key accompanying public key certificates, PKCS#12 protected by symmetrical password PKIX Internet X.509 Public Key Infrastructure RSA Rivest Shamir Adleman - an algorithm for public-key cryptography SCA Signature Creation Application SCD Signature Creation Device SME Subject Matter Expert SMO Stakeholder Management Office (CEF) SOAP Simple Object Access Protocol SSCD Secure Signature-Creation Device SVA Signature Validation Application TL Trusted List TLManager Application for managing trusted lists. TSA Time Stamping Authority TSL Trust-service Status List TSP Time Stamp Protocol TSP Trusted Service Provider TST Time-Stamp Token UAT User Acceptance Testing UCF Universal Container Format URI Uniform Resource Identifier WP Work Package WSDL Web Services Description Language WYSIWYS What you see is what you sign XAdES XML Advanced Electronic Signatures XML Extensible Markup Language ZIP File format used for data compression and archiving
Date: 05/03/2015 6 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
TABLE OF CONTENTS REFERENCE AND APPLICABLE DOCUMENTS...... 4 1 INTRODUCTION...... 10
1.1 PURPOSE OF THE DOCUMENT...... 10 1.2 SCOPE OF THE DOCUMENT...... 10 1.3 INTENDED AUDIENCE...... 10 2 GENERAL FRAMEWORK STRUCTURE...... 11 3 SIGNATURE’S PROFILE SIMPLIFICATION...... 14 4 THE XML SIGNATURE (XADES)...... 15
4.1 XADES PROFILES...... 15 4.1.1 XAdES-BASELINE-B...... 15 4.1.1.1 Signing process...... 18 4.1.1.2 Additional attributes...... 19 4.1.1.3 Handling signature policy...... 22 4.1.2 XAdES-BASELINE-T...... 25 4.1.2.1 Use of online TSP source...... 26 4.1.3 XAdES-BASELINE-LT...... 28 4.1.4 XAdES-BASELINE-LTA...... 30 4.2 VARIOUS SETTINGS...... 31 4.2.1 Trust anchor inclusion policy...... 31 4.3 MULTIPLE SIGNATURES...... 31 4.4 THE XML SIGNATURE EXTENSION (XADES)...... 32 4.5 XADES-BASELINE-T...... 32 4.6 XADES-BASELINE-LT AND -LTA...... 34 4.7 XADES AND SPECIFIC SCHEMA VERSION...... 34 5 THE SIGNATURE VALIDATION...... 35
5.1 VALIDATION PROCESS...... 35 5.2 EU TRUSTED LISTS OF CERTIFICATION SERVICE PROVIDERS...... 39 5.3 VALIDATION RESULT MATERIALS...... 39 5.3.1 Simple Report...... 40 5.3.2 Detailed Report...... 40 5.3.3 Diagnostic Data...... 41 5.4 CUSTOMISED VALIDATION POLICY...... 44 5.5 STRUCTURAL SIGNATURE VALIDATION...... 47 6 CADES SIGNATURE AND VALIDATION...... 48 7 PADES SIGNATURE AND VALIDATION...... 50
7.1 PADES VISIBLE SIGNATURE...... 52 8 ASIC SIGNATURE AND VALIDATION...... 55 9 MANAGEMENT OF SIGNATURE TOKENS...... 58 9.1 PKCS#11...... 58 9.2 PKCS#12...... 59 9.3 MS CAPI...... 60 9.4 OTHER IMPLEMENTATIONS...... 61 10 MANAGEMENT OF CERTIFICATES SOURCES...... 66 11 MANAGEMENT OF CRL AND OCSP SOURCES...... 68
11.1 OTHER IMPLEMENTATIONS OF CRL AND OCSP SOURCES...... 68
Date: 05/03/2015 7 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
12 TSP SOURCES...... 71 13 WEB SERVICES...... 72
13.1 AVAILABLE SOAP SERVICES:...... 72 13.1 SIGNATURESERVICE...... 72 13.2 VALIDATIONSERVICE...... 76 14 HOW TO CHECK A SIMPLE CERTIFICATE...... 78 15 VALIDATION OF NON ADES SIGNATURES...... 81 16 HANDLING THE SCOPE OF THE SIGNATURE...... 82 17 TESTING FACILITY CLASSES...... 83
MOCK CRL SOURCES...... 83 MOCK OCSP SOURCES...... 83 ALWAYSVALIDOCSPSOURCE...... 83 MOCKTSLCERTIFICATESOURCE...... 83 MOCKTSPSOURCE...... 83 18 ACCESSING A STANDARD JAVA KEYSTORE...... 84
18.1 JAVAKEYSTORE...... 84 18.2 SIGNING „APPLICATION“...... 85 18.3 ROOT CLASS „COOKBOOK“...... 87
Date: 05/03/2015 8 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
TABLE OF FIGURES
FIGURE 1: SIGNATURE VALIDATION PROCESS SCHEME (SOURCE: [ETSI TS 102 853])...... 35 FIGURE 2: PKCS11SIGNATURETOKEN INTERFACE...... 58 FIGURE 3: PKCS12SIGNATURETOKEN INTERFACE...... 59 FIGURE 4: MSCAPISIGNATURETOKEN INTERFACE...... 60 FIGURE 5: IMPLEMENTATION OF SIGNATURETOKENCONNECTION FOR JAVA 6 IO PC/SC...... 62 FIGURE 6: CERTIFICATESOURCE INTERFACE (NOT TRUSTED PART)...... 67 FIGURE 7: CERTIFICATESOURCE INTERFACE (TRUSTED PART)...... 67 FIGURE 8: CRLSOURCE INTERFACE...... 69 FIGURE 9: OCSPSOURCE INTERFACE...... 70 FIGURE 10: SIGNATURESCOPE DEFAULT SPECIALIZATIONS...... 82 FIGURE 11: SIGNATURESCOPEFINDER AND ITS SPECIALIZATIONS...... 82 FIGURE 12: SIGNATURESCOPEFINDERFACTORY CLASS...... 82
TABLE OF CODE
CODE 1: SRC\MAIN\RESOURCES\XML_EXAMPLE.XML...... 15 CODE 2: COOKBOOK.EXAMPLE.SIGN.SIGNXMLXADESB.JAVA...... 17 CODE 3: COOKBOOK.EXAMPLE.SIGNXMLXADESBPROPERTIES.JAVA...... 20 CODE 4: COOKBOOK.EXAMPLE.SIGN.SIGNXMLXADESBALLDATAOBJECTSTIMESTAMP.JAVA...... 22 CODE 5: COOKBOOK.EXAMPLE.SIGN.SIGNXMLXADESBIMPLICITPOLICY.JAVA...... 23 CODE 6: COOKBOOK.EXAMPLE.SIGN.SIGNXMLXADESBEXPLICITPOLICY.JAVA...... 24 CODE 7: COOKBOOK.EXAMPLE.SIGN.SIGNXMLXADEST.JAVA...... 26 CODE 8: COOKBOOK.EXAMPLE.SIGN.SIGNXMLXADESTWITHONLINESOURCE.JAVA...... 27 CODE 9: COOKBOOK.EXAMPLE.SIGN.SIGNXMLXADESLT.JAVA...... 29 CODE 10: COOKBOOK.EXAMPLE.SIGN.COUNTERSIGNXMLXADESB.JAVA...... 32 CODE 11: COOKBOOK.EXAMPLE.SIGN.EXTENDSIGNXMLXADESBTOT.JAVA...... 33 CODE 12: COOKBOOK.EXAMPLE.VALIDATE.VALIDATESIGNEDXMLXADESB.JAVA...... 37 CODE 13: COOKBOOK.EXAMPLE.VALIDATE.VALIDATEXMLXADESLTWITHONLINESOURCES.JAVA...... 38 CODE 14: COOKBOOK.EXAMPLE.VALIDATE.VALIDATESIGNEDXMLXADESBWITHCUSTOMPOLICY.JAVA...... 46 CODE 15: COOKBOOK.EXAMPLE.SIGN.SIGNXMLCADESB.JAVA...... 49 CODE 16: COOKBOOK.EXAMPLE.SIGN.SIGNPDFPADESB.JAVA...... 51 CODE 17: COOKBOOK.EXAMPLE.SIGN. SIGNPDFPADESBVISIBLE.JAVA...... 54 CODE 18: COOKBOOK.EXAMPLE.SIGN.SIGNPDFASICB.JAVA...... 56 CODE 19: COOKBOOK.EXAMPLE.SIGN.SIGNXMLXADESBWITHMSCAPI.JAVA...... 61 CODE 20: COOKBOOK.EXAMPLE.SIGN.EIDNATIVESIGNATURETOKENCONNECTION.JAVA...... 63 CODE 21: COOKBOOK.EXAMPLE.SOURCES.EIDPRIVATEKEYENTRY.JAVA...... 64 CODE 22: COOKBOOK.EXAMPLE.SOURCES.APPLETVIEW.JAVA...... 65 CODE 23: COOKBOOK.EXAMPLE.SOURCES.INITONLINETSPSOURCE.JAVA...... 71 CODE 24: COOKBOOK.EXAMPLE.SIGN.SIGNWITHWS.JAVA...... 76 CODE 25: COOKBOOK.EXAMPLE.SOURCES.CHECKCERTIFICATE.JAVA...... 79 CODE 26: CONSTRAINT FILE FOR NON ADES SIGNATURE VALIDATION...... 81 CODE 27: EXAMPLE OF THE JAVA CODE TO VALIDATE NON ADES SIGNATURE...... 81 CODE 28: EXAMPLE OF THE SIMPLE (NON ADES) XML SIGNATURE...... 81 CODE 29: EXAMPLE OF THE SIMPLE REPORT ASSOCIATED TO THE NON ADES SIGNATURE...... 81 CODE 30: XSD DESCRIPTION OF THE SIGNATURE SCOPE...... 82 CODE 31: COOKBOOK.EXAMPLE.SOURCES.JAVAKEYSTORETOOL.JAVA...... 85 CODE 32: COOKBOOK.EXAMPLE.SIGN.SIGNINGAPPLICATION.JAVA...... 86 CODE 33: COOKBOOK.EXAMPLE.COOKBOOK.JAVA...... 88
Date: 05/03/2015 9 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
1 INTRODUCTION
1.1 Purpose of the Document
This document describes some examples of how to develop in Java using the DSS framework. The aim is to show to the developers, in a progressive manner, the different uses of the framework. It will familiarise them with the code step by step.
1.2 Scope of the Document
This document provides examples of code which allow easy handling of digital signatures. The examples are consistent with the Release 4.4.RC1 of SD-DSS framework which can be downloaded via https://joinup.ec.europa.eu/software/sd-dss/release/all. Three main features can be distinguished within the framework: The digital signature; The extension of a digital signature and; The validation of a digital signature. On a more detailed manner the following concepts and features are addressed in this document: Formats of the signed documents: XML, PDF, DOC, TXT, ZIP…; Packaging structures: enveloping, enveloped and detached; Forms of digital signatures: XAdES, CAdES, PAdES and ASiC; Profiles associated to each form of the digital signature; Trust management; Revocation data handling (OCSP and CRL sources); Certificate chain building; Signature validation and validation policy; Validation of the signing certificate. This is not an exhaustive list of all the possibilities offered by the framework and the proposed examples cover only the most useful features. However, to discover every detail of the operational principles of the framework, the JavaDoc is available within the source code. Please note that the SD-DSS framework is still under maintenance and new features will be released in the future.
1.3 Intended Audience
The present document is intended to be read by the following teams, but not limited to: DG MARKT Team; Development Teams.
Date: 05/03/2015 10 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
2 GENERAL FRAMEWORK STRUCTURE
The framework consists of the modules below. The core building blocks of SD-DSS: dss-common Contains the XSD schemas needed to parse and create Java classes for XAdES signature and TSL management (using JAXB as underlying technology). Additionally there are a very limited amount of other classes used by trusted list manager (TLManager). dss-document That is the most important module that allows to easy sign a document and to verify a signature. Different forms of signatures are implemented: XAdES CAdES, PAdES and ASiC. dss-itext This module was removed. The iText library for handling PDFs was replaced by PDFBox library. dss-report This module was removed. It allowed creating the technical validation report, indeed the result of the validation process is now represented in the generic form of XML. dss-spi It provides the Service Provider Interface of SD-DSS framework. It contains utility classes and some common functionality (PKCS#11, PKCS#12, MS CAPI…). dss-service This module provides the server-side implementation of services for TSL handling, revocation data and certificates retrieval. The integration building blocks of SD-DSS framework: dss-webservices This defines and implements a SOAP web service of SD-DSS server. This endpoint permits the use of web service functionality from a third party application. dss-webservices-client This module contains client side implementation of web services. It is used for demonstration purpose in the applet. MOCCA integration: sscd-mocca-adapter This module provides the integration layer for MOCCA within the SD-DSS framework. Some examples/demonstrations on how to use SD-DSS framework: dss-demo-webapp This is a Spring MVC based web application that provides an intuitive user interface giving access to an applet; implements the server-side logic and an administration part. dss-demo-applet This provides an applet with the following functionalities:
Date: 05/03/2015 11 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
Signing a document (including the communication with a SSCD); Extending an existing signature; Validating a signed document (including creation of simple validation report, detailed validation report and diagnostic data); Editing the validation policy.
Below you find a list of classes (under the eu.europa.ec.markt package) with their brief descriptions used in the examples of this cookbook: NOTE: The source code of the CookBook facility classes is included in this document, please follow the links.
Class Package Module AlwaysValidOCSPSource (C) cookbook CookBook facility classes A utility test class that simulates the use of OCSP. ASiCXMLSignatureService (C) *.dss.signature.cades dss-document ASiC-S signature implementation based on DocumentSignatureService. CAdESService (C) *.dss.signature.cades dss-document CAdES implementation of DocumentSignatureService. DSSDocument (I) *.dss.signature dss-spi Interface representing any document (signed or to be signed). DocumentSignatureService (I) *.dss.signature dss-document This interface provides operations to sign (also extend) and to verify a document. FileDocument (C) *.dss.signature dss-document Document implementation stored on file-system InMemoryDocument (C) *.dss.signature dss-document In memory representation of a document MockTSLCertificateSource (C) cookbook CookBook facility classes A utility test class that simulates the use of TSL. MockTSPSource (C) cookbook CookBook facility classes A utility test class that simulates the use of TSP. PAdESLevelBaselineLTA (C) *.dss.signature.pades dss-document Extends a PAdES signature by incorporating an archive timestamp. PAdESService (IC) *.dss.signature.pades dss-document PAdES implementation of the DocumentSignatureService. SignatureLevel (E) *.dss.signature dss-document All signature levels handled by the framework SignaturePackaging (E) *.dss.signature dss-document Packaging method of the signature SignatureParameters (C) *.dss.signature dss-document Parameters driving the signature creation/extension SignedDocumentValidator (C) *.dss.validation102853 dss-document Validates the signed document
Date: 05/03/2015 12 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
CommonCertificateVerifier (C) *.dss.validation102853 dss-document Verifies the status of a certificate using provided sources of information. XAdESService (C) *.dss.signature.xades dss-document XAdES implementation of DocumentSignatureService AbstractSignatureTokenConnection *.dss.signature.token dss-spi (AC) Sometimes, the signature process has to be split in two phases: the digest phase and the encryption phase. This separation is useful when the file and the SSCD are not on the same hardware. Four implementations of this abstract class are provided. CertificateSource (I) *.dss.validation102853 dss-spi The validation of a certificate requires accessing some other certificates from multiple sources (Trusted List, Trust Store, the signature itself). This interface provides an abstraction for accessing a certificate, regardless of the source. DigestAlgorithm (E) *.dss dss-spi Models a list of digest algorithms. Not all of them are supported. DSSPrivateKeyEntry (I) *.dss.signature.token dss-spi This interface represents a PrivateKey. KeyStoreCertificateSource (C) *.dss.validation102853 dss-spi Implements a CertificateSource using a JKS KeyStore. Pkcs12SignatureToken (C) *.dss.signature.token dss-spi Class holding all PKCS#12 file access logic. SignatureTokenConnection (I) *.dss.signature.token dss-spi This interface represents a connection through available API to the SSCD (SmartCard, MSCAPI, PKCS#12, MOCCA) CommonsHttpDataLoader (C) *.dss.validation.https dss-service Implementation of HTTPDataLoader using HttpClient. More flexible for HTTPS without having to add the certificate to the JVM TrustStore. OnlineCRLSource (C) *.dss.validation.crl dss-service This Online CRL repository implementation downloads the CRLs from the given CRL URIs. OnlineTSPSource (C) *.dss.validation.tsp dss-service Class encompassing a RFC 3161 TSA, accessed through HTTP(S) to a given URI TrustedListsCertificateSource (C) *.dss.validation102853.tsl dss-service Certificates coming from the Trusted List
Date: 05/03/2015 13 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
3 SIGNATURE’S PROFILE SIMPLIFICATION
The different formats of the digital signature make possible to cover a wide range of real live cases of use of this technique. Thus we distinguish the following formats: XAdES, CAdES, PAdES and ASIC. To each one of them a specific standard is dedicated. The wide variety of options, settings and versions of the standards makes their interoperability very difficult. This is the main reason for which new standards commonly called « baseline profiles » were published. Their goal is to limit the number of options and variants thereby making possible a better interoperability between different actors. In general can be said that for each format of the digital signature the number of security levels defined in the new standards has been reduced. Below is a comparative table of old and new levels for each format of the signature:
XAdES CAdES PAdES
STANDARD BASELINE STANDARD BASELINE STANDARD BASELINE
XADES-BES CADES-BES PADES-BES XADES-B CADES-B PADES-B XADES-EPES CADES-EPES PADES-EPES
XADES-T XADES-T CADES-T CADES-T PADES-T PADES-T
XADES-C CADES-C
XADES-X CADES-X
XADES-XL XADES-LT CADES-XL CADES-LT PADES-LT PADES-LT
XADES-A XADES-LTA CADES-A CADES-LTA PADES-LTV PADES-LTA
Note that the new version (v4) of the SD-DSS framework is compatible with the baseline profiles, it is no longer possible to use the standard profiles for signing purpose. The validation of the signature still takes into account the old profiles.
Date: 05/03/2015 14 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
4 THE XML SIGNATURE ( XADES )
The simplest way to address the digital signature passes through the XAdES format. Indeed, it allows to visualize the content of the signature with a simple text editor. Thus it becomes much easier to make the connection between theoretical concepts and their implementation. Before embarking on the use of the SD- DSS framework, it is advisable to read the following documents: XAdES Specifications (cf. [R04]) XAdESXAdES Baseline Profile (cf. [R17]) DSS Technical Analysis: Design Model (cf. [R03]) After reading these documents, it is clear that: - To electronically sign a document, a signing certificate (that proves the signer's identity) and the access to its associated private key is needed. - To electronically validate a signed document the signer’s certificate containing the public key is needed. To give a more colourful example: when a digitally signed document is sent to a given person or organization in order to be validated, the certificate with the public key used to create the signature must also be provided.
1.4 XAdES Profiles
The new ETSI standard [17] defines four conformance levels to address the growing need to protect the validity of the signature in time. Henceforth to denote the level of the signature the word “level” will be used. Follows the list of levels defined in the standard: XAdES-BASELINE- B: Basic Electronic Signature The lowest and simplest version just containing the SignedInfo, SignatureValue, KeyInfo and SignedProperties. This level combines the old –BES and –EPES levels. This form extends the definition of an electronic signature to conform to the identified signature policy. XAdES-BASELINE- T: Signature timestamp A timestamp regarding the time of signing is added to protect against repudiation. XAdES-BASELINE- LT: Long Term level Certificates and revocation data are embedded to allow verification in future even if their original source is not available. This level is equivalent to the old –XL level. XAdES-BASELINE- LTA: Long Term with Archive timestamp By using periodical timestamping (e.g. each year) compromising is prevented which could be caused by weakening previous signatures during a long-time storage period. This level is equivalent to the old –A level. NOTE: Old levels: -BES, -EPES, -C, -X, -XL, -A are not supported any more when signing. 1.4.1 XAdES-BASELINE-B To start, let's take a simple XML document:
Date: 05/03/2015 15 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
Since this is an XML document, we will use the XAdES signature and more particularly XAdES-BASELINE- B level, which is the lowest level of protection: just satisfying Directive (cf. [R13]) legal requirements for advanced signature. The normal process of signing wants to sign first with the level -B or level-T, and then later when it becomes necessary to complete the signature with superior levels. However, the framework allows signing directly with any level. The use of CAdES format for signing an XML document is also possible, but will be discussed later. When signing data, the resulting signature needs to be linked with the data to which it applies. This can be done either by creating a data set which combines the signature and the data (e.g. by enveloping the data with the signature or including a signature element in the data set) or placing the signature in a separate resource and having some external means for associating the signature with the data. So, we need to define the packaging of the signature, namely ENVELOPED, ENVELOPING or DETACHED.
ENVELOPED: when the signature applies to data that surround the rest of the document;
ENVELOPING: when the signed data form a sub-element of the signature itself;
DETACHED: when the signature relates to the external resources separated from it. For our example we will use ENVELOPED packaging. To write our Java code, we still need to specify the type of KeyStore to use for signing our document, more simply, where the private key can be found. We can choose between three different connection tokens: PKCS#11, PKCS#12, MS CAPI The SD-DSS also provides the support for MOCCA framework to communicate with the Smartcard with PC/SC, but it involves the installation of the MOCCA and IAIK libraries. To use a Java KeyStore please refer to the following paragraphs: #JavaKeyStore, #JKSSignatureToken and #Signing_with_JKSSignatureToken. In the package "eu.europa.ec.markt.dss.signature.token" (see [R03] document for further details on the structure of components and packages.), we can find three corresponding Java classes: Pkcs11SignatureToken, Pkcs12SignatureToken, MSCAPISignatureToken. To know more about the use of the different signature tokens, please consult “Management of Signature Tokens” chapter. In our example the class: "Pkcs12SignatureToken" will be used. A file in PKCS#12 format must be provided to the constructor of the class. It contains an X.509 private key accompanying the public key certificate and protected by symmetrical password. The certification chain can also be included in this file. It is possible to generate dummy certificates and their chains with OpenSSL. Please visit http://www.openssl.org/ for more details. This is the complete code that allows you to sign our XML document. package eu.europa.ec.markt.dss.cookbook.example.sign; import java.io.IOException; import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.xades.XAdESService;
Date: 05/03/2015 16 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to sign with XAdES-BASELINE-B */ public class SignXmlXadesB extends Cookbook {
public static void main(final String[] args) throws DSSException, IOException { // GET document to be signed - // Return DSSDocument toSignDocument prepareXmlDoc();
// Get a token connection based on a pkcs12 file commonly used to store private // keys with accompanying public key certificates, protected with a password-based // symmetric key - // Return AbstractSignatureTokenConnection signingToken // and it's first private key entry from the PKCS12 store // Return DSSPrivateKeyEntry privateKey preparePKCS12TokenAndKey();
// Preparing parameters for the XAdES signature SignatureParameters parameters = new SignatureParameters(); // We choose the level of the signature (-B, -T, -LT, -LTA). parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B); // We choose the type of the signature packaging (ENVELOPED, ENVELOPING, DETACHED). parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); // We set the digest algorithm to use with the signature algorithm. You must use the // same parameter when you invoke the method sign on the token. The default value is
// SHA256 parameters. setDigestAlgorithm (DigestAlgorithm. SHA256 ); // We choose the private key with the certificate and corresponding certificate chain. parameters.setPrivateKeyEntry(privateKey);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create XAdES service for signature XAdESService service = new XAdESService(commonCertificateVerifier);
// Get the SignedInfo XML segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm byte[] signatureValue = signingToken.sign(dataToSign, parameters. getDigestAlgorithm (), privateKey);
// We invoke the service to sign the document with the signature value obtained in // the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
//DSSUtils.copy(signedDocument.openStream(), System.out); DSSUtils.saveToFile(signedDocument.openStream(), "target/signedXmlXadesB.xml"); } }
Code 2: cookbook.example.sign.SignXmlXadesB.java What you may notice is that to sign a document we need to: - Create an object based on SignatureParameters class. The number of specified parameters depends on the type of signature. Generally, the number of specified parameters depends on the profile of signature. This object also defines some default parameters. - Choose the profile, packaging, signature digest algorithm. - Indicate the private key entry to be used. - Instantiate the adequate signature service. - Carry out the signature process.
Date: 05/03/2015 17 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
The encryption algorithm is determined by the private key and therefore cannot be compelled by the setter of the signature parameters object. It will cause an inconsistency in the signature making its validation impossible. This setter can be used in a particular context where the signing process is distributed on different machines and the private key is known only to the signature value creation process. See clause « Signing process » for more information. In the case where the private key entry object is not available, it is possible to choose the signing certificate and its certificate chain as in the following example: // We choose the certificate to be used for the signature. parameters.setSigningCertificate(x509SigningCertificate); // We choose the certificate chain to be used for the signature. parameters.setCertificateChain(x509IntermediateCertificate1, x509IntermediateCertificate2); Integrating the certificate chain in the signature simplifies the build of a prospective certificate chain during the validation process. By default the framework uses the current date time to set the signing date, but in the case where it is necessary to indicate the different time it is possible to use the setter «setSigningDate(Date) » as in the example: // We set the date of the signature. parameters.bLevel().setSigningDate(new Date()); When the specific service is instantiated a certificate verifier must be set. This object is used to provide four different sources of information: the source of trusted certificates (based on the trusted list(s) specific to the context); the source of intermediate certificates used to build the certificate chain till the trust anchor. This source is only needed when these certificates are not included in the signature itself; the source of OCSP; the source of CRL. In the current implementation this object is only used when profile –LT or –LTA are created. In the next release it will be used to identify the trust anchor and by the same limit the number of certificates included within the KeyInfo. 4.1.1 Signing process Once the parameters of the signature were identified the service object itself must be created. The service used will depend on the type of document to sign. In our case it is an XML file, so we will instantiate a XAdES service. The process of signing takes place in three stages. The first is the "getDataToSign ()" method call, passing as a parameter the document to be signed and the previously selected settings. This step returns the data which is going to be digested and encrypted. In our case it corresponds to the SignedInfo XMLDSig element. XAdESService service = new XAdESService(commonCertificateVerifier); byte[] dataToSign = service.getDataToSign(toSignDocument, parameters); The next step is a call to the function "sign()" which is invoked on the object token representing the KeyStore and not on the service. This method takes three parameters. The first is the array of bytes that must be signed. It is obtained by the previous method invocation. The second is the algorithm used to create the digest. You have the choice between SHA1, SHA256, and SHA512 (this list is not exhaustive). And the last one is the private key entry. DigestAlgorithm digestAlgorithm = parameters.getDigestAlgorithm(); byte[] signatureValue = token.sign(dataToSign, digestAlgorithm, privateKey); The last step of this process is the integration of the signature value in the signature and linking of that one to the signed document based on the selected packaging method. This is the method "signDocument()" on the
Date: 05/03/2015 18 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
service. We must pass to it three parameters: again the document to sign, the signature parameters and the value of the signature obtained in the previous step. This separation into three steps allows use cases where different environments have their precise responsibilities: specifically the distinction between communicating with the token and executing the business logic. When the breakdown of this process is not necessary than a simple call to only one method can be done as in the following example: service.signDocument(toSignDocument,parameters); Note that in this particular case, the signing token must be set. 4.1.2 Additional attributes For this type (XAdES-BASELINE-B) of signature it is possible to identify some additional attributes: SignerRole - contains claimed or certified roles assumed by the signer when creating the signature. SignatureProductionPlace - contains the indication of the purported place where the signer claims to have produced the signature. CommitmentTypeIndication - identifies the commitment undertaken by the signer in signing (a) signed data object(s) in the context of the selected signature policy. (for more information consult [R03]). AllDataObjectsTimeStamp – each time-stamp token within this property covers the full set of references defined in the Signature’s SignedInfo element, excluding references of type “SignedProperties”. IndividualDataObjectsTimeStamp - each time-stamp token within this property covers selected signed data objects. CounterSignature - contains signature(s) produced on the signature. The DSS framework allows to setup the following signed properties: SignerRole, SignatureProductionPlace, CommitmentTypeIndication, AllDataObjectsTimestamp, IndividualDataObjectsTimeStamp and CounterSignature.
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException; import java.util.ArrayList; import java.util.List;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.parameter.BLevelParameters; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to add signed properties to the signature. */ public class signXmlXadesBProperties extends Cookbook {
public static void main(String[] args) throws DSSException, IOException {
prepareXmlDoc();
preparePKCS12TokenAndKey();
Date: 05/03/2015 19 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
SignatureParameters parameters = new SignatureParameters(); parameters.setPrivateKeyEntry(privateKey); parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B); parameters. setDigestAlgorithm (DigestAlgorithm. SHA512 );
BLevelParameters bLevelParameters = parameters.bLevel(); bLevelParameters.addClaimedSignerRole("My Claimed Role");
BLevelParameters.SignerLocation signerLocation = new BLevelParameters.SignerLocation(); signerLocation.setCountry("Belgium"); signerLocation.setStateOrProvince("Luxembourg"); signerLocation.setPostalCode("1234"); signerLocation.setCity("SimCity"); bLevelParameters.setSignerLocation(signerLocation);
List
CommonCertificateVerifier verifier = new CommonCertificateVerifier(); XAdESService service = new XAdESService(verifier); byte[] dataToSign = service.getDataToSign(toSignDocument, parameters); byte[] signatureValue = signingToken.sign(dataToSign, parameters. getDigestAlgorithm (), privateKey);
DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
DSSUtils.saveToFile(signedDocument.openStream(), "signedXmlXadesBProperties.xml"); } }
Code 3: cookbook.example.signXmlXadesBProperties.java This code adds the following elements into the signature:
The following code provides an example of AllDataObjectsTimestamp generation for a XAdES Detached signature:
Date: 05/03/2015 20 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.parameter.DSSReference; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.parameter.TimestampParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.timestamp.TimestampService; import eu.europa.ec.markt.dss.signature.validation.TimestampToken; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CertificatePool; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier; import eu.europa.ec.markt.dss.validation102853.TimestampType;
/** * Shows how to generate an AllDataObjectsTimestamp */
public class SignXmlXadesBAllDataObjectsTimestamp extends Cookbook {
public static void main(String[] args) throws IOException { //Select document that will eventually be signed prepareXmlDoc();
//Set signature token preparePKCS12TokenAndKey();
//Define the references that have to be considered for the AllDataObjectsTimestamp List
//Define the signature parameters SignatureParameters signatureParameters = new SignatureParameters(); signatureParameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B); signatureParameters.setSignaturePackaging(SignaturePackaging.DETACHED); signatureParameters.setReferences(references); signatureParameters.setPrivateKeyEntry(signingToken.getKeys().get(0)); signatureParameters. setSigningToken ( signingToken );
TimestampParameters contentTimestampParameters = new TimestampParameters(); contentTimestampParameters.setDigestAlgorithm(DigestAlgorithm.SHA1);
contentTimestampParameters.setCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE); signatureParameters.setContentTimestampParameters(contentTimestampParameters);
//Define the contentTimestamp specific parameters TimestampService timestampService = new TimestampService(getMockTSPSource(), new CertificatePool()); TimestampToken timestampToken = timestampService.generateXAdESContentTimestampAsTimestampToken(toSignDocument, signatureParameters, TimestampType.INDIVIDUAL_DATA_OBJECTS_TIMESTAMP);
//The AllDataObjectsTimestamp has been generated, now we have to include it in the signature parameters List
Date: 05/03/2015 21 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
//Create the signature, including the AllDataObjectsTimestamp CommonCertificateVerifier verifier = new CommonCertificateVerifier(); XAdESService service = new XAdESService(verifier); DSSDocument signedDocument = service.signDocument(toSignDocument, signatureParameters);
InputStream is = new ByteArrayInputStream(signedDocument.getBytes());
DSSUtils.saveToFile(is, "signedXmlXadesBAllDataObjectsTimestamp.xml"); } }
Code 4: cookbook.example.sign.SignXmlXadesBAllDataObjectsTimestamp.java 4.1.3 Handling signature policy With the new standards [R17…20] the policy handling is linked to –B level. The old –EPES level is not used anymore by the framework. This does not alter the structure of the old signature but only modifies how to control the process of its creation. The SD-DSS framework allows you to reference a signature policy, which is a set of rules for the creation and validation of an electronic signature. It includes two kinds of text: In human readable form: It can be assessed to meet the requirements of the legal and contractual context in which it is being applied. In a machine processable form: To facilitate its automatic processing using the electronic rules. If no signature policy is identified then the signature may be assumed to have been generated or verified without any policy constraints, and hence may be given no specific legal or contractual significance through the context of a signature policy. The signer may reference the policy either implicitly or explicitly. An implied policy means the signer follows the rules of the policy but the signature does not indicate which policy. It is assumed the choice of policy is clear from the context in which the signature is used and SignaturePolicyIdentifier element will be empty. When the policy is not implied, the signature contains an ObjectIdentier that uniquely identifies the version of the policy in use. The signature also contains a hash of the policy document to make sure that the signer and verifier agree on the contents of the policy document. This example demonstrates an implicit policy identifier. To implement this alternative you must set SignaturePolicyId to empty string.
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.parameter.BLevelParameters; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to set implicit policy. */ public class SignXmlXadesBImplicitPolicy extends Cookbook {
Date: 05/03/2015 22 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
public static void main(String[] args) throws IOException {
prepareXmlDoc();
SignatureParameters parameters = new SignatureParameters(); parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B); parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); parameters. setDigestAlgorithm (DigestAlgorithm. SHA256 ); parameters.setPrivateKeyEntry(privateKey);
BLevelParameters bLevelParameters = parameters.bLevel();
BLevelParameters.Policy policy = new BLevelParameters.Policy(); policy.setId("");
bLevelParameters.setSignaturePolicy(policy);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create xadesService for signature XAdESService service = new XAdESService(commonCertificateVerifier);
// Get the SignedInfo segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm DigestAlgorithm digestAlgorithm = parameters. getDigestAlgorithm (); byte[] signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);
// We invoke the xadesService to sign the document with the signature value obtained // in the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
InputStream is = new ByteArrayInputStream(signedDocument.getBytes()); DSSUtils.saveToFile(is, "signedXmlXadesBImplicitPolicy.xml"); } }
Code 5: cookbook.example.sign.SignXmlXadesBImplicitPolicy.java An XML segment will be added to the signature’s qualified and signed properties:
The next example demonstrates an explicit policy identifier. This is obtained by setting –B profile signature policy and assigning values to the policy parameters. The Signature Policy Identifier is a URI or OID1 that uniquely identifies the version of the policy document. The signature will contain the identifier of the hash algorithm and the hash value of the policy document. The SD-DSS framework does not automatically calculate the hash value; it is to the developer to proceed with the calculation using for example java.security.MessageDigest class (rt.jar). It is important to keep the policy file intact in order to keep the hash constant. It would be wise to make the policy file read-only. See also chapter 7 for further information.
import java.io.ByteArrayInputStream; import java.io.IOException;
1 An object identifier (OID, see also http://en.wikipedia.org/wiki/Object_identifier) is a mechanism widely used as identification protocol developed by ITU-T and ISO / IEC to assign names to any type of object. It is not intended to be used for transient naming. OID, once assigned, it can not be reused for another object.
Date: 05/03/2015 23 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
import java.io.InputStream;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.parameter.BLevelParameters; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to set explicit policy. */ public class SignXmlXadesBExplicitPolicy extends Cookbook {
public static void main(String[] args) throws IOException {
prepareXmlDoc();
SignatureParameters parameters = new SignatureParameters(); parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B); parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); parameters. setDigestAlgorithm (DigestAlgorithm. SHA256 ); parameters.setPrivateKeyEntry(privateKey);
BLevelParameters bLevelParameters = parameters.bLevel();
//Get and use the explicit policy String signaturePolicyId = "http://www.example.com/policy.txt"; DigestAlgorithm signaturePolicyHashAlgo = DigestAlgorithm.SHA256; String signaturePolicyDescription = "Policy text to digest"; byte[] signaturePolicyDescriptionBytes = signaturePolicyDescription.getBytes(); byte[] digestedBytes = DSSUtils.digest(signaturePolicyHashAlgo, signaturePolicyDescriptionBytes);
BLevelParameters.Policy policy = new BLevelParameters.Policy(); policy.setId(signaturePolicyId); policy.setDigestAlgorithm(signaturePolicyHashAlgo); policy.setDigestValue(digestedBytes);
bLevelParameters.setSignaturePolicy(policy);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create xadesService for signature XAdESService service = new XAdESService(commonCertificateVerifier);
// Get the SignedInfo segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm DigestAlgorithm digestAlgorithm = parameters. getDigestAlgorithm (); byte[] signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);
// We invoke the xadesService to sign the document with the signature value obtained // in the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
InputStream is = new ByteArrayInputStream(signedDocument.getBytes()); DSSUtils.saveToFile(is, "signedXmlXadesBExplicitPolicy.xml"); } }
Code 6: cookbook.example.sign.SignXmlXadesBExplicitPolicy.java
Date: 05/03/2015 24 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
The following XML segment will be added to the signature qualified & signed properties (
1.4.2 XAdES-BASELINE-T XAdES-BASELINE-T is a signature for which there exists a trusted time associated to the signature. It provides the initial steps towards providing long term validity and more specifically it provides a protection against repudiation. This extension of the signature can be created as well during the generation process as validation process. However, the case when these validation data are not added during the generation process should no longer occur. The XAdES-BASELINE-T trusted time indications must be created before the signing certificate has been revoked or expired and close to the time that the XAdES signature was produced. The XAdES-BASELINE-T form must be built on a XAdES-BASELINE-B form. The SD-DSS framework allows extending the old -BES and -EPES profiles to the new BASELINE-T profile, indeed there is no difference in the structure of the signature. To implement this profile of signature you must indicate to the service the TSA source, which delivers from each Timestamp Request a Timestamp Response (RFC 3161 (cf. [R14])) containing tokens. Below is the source code that creates a XAdES-BASELINE-T signature. For our example we will use a virtual provider. In a real situation, you can use OnlineTSPSource class encompassing communication with Time Stamping Authority based on RFC 3161 (cf. [R14]) or you can implement your own class using TSPSource interface (see “TSP Sources” chapter for more details).
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.cookbook.mock.MockTSPSource; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier; /** * How to sign with XAdES-BASELINE-T */ public class SignXmlXadesT extends Cookbook {
public static void main(String[] args) throws DSSException, IOException {
// GET document to be signed - // Return DSSDocument toSignDocument prepareXmlDoc();
// Get a token connection based on a pkcs12 file commonly used to store private
Date: 05/03/2015 25 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
// keys with accompanying public key certificates, protected with a password-based // symmetric key - // Return AbstractSignatureTokenConnection signingToken // and it's first private key entry from the PKCS12 store // Return DSSPrivateKeyEntry privateKey ***** preparePKCS12TokenAndKey();
// Preparing parameters for the XAdES signature SignatureParameters parameters = new SignatureParameters(); // We choose the level of the signature (-B, -T, -LT, -LTA). parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_T); // We choose the type of the signature packaging (ENVELOPED, ENVELOPING, DETACHED). parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); // We set the digest algorithm to use with the signature algorithm. You must use the // same parameter when you invoke the method sign on the token. The default value is // SHA256 parameters. setDigestAlgorithm (DigestAlgorithm. SHA256 ); // We choose the private key with the certificate and corresponding certificate chain. parameters.setPrivateKeyEntry(privateKey);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create XAdES service for signature XAdESService service = new XAdESService(commonCertificateVerifier);
//Set the TimeStamp MockTSPSource mockTSPSource = new MockTSPSource(); service.setTspSource(mockTSPSource);
// Get the SignedInfo XML segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm byte[] signatureValue = signingToken.sign(dataToSign, parameters. getDigestAlgorithm (), privateKey);
// We invoke the service to sign the document with the signature value obtained in // the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
DSSUtils.saveToFile(signedDocument.openStream(), "signedXmlXadesT.xml"); } }
Code 7: cookbook.example.sign.SignXmlXadesT.java
The SignatureTimeStamp mandated by the XAdES-T form appears as an unsigned property within the QualifyingProperties:
4.1.4 Use of online TSP source If you know the address of an online TSP source, so you can make the call as below:
Date: 05/03/2015 26 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException; import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier; import eu.europa.ec.markt.dss.validation102853.tsp.OnlineTSPSource;
/** * How to sign with XAdES-BASELINE-T */ public class SignXmlXadesTWithOnlineSource extends Cookbook {
public static void main(String[] args) throws DSSException, IOException { // GET document to be signed - // Return DSSDocument toSignDocument prepareXmlDoc();
// Get a token connection based on a pkcs12 file commonly used to store private // keys with accompanying public key certificates, protected with a password-based // symmetric key - // Return AbstractSignatureTokenConnection signingToken // and it's first private key entry from the PKCS12 store // Return DSSPrivateKeyEntry privateKey ***** preparePKCS12TokenAndKey();
// Preparing parameters for the XAdES signature SignatureParameters parameters = new SignatureParameters(); // We choose the level of the signature (-B, -T, -LT, -LTA). parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_T); // We choose the type of the signature packaging (ENVELOPED, ENVELOPING, DETACHED). parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); // We set the digest algorithm to use with the signature algorithm. You must use the // same parameter when you invoke the method sign on the token. The default value is // SHA256 parameters. setDigestAlgorithm (DigestAlgorithm. SHA256 ); // We choose the private key with the certificate and corresponding certificate chain. parameters.setPrivateKeyEntry(privateKey);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create XAdES service for signature XAdESService service = new XAdESService(commonCertificateVerifier);
//Set the Timestamp source String tspServer = "http://services.globaltrustfinder.com/adss/tsa"; OnlineTSPSource onlineTSPSource = new OnlineTSPSource(tspServer); service.setTspSource(onlineTSPSource);
// Get the SignedInfo XML segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm byte[] signatureValue = signingToken.sign(dataToSign, parameters. getDigestAlgorithm (), privateKey); // We invoke the service to sign the document with the signature value obtained in // the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue); //DSSUtils.copy(signedDocument.openStream(), System.out); DSSUtils.saveToFile(signedDocument.openStream(), "signedXmlXadesTOnline.xml"); } }
Code 8: cookbook.example.sign.SignXmlXadesTWithOnlineSource.java
Date: 05/03/2015 27 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
If the timestamp source is not set the following exception is thrown: Exception in thread "main" eu.europa.ec.markt.dss.exception.ConfigurationException: A TSA must be configured This profile is not supported any more by SD-DSS framework. 1.4.3 XAdES-BASELINE-LT This level has to prove that the certification path was valid, at the time of the validation of the signature, up to a trust point according to the naming constraints and the certificate policy constraints from the "Signature Validation Policy". It will add to the signature the CertificateValues and RevocationValues unsigned properties. The CertificateValues element contains the full set of certificates that have been used to validate the electronic signature, including the signer's certificate. However, it is not necessary to include one of those certificates, if it is already present in the ds:KeyInfo element of the signature. This is like SD-DSS framework behaves. In order to find a list of all the certificates and the list of all revocation data, an automatic process of signature validation is executed. To carry out this process an object called CertificateVerifier must be passed to the service. The implementer must set some of its properties like par example the source of trusted certificates. The code below shows how to use the default parameters with this object. Please refer to “The Signature Validation” chapter to have the further information. It also includes an example of how to implement this level of signature:
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier; import eu.europa.ec.markt.dss.validation102853.crl.OnlineCRLSource; import eu.europa.ec.markt.dss.validation102853.https.CommonsDataLoader; import eu.europa.ec.markt.dss.validation102853.ocsp.OnlineOCSPSource; import eu.europa.ec.markt.dss.validation102853.tsl.TSLRefreshPolicy; import eu.europa.ec.markt.dss.validation102853.tsl.TrustedListsCertificateSource;
/** * How to sign with XAdES-BASELINE-LT */ public class SignXmlXadesLT extends Cookbook {
public static void main(String[] args) throws DSSException, IOException {
// GET document to be signed - // Return DSSDocument toSignDocument prepareXmlDoc();
// Get a token connection based on a pkcs12 file commonly used to store private // keys with accompanying public key certificates, protected with a password-based // symmetric key - // Return AbstractSignatureTokenConnection signingToken // and it's first private key entry from the PKCS12 store // Return DSSPrivateKeyEntry privateKey ***** preparePKCS12TokenAndKey();
// Preparing parameters for the XAdES signature SignatureParameters parameters = new SignatureParameters(); // We choose the level of the signature (-B, -T, -LT, -LTA). parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_LT); // We choose the type of the signature packaging (ENVELOPED, ENVELOPING, DETACHED). parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); // We set the digest algorithm to use with the signature algorithm. You must use the // same parameter when you invoke the method sign on the token. The default value is
Date: 05/03/2015 28 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
// SHA256 parameters. setDigestAlgorithm (DigestAlgorithm. SHA256 ); // We choose the private key with the certificate and corresponding certificate chain. parameters.setPrivateKeyEntry(privateKey);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();
CommonsDataLoader commonsHttpDataLoader = new CommonsDataLoader();
String lotlUrl = "https://ec.europa.eu/information_society/policy/esignature/trusted- list/tl-mp.xml"; TrustedListsCertificateSource tslCertificateSource = new TrustedListsCertificateSource(); tslCertificateSource.setLotlUrl(lotlUrl); tslCertificateSource.setCheckSignature(false); tslCertificateSource.setDataLoader(commonsHttpDataLoader); tslCertificateSource.setTslRefreshPolicy(TSLRefreshPolicy.NEVER); tslCertificateSource.init(); commonCertificateVerifier.setTrustedCertSource(tslCertificateSource);
OnlineCRLSource onlineCRLSource = new OnlineCRLSource(); onlineCRLSource.setDataLoader(commonsHttpDataLoader); commonCertificateVerifier.setCrlSource(onlineCRLSource);
OnlineOCSPSource onlineOCSPSource = new OnlineOCSPSource(); onlineCRLSource.setDataLoader(commonsHttpDataLoader); commonCertificateVerifier.setOcspSource(onlineOCSPSource);
// Create XAdES service for signature XAdESService service = new XAdESService(commonCertificateVerifier); service.setTspSource(getMockTSPSource());
// Get the SignedInfo XML segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm byte[] signatureValue = signingToken.sign(dataToSign, parameters. getDigestAlgorithm (), privateKey);
// We invoke the service to sign the document with the signature value obtained in // the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
//DSSUtils.copy(signedDocument.openStream(), System.out); DSSUtils.saveToFile(signedDocument.openStream(), "signedXmlXadesLT.xml"); } }
Code 9: cookbook.example.Sign.SignXmlXadesLT.java
Date: 05/03/2015 29 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
The following XML segment will be added to the signature qualified and unsigned properties:
NOTE: The use of online sources can significantly increase the execution time of the signing process. For testing purpose you can create your own source of data. In last example the CommonsHttpDataLoader is used to provide the communication layer for HTTP protocol. Each source which need to go through the network to retrieve data need to have this component set. 1.4.4 XAdES-BASELINE-LTA When the cryptographic data becomes weak and the cryptographic functions become vulnerable the auditor should take steps to maintain the validity of the signature. The XAdES-BASELINE-A form uses a simple approach called “archive validation data”. It adds additional time-stamps for archiving signatures in a way that they are still protected, but also to be able to prove that the signatures were validated at the time when the used cryptographic algorithms were considered safe. The time-stamping process may be repeated every time the protection used becomes weak. Each time-stamp needs to be affixed before either the signing key or the algorithms used by the TSA are no longer secure. XAdES-A form adds the ArchiveTimestamp element within the UnsignedSignatureProperties and may contain several ArchiveTimestamp elements. Below is an example of the implementation of this level of signature (but in practice, we will rather extend the signature to this level when there is a risk that the cryptographic functions become vulnerable or when one of certificates arrives to its expiration date): … parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_LTA); …
The following XML segment will be added to the signature qualified and unsigned properties:
Date: 05/03/2015 30 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
1.5 Various settings
1.5.1 Trust anchor inclusion policy It is possible to indicate to the framework if the certificate related to the trust anchor should be included to the signature or not. The setter #setTrustAnchorBPPolicy of the BLevelParameters class should be used for this purpose. This rule applies as follows: when -B level is constructed the trust anchor is not included, when -LT level is constructed the trust anchor is included. NOTE: when trust anchor baseline profile policy is defined only the certificates previous to the trust anchor are included when -B level is constructed.
1.6 Multiple signatures
In everyday life, there are many examples where it is necessary to have multiple signatures covering the same document, such as a contract to purchase a vehicle. Depending on the fact that the order of the signatures is important or not, we can establish two basic categories for multiple signatures: independent signatures; countersignatures.
Independent signatures are parallel signatures where the ordering of the signatures is not important. The computation of these signatures is performed on exactly the same input but using different private keys.
Countersignatures are signatures generated over existing signatures. The computation of these signatures is performed strictly over a selected signature’s SignatureValue element. Below is an example of how to generate a countersignature using the DSS framework:
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.parameter.BLevelParameters; import eu.europa.ec.markt.dss.parameter.BLevelParameters.SignerLocation; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.FileDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to generate a countersignature over an existing signature */ public class CountersignXmlXadesB extends Cookbook {
public static void main(final String[] args) throws IOException {
//Select a document to countersign DSSDocument toCountersignDocument = new FileDocument("signedXmlXadesB.xml");
// Create a token connection based on a pkcs12 file preparePKCS12TokenAndKey();
// Preparing the parameters for the countersignature SignatureParameters countersigningParameters = new SignatureParameters(); countersigningParameters. setSigningToken ( signingToken ); countersigningParameters.setPrivateKeyEntry(privateKey); countersigningParameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B);
Date: 05/03/2015 31 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
countersigningParameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); //The ID of the signature was manually retrieved in the document to countersign countersigningParameters.setToCounterSignSignatureId("id- E2727C1693F3602F89D515E6BEE5F1DC");
//Possibility to add properties in the countersignature BLevelParameters blParam = countersigningParameters.bLevel(); SignerLocation location = new SignerLocation(); location.setCountry("Belgium"); location.setStateOrProvince("Luxembourg"); blParam.setSignerLocation(location);
// Countersign the document CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); XAdESService service = new XAdESService(commonCertificateVerifier); DSSDocument countersignedDocument = service.counterSignDocument(toCountersignDocument, countersigningParameters);
InputStream is = new ByteArrayInputStream(countersignedDocument.getBytes()); DSSUtils.saveToFile(is, "countersigned.xml"); } }
Code 10: cookbook.example.sign.CountersignXmlXadesB.java Following this logic, it is therefore possible to generate arbitrarily long signature chains, where each subsequent signature countersigns a previous one.
Note: The XAdES enveloping form of a signature does not operate with multiple signatures.
1.7 The XML Signature Extension (XAdES)
The -B level contains immutable signed properties. Once this level is created, these properties cannot be changed. The levels -T/-LT/-LTA add unsigned properties to the signature. This means that the properties of these levels could be added afterwards to any AdES signature. This addition helps to make the signature more resistant to cryptographic attacks on a longer period of time. The extension of the signature is incremental, i.e. when you want to extend the signature to the level -LT the lower level (-T) will also be added. The whole extension process is implemented by reusing components from signature production. To extend a signature we proceed in the same way as in the case of a signature, except that you have to call the function “extendDocument” instead of the “sign” function. Note that when the document is signed with several signatures then they are all extended.
1.8 XAdES-BASELINE-T
The XAdES-BASELINE-T trusted time indications have to be created before a certificate has been revoked or expired and close to the time that the XAdES signature was produced. It provides a protection against repudiation. The framework adds the timestamp only if there is no timestamp or there is one but the creation of a new extension of the level-T is deliberate (using another TSA). It is not possible to extend a signature which already incorporates higher level as –LT or –LTA. In the theory it would be possible to add another –T level when the signature has already reached level –LT but the framework prevents this operation. Note that if the signed document contains multiple signatures, then all the signatures will be extended to level –T. It is also possible to sign a document directly at level -T. Here is an example of creating an extension of type T:
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream;
Date: 05/03/2015 32 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.FileDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to extend with XAdES-BASELINE-T */ public class ExtendSignXmlXadesBToT extends Cookbook {
public static void main(final String[] args) throws IOException {
toExtendDocument = new FileDocument("signedXmlXadesB.xml");
SignatureParameters parameters = new SignatureParameters(); parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED);
parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_T);
CommonCertificateVerifier certificateVerifier = new CommonCertificateVerifier(); XAdESService xadesService = new XAdESService(certificateVerifier); xadesService.setTspSource(getMockTSPSource());
DSSDocument extendedDocument = xadesService.extendDocument(toExtendDocument, parameters);
//DSSUtils.copy(extendedDocument.openStream(), System.out); InputStream is = new ByteArrayInputStream(extendedDocument.getBytes()); DSSUtils.saveToFile(is, "extendedSignedXmlXadesBToT.xml"); } }
Code 11: cookbook.example.sign.ExtendSignXmlXadesBToT.java Here is the result of adding a new extension of type-T to an already existing -T level signature:
If the signature to extend does not contain valid XML (in the example below the SignedProperties tag has been misspelled) then you will get the following error message: [Fatal Error] :1:7575: The element type "xades:SignedPrssssoperties" must be terminated by the matching end-tag "". Exception in thread "main" eu.europa.ec.markt.dss.exception.DSSException: org.xml.sax.SAXParseException: The element type "xades:SignedPrssssoperties" must be terminated by the matching end-tag "".
at eu.europa.ec.markt.dss.DSSXMLUtils.buildDOM(DSSXMLUtils.java:330) at eu.europa.ec.markt.dss.signature.xades.XAdESProfileT.extendSignatures(XAdESProfileT.java:171)
Date: 05/03/2015 33 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
1.9 XAdES-BASELINE-LT and -LTA
For these types of extensions, the procedure to follow is the same as the case of the extension of type T. Please refer to the chapter XAdES Profiles (XAdES) to know specific parameters for each level of signature and which must be positioned.
1.10 XAdES and specific schema version
Some signatures may have been created with an older version of XAdES standard using different schema definition. To take into account the validation of such signatures the class eu.europa.ec.markt.dss.validation102853.xades.XPathQueryHolder was created. This class includes all XPath queries which are used to explore the elements of the signature. It is now easy to extend this class in order to define specific queries to a given schema. The SD-DSS framework proposes in standard the class eu.europa.ec.markt.dss.validation102853.xades.XAdES111XPathQueryHolder that defines the XPath queries for the version "http://uri.etsi.org/01903/v1.1.1#" of XAdES standard. When carrying out the validation process of the signature, the choice of query holder to be used is taken by invoking the method: eu.europa.ec.markt.dss.validation102853.xades.XPathQueryHolder#canUseThisXPathQueryHolder This choice is made based on the namespace. If the namespace is: http://uri.etsi.org/01903/v1.3.2# then the default query holder is used, if the namespace is http://uri.etsi.org/01903/v1.1.1# the XAdES111XPathQueryHolder is used. The element used to choose the namespace is “QualifyingProperties”. To implement another query holder the class XPathQueryHolder must be extended, new XPath queries defined and the method canUseThisXPathQueryHolder overridden. In case there is a need to use only a specific query holder the following steps should be followed:
Call: eu.europa.ec.markt.dss.validation102853.xades.XMLDocumentValidator#clearQueryHolders Call: eu.europa.ec.markt.dss.validation102853.xades.XMLDocumentValidator#addXPathQueryHolder and pass the specific query holder
Date: 05/03/2015 34 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
5 THE SIGNATURE VALIDATION
Generally and following ETSI standard, the validation process of an electronic signature must provide one of the three following status: INVALID, VALID or INDETERMINATE. A VALID response indicates that the signature has passed verification and it complies with the signature validation policy. An INVALID response indicates that either the signature format is incorrect or that the digital signature value fails verification. An INDETERMINATE validation response indicates that the format and digital signature verifications have not failed but there is insufficient information to determine if the electronic signature is valid. For each of the validation checks, the validation process must provide information justifying the reasons for the resulting status indication as a result of the check against the applicable constraints. In addition, the ETSI standard defines a consistent and accurate way for justifying statuses under a set of sub-indications.
1.11 Validation Process
Since version 3 of the SD-DSS framework the validation process is based on the new ETSI standard [R15]. It is driven by the validation policy and allows long term signature validation. It not only verifies the existence of certain data and their validity, but it also checks the temporal dependences between these elements. The signature check is done following basic building blocks. On the simplified diagram below, showing the process of the signature validation, you can follow the relationships between each building block which represents a logic set of checks used in validation process.
Figure 1: Signature Validation Process Scheme (source: [ETSI TS 102 853]) To have a thorough understanding of the validation process, please refer to [R21].
Date: 05/03/2015 35 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
Note that the current version of the framework during the validation process does not indicate what part of document was signed. However, in the case of the XAdES signature XPath transformations present in the signature will be applied, in the case of CAdES or PAdES signature the whole document must be signed. At the end of the validation process three reports are created. They contain the different details level concerning the validation result. They provide three kinds of visions of validation process: macroscopic, microscopic and input data. For more information about these reports, please refer to “Simple Report” chapter. Below is the simplest example of the validation of the signature of a document. The first thing to do is instantiating an object named validator, which orchestrates the verification of the different rules. To perform this it is necessary to invoke a static method fromDocument() on the abstract class SignedDocumentValidator. This method returns the object in question whose type is chosen dynamically based on the type of source document. The DSS framework provides four types of validators: XMLDocumentValidator, CMSDocumentValidator, PDFDocumentValidator, ASiCXMLDocumentValidator. The next step is to create an object that will check the status of a certificate using the Trusted List model (see “EU Trusted Lists of Certification Service Providers” for more information). In our example, this object is instantiated from the TrustedListCertificateVerifier class. In turn, this object needs an OCSP and/or CRL source and a TSL source (which defines how the certificates are retrieved from the Trusted Lists). See chapter “Management of CRL and OCSP Sources” for more information concerning sources. Note this validation process uses the default validation policy which can be changed by each implementer. To see how to use a customised validation policy, please refer to “1.14”. More information can be found on joinup: https://joinup.ec.europa.eu/asset/sd-dss/topic/how-validate-signature-real-crl-ocsp-and-certificate- sources#comment-15459
package eu.europa.ec.markt.dss.cookbook.example.validate;
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.cookbook.sources.AlwaysValidOCSPSource; import eu.europa.ec.markt.dss.cookbook.mock.MockServiceInfo; import eu.europa.ec.markt.dss.cookbook.mock.MockTSLCertificateSource; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.FileDocument; import eu.europa.ec.markt.dss.validation102853.CertificateToken; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier; import eu.europa.ec.markt.dss.validation102853.SignedDocumentValidator; import eu.europa.ec.markt.dss.validation102853.condition.ServiceInfo; import eu.europa.ec.markt.dss.validation102853.report.Reports; import eu.europa.ec.markt.dss.validation102853.report.SimpleReport;
/** * How to validate a XAdES-BASELINE-B signature. */ public class ValidateSignedXmlXadesB extends Cookbook {
public static void main(String[] args) throws IOException {
// To be able to validate our fake signature, we must define one of the certificates in the chain as trusted anchor. // If you have a real signature for which it is possible to build the chain till the TSL then just skip this point. preparePKCS12TokenAndKey(); final CertificateToken[] certificateChain = privateKey.getCertificateChain();
Date: 05/03/2015 36 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
final CertificateToken trustedCertificate = certificateChain[0];
// Already signed document - Created with the SignXmlXadesB Class DSSDocument document = new FileDocument("signedXmlXadesB.xml"); SignedDocumentValidator validator = SignedDocumentValidator.fromDocument(document);
CommonCertificateVerifier verifier = new CommonCertificateVerifier(); AlwaysValidOCSPSource ocspSource = new AlwaysValidOCSPSource(); verifier.setOcspSource(ocspSource); /** * This Trusted List Certificates Source points to * "https://ec.europa.eu/information_society/policy/esignature/trusted-list/tl-mp.xml" */ MockTSLCertificateSource trustedCertSource = new MockTSLCertificateSource(); ServiceInfo mockServiceInfo = new MockServiceInfo(); trustedCertSource.addCertificate(trustedCertificate, mockServiceInfo); verifier.setTrustedCertSource(trustedCertSource);
validator.setCertificateVerifier(verifier);
Reports reports = validator.validateDocument(); SimpleReport simpleReport = reports.getSimpleReport();
InputStream is = new ByteArrayInputStream(simpleReport.toByteArray()); DSSUtils.saveToFile(is, "validationXmlXadesB.xml"); } }
Code 12: cookbook.example.validate.ValidateSignedXmlXadesB.java
It is also possible to use the real sources of OSCP, CRL and certificates:
package eu.europa.ec.markt.dss.cookbook.example.validate;
import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.cookbook.mock.MockServiceInfo; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.FileDocument; import eu.europa.ec.markt.dss.validation102853.CertificateToken; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier; import eu.europa.ec.markt.dss.validation102853.SignedDocumentValidator; import eu.europa.ec.markt.dss.validation102853.crl.OnlineCRLSource; import eu.europa.ec.markt.dss.validation102853.https.CommonsDataLoader; import eu.europa.ec.markt.dss.validation102853.https.FileCacheDataLoader; import eu.europa.ec.markt.dss.validation102853.ocsp.OnlineOCSPSource; import eu.europa.ec.markt.dss.validation102853.report.DetailedReport; import eu.europa.ec.markt.dss.validation102853.report.Reports; import eu.europa.ec.markt.dss.validation102853.report.SimpleReport; import eu.europa.ec.markt.dss.validation102853.tsl.TSLRefreshPolicy; import eu.europa.ec.markt.dss.validation102853.tsl.TrustedListsCertificateSource;
/** * How to validate a XAdES-BASELINE-LT enveloped signature with online sources. */ public class ValidateXmlXadesLTWithOnlineSources extends Cookbook {
public static void main(String[] args) throws IOException {
// To be able to validate our fake signature, we must define one of the certificates in the chain as trusted anchor. // If you have a real signature for which it is possible to build the chain till the TSL then just skip this point. preparePKCS12TokenAndKey(); final CertificateToken[] certificateChain = privateKey.getCertificateChain(); final CertificateToken trustedCertificate = certificateChain[0];
Date: 05/03/2015 37 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
// Already signed document DSSDocument document = new FileDocument("signedXmlXadesLT.xml");
SignedDocumentValidator validator = SignedDocumentValidator.fromDocument(document);
CommonsDataLoader commonsDataLoader = new CommonsDataLoader();
CommonCertificateVerifier verifier = new CommonCertificateVerifier(); OnlineCRLSource crlSource = new OnlineCRLSource(); crlSource.setDataLoader(commonsDataLoader); verifier.setCrlSource(crlSource);
OnlineOCSPSource ocspSource = new OnlineOCSPSource(); // The default OCSPDataLoader is created. You can also create your own HttpDataLoader. verifier.setOcspSource(ocspSource);
// SEE NOTE 1 FileCacheDataLoader fileCacheDataLoader = new FileCacheDataLoader(); File cacheFolder = new File("/temp"); fileCacheDataLoader.setFileCacheDirectory(cacheFolder);
TrustedListsCertificateSource certificateSource = new TrustedListsCertificateSource();
certificateSource.setLotlUrl("https://ec.europa.eu/information_society/policy/esignature/trusted- list/tl-mp.xml"); certificateSource.setCheckSignature(true); certificateSource.setDataLoader(fileCacheDataLoader); certificateSource.setTslRefreshPolicy(TSLRefreshPolicy.NEVER); certificateSource.setLotlCertificate("file:/" + getPathFromResource("/lotl.cer")); certificateSource.init();
certificateSource.addCertificate(trustedCertificate, new MockServiceInfo()); verifier.setTrustedCertSource(certificateSource);
verifier.setDataLoader(fileCacheDataLoader);
validator.setCertificateVerifier(verifier);
Reports reports = validator.validateDocument(); SimpleReport simpleReport = reports.getSimpleReport(); DetailedReport detailReport = reports.getDetailedReport();
InputStream is = new ByteArrayInputStream(simpleReport.toByteArray()); DSSUtils.saveToFile(is, "validationXmlXadesLT_Online_simpleReport.xml");
is = new ByteArrayInputStream(detailReport.toByteArray()); DSSUtils.saveToFile(is, "validationXmlXadesLT_Online_detailReport.xml");
} }
Code 13: cookbook.example.validate.ValidateXmlXadesLTWithOnlineSources.java NOTE: When using the TrustedListsCertificateSource class, for performance reasons, consider creating a single instance of this class and initialize it only once. NOTE: In general, the signature must cover the entire document so that the DSS framework can validate it. However, for example in the case of a XAdES signature, some transformations can be applied on the XML document. They can include operations such as canonicalization, encoding/decoding, XSLT, XPath, XML schema validation, or XInclude. XPath transforms permit the signer to derive an XML document that omits portions of the source document. Consequently those excluded portions can change without affecting signature validity. Note that the current version of the framework can sign only the entire document.
Date: 05/03/2015 38 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
1.12 EU Trusted Lists of Certification Service Providers
On 16 October 2009 the European Commission adopted a Decision setting out measures facilitating the use of procedures by electronic means through the ‘points of single contact’ under the Services Directive. One of the measures adopted by the Decision consisted in the obligation for Member States to establish and publish by 28.12.2009 their Trusted List of supervised/accredited certification service providers issuing qualified certificates to the public. The objective of this obligation is to enhance cross-border use of electronic signatures by increasing trust in electronic signatures originating from other Member States. The Decision was updated several times since 16.10.2009; the last amendment was made on 01.02.2014. The consolidated version is available here for information. In order to allow access to the trusted lists of all Member States in an easy manner, the European Commission has published a central list with links to national "trusted lists". This central list will now be designated in the document under the abbreviation LOTL. To manage this LOTL the SD-DSS framework offers the class eu.europa.ec.markt.dss.validation102853.tsl.TrustedListsCertificateSource which is responsible for: Downloading of the list of lists, Verifying the signature of the List of the Lists. o This phase is optional; in fact the LOTL does not change very often, so it is necessary to check its signature when it has been modified. TrustedListsCertificateSource class does not automatically manage the change of LOTL. The user can manually force or not the signature verification through the setter "public void setCheckSignature (boolean CheckSignature)". The default value is true. o To validate the signature of the LOTL “TrustedListsCertificateSource” needs the certificate used to sign it. This certificate can be provided using the “public void setLotlCertificate(Resource lotlCertificate)” setter. The framework does not verify the origin of this certificate (see page 8 of the Official Journal of the European Union C 374 of 22.12.2011.); it assumes that the original is secure. Business loading of the LOTL For each member state downloading their list o The same business logic is applied to the individual list as for the LOTL. Loading all the certificates of all the Trusted Lists.
These certificates are used in the process of validating a signature to establish the trust relationship between the signing certificate and the trust anchor.
It is possible to control the refresh of lists indicating the appropriate policy. The enumeration TSLRefreshPolicy drives the class TrustedListsCertificateSource. The following TSL refresh policies are available: ALWAYS: the refresh is always performed; WHEN_NECESSARY: the refresh is performed only if the hash value described in "ETSI TS 119 612 V1.1.1 (2013-06) 6.1 TL publication" has changed. WHEN_NECESSARY_OR_INDETERMINATE: as above but also when the mechanism described in "ETSI TS 119 612 V1.1.1 (2013-06) 6.1 TL publication" is not supported. NEVER: the refresh is never performed. It is left to the responsibility an external application.
1.13 Validation Result Materials
The result of the validation process consists of three elements: the simple report, the detailed report and, the diagnostic data.
Date: 05/03/2015 39 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
All these reports are encoded using XML, which allows the implementer to easily manipulate and extract information for further analysis. You will find below a detailed description of each of these elements. 1.13.1 Simple Report This is a sample of the simple validation report. ------Simple report------
------Validation report------
Date: 05/03/2015 40 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
For example the Basic Building Blocks are divided into five elements: ISC - IDENTIFICATION OF SIGNER’S CERTIFICATE VCI - VALIDATION CONTEXT INITIALIZATION XCV - X.509 CERTIFICATE VALIDATION CV - CRYPTOGRAPHIC VERIFICATION SAV - SIGNATURE ACCEPTANCE VALIDATION Each block contains a number of rules that are executed sequentially. The rules are driven by the constraints defined in the validation policy. The result of each rule is OK or NOT OK. The process is stopped when the first rule fails. Each block also contains a conclusion. If all rules are met then the conclusion node indicates VALID. Otherwise INVALID or INDETERMINATE indication is returned depending on the ETSI standard definition. 1.13.3 Diagnostic Data This is a data set constructed from the information contained in the signature itself, but also from information retrieved dynamically as revocation data and information extrapolated as the mathematical validity of a signature. All this information is independent of the applied validation policy. Two different validation policies applied to the same diagnostic data can lead to different results. This is an example of the diagnostic data for a XAdES signature. Certain fields and certain values were trimmed or deleted to make reading easier:
Date: 05/03/2015 41 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
Date: 05/03/2015 42 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
Date: 05/03/2015 43 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
1.14 Customised Validation Policy
The validation process may be driven by a set of constraints that are contained in the XML file constraint.xml.
Date: 05/03/2015 44 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
Here is the description of the most important fields: AcceptablePolicies It is possible to define the list of acceptable signature policies. [*] character can be used to indicate that any policy is acceptable. It is also possible to define an exhaustive list of acceptable policies:
It is possible to define a set of cryptographic constraints which can be applied on different cryptographic material. The following tag is used:
Each of these categories allows the definition of the following constraints:
To create the customised validation policy it is necessary to make a copy of the default validation policy file which can be found: /102853/policy/constraint.xml Then apply the changes you want and save it to the desired location.
Date: 05/03/2015 45 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
When invoking the validation process it is possible to indicate the validation policy to consider. Here is the java code example:
package eu.europa.ec.markt.dss.cookbook.example.validate;
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.cookbook.sources.AlwaysValidOCSPSource; import eu.europa.ec.markt.dss.cookbook.mock.MockServiceInfo; import eu.europa.ec.markt.dss.cookbook.mock.MockTSLCertificateSource; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.FileDocument; import eu.europa.ec.markt.dss.validation102853.CertificateToken; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier; import eu.europa.ec.markt.dss.validation102853.SignedDocumentValidator; import eu.europa.ec.markt.dss.validation102853.condition.ServiceInfo; import eu.europa.ec.markt.dss.validation102853.report.DetailedReport; import eu.europa.ec.markt.dss.validation102853.report.Reports; import eu.europa.ec.markt.dss.validation102853.report.SimpleReport;
/** * How to validate a signature with a custom validation policy. */ public class ValidateSignedXmlXadesBWithCustomPolicy extends Cookbook {
public static void main(String[] args) throws IOException {
// To be able to validate our fake signature, we must define one of the certificates // in the chain as trusted anchor. // If you have a real signature for which it is possible to build the chain till the // TSL then just skip this point. preparePKCS12TokenAndKey(); final CertificateToken[] certificateChain = privateKey.getCertificateChain(); final CertificateToken trustedCertificate = certificateChain[0];
DSSDocument document = new FileDocument("signedXmlXadesB.xml");
SignedDocumentValidator validator = SignedDocumentValidator.fromDocument(document);
CommonCertificateVerifier verifier = new CommonCertificateVerifier();
AlwaysValidOCSPSource ocspSource = new AlwaysValidOCSPSource(); verifier.setOcspSource(ocspSource);
MockTSLCertificateSource trustedCertSource = new MockTSLCertificateSource(); ServiceInfo mockServiceInfo = new MockServiceInfo(); trustedCertSource.addCertificate(trustedCertificate, mockServiceInfo);
verifier.setTrustedCertSource(trustedCertSource); validator.setCertificateVerifier(verifier);
Reports reports = validator.validateDocument(getPathFromResource("/constraints.xml")); SimpleReport simpleReport = reports.getSimpleReport(); DetailedReport detailedReport = reports.getDetailedReport();
InputStream is = new ByteArrayInputStream(simpleReport.toByteArray()); DSSUtils.saveToFile(is, "validationXmlXadesBWithCustomPolicy_simpleReport.xml"); is = new ByteArrayInputStream(detailedReport.toByteArray()); DSSUtils.saveToFile(is, "validationXmlXadesBWithCustomPolicy_detailReport.xml"); } }
Code 14: cookbook.example.validate.ValidateSignedXmlXadesBWithCustomPolicy.java
Date: 05/03/2015 46 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
1.15 Structural signature validation
In the case of XAdES signatures it possible to validate them against the associated schema. To do so the constraint in the validation policy (constraint.xml) must be set:
/ConstraintsParameters/MainSignature/StructuralValidation:
Date: 05/03/2015 47 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
6 CADES SIGNATURE AND VALIDATION
To familiarise yourself with this type of signature it is advisable to read the following document: CAdES Specifications (cf. [R05]) To implement this form of signature you can use the XAdES examples. You only need to instantiate the CAdES object service and change the SignatureLevel parameter value. Below is an example of the CAdES-T signature:
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.cades.CAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to sign with CAdES-BASELINE-B enveloping signature. */ public class SignXmlCadesB extends Cookbook {
public static void main(final String[] args) throws IOException {
// GET document to be signed - // Return DSSDocument toSignDocument prepareXmlDoc();
// Get a token connection based on a pkcs12 file commonly used to store private // keys with accompanying public key certificates, protected with a password-based // symmetric key - // Return AbstractSignatureTokenConnection signingToken
// and it's first private key entry from the PKCS12 store // Return DSSPrivateKeyEntry privateKey ***** preparePKCS12TokenAndKey();
// Preparing parameters for the CAdES signature SignatureParameters parameters = new SignatureParameters(); // We choose the level of the signature (-B, -T, -LT, -LTA). parameters.setSignatureLevel(SignatureLevel.CAdES_BASELINE_B); // We choose the type of the signature packaging (ENVELOPING, DETACHED). parameters.setSignaturePackaging(SignaturePackaging.ENVELOPING); // We set the digest algorithm to use with the signature algorithm. You must use the // same parameter when you invoke the method sign on the token. The default value is // SHA256 parameters. setDigestAlgorithm (DigestAlgorithm. SHA256 ); // We choose the private key with the certificate and corresponding certificate // chain. parameters.setPrivateKeyEntry(privateKey); // Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create CAdES xadesService for signature CAdESService service = new CAdESService(commonCertificateVerifier);
// Get the SignedInfo segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm DigestAlgorithm digestAlgorithm = parameters. getDigestAlgorithm ();
Date: 05/03/2015 48 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
byte[] signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);
// We invoke the xadesService to sign the document with the signature value obtained // in the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue); //signedDocument.save("c:/xml_example-cades-enveloping-b-signed.xml"); DSSUtils.saveToFile(signedDocument.openStream(), "signedXmlCadesBEnvelopping"); } }
Code 15: cookbook.example.sign.SignXmlCadesB.java
For the extension and validation of the signature of the form CAdES respectively follow the examples in the following chapters: The XML Signature Extension (XAdES)
Date: 05/03/2015 49 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
7 PADES SIGNATURE AND VALIDATION
The standard ISO 32000-1 (cf. [R10]) allows defining a file format for portable electronic documents. It is based on PDF 1.7 of Adobe Systems. Concerning the digital signature it supports three operations: Adding a digital signature to a document, Providing a placeholder field for signatures, Checking signatures for validity. PAdES defines eight different profiles to be used with advanced electronic signature in the meaning of European Union Directive 1999/93/EC (cf. [R13]): PAdES Basic - PDF signature as specified in ISO 32000-1 (cf. [R10]). The profile is specified in TS 102 778-2 (cf. [R06]). PAdES-BES Profile - based upon CAdES-BES as specified in TS 101 733 (cf. [R05]) with the option of a signature time-stamp (CAdES-T). PAdES-EPES profile - based upon CAdES-EPES as specified in TS 101 733 (cf. [R05]). This profile is the same as the PAdES - BES with the addition of a signature policy identifier and optionally a commitment type indication. PAdES-LTV Profile - This profile supports the long term validation of PDF Signatures and can be used in conjunction with the above-mentioned profiles. Four other PAdES profiles for XML Content. To familiarise yourself with this type of signature it is advisable to read the documents referenced above. Below is an example of code to perform a PADES-BASELINE-B type signature:
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.pades.PAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to sign PDF Document with PAdES-BASELINE-B */ public class SignPdfPadesB extends Cookbook {
public static void main(final String[] args) throws IOException { // GET document to be signed - // Return DSSDocument toSignDocument preparePdfDoc();
// Get a token connection based on a pkcs12 file commonly used to store private // keys with accompanying public key certificates, protected with a password-based // symmetric key - // Return AbstractSignatureTokenConnection signingToken
// and it's first private key entry from the PKCS12 store // Return DSSPrivateKeyEntry privateKey ***** preparePKCS12TokenAndKey();
Date: 05/03/2015 50 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
// Preparing parameters for the PAdES signature SignatureParameters parameters = new SignatureParameters(); // We choose the level of the signature (-B, -T, -LT, -LTA). parameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B); // We choose the type of the signature packaging (ENVELOPING, DETACHED). parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); // We set the digest algorithm to use with the signature algorithm. You must use the // same parameter when you invoke the method sign on the token. The default value is // SHA256 parameters. setDigestAlgorithm (DigestAlgorithm. SHA256 ); // We choose the private key with the certificate and corresponding certificate // chain. parameters.setPrivateKeyEntry(privateKey);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create PAdES padesService for signature PAdESService service = new PAdESService(commonCertificateVerifier);
// Get the SignedInfo segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm DigestAlgorithm digestAlgorithm = parameters. getDigestAlgorithm (); byte[] signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);
// We invoke the xadesService to sign the document with the signature value obtained // in the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
//We use the DSSUtils to Save to file DSSUtils.saveToFile(signedDocument.openStream(), "signedPdfPadesB.pdf");
} }
Code 16: cookbook.example.sign.SignPdfPadesB.java To add the timestamp to the signature (PAdES-T or LTA), please provide TSP source to the service. To create PAdES-BASELINE-B level with additional options: signature policy identifier and optionally a commitment type indication, please observe the following example in code 5. All these parameters are optional. SignaturePolicyOID: The string representation of the OID of the signature policy to use when signing. SignaturePolicyHashValue: The value of the hash of the signature policy, computed the same way as in clause 5.8.1 of CAdES (TS 101 733 (cf. [R05])). SignaturePolicyHashAlgorithm: The hash function used to compute the value of the SignaturePolicyHashValue entry. Entries must be represented the same way as in table 257 of ISO 32000-1 (cf. [R10]). SignaturePolicyCommitmentType: If the SignaturePolicyOID is present, this array defines the commitment types that can be used within the signature policy. An empty string can be used to indicate the default commitment type. If the SignaturePolicyOID is absent, the three other fields defined above will be ignored. If the SignaturePolicyOID is present but the SignaturePolicyCommitmentType is absent, all commitments defined by the signature policy will be used.
Date: 05/03/2015 51 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
The extension of a signature of the level PAdES-BASELINE-B up to PAdES-BASELINE-LTA profile will add the following features: Addition of validation data to an existing PDF document which may be used to validate earlier signatures within the document (including PDF signatures and time-stamp signatures). Addition of a document time-stamp which protects the existing document and any validation data. Further validation data and document time-stamp may be added to a document over time to maintain its authenticity and integrity. To implement the validation of a signature on a PDF document please refer to the chapter: ”
1.16 PAdES Visible Signature
The framework also allows to create PDF files with visible signature as specified in TS 102 778-6 (cf. [R06]). In the SignatureParameters object, there’s a special attribute named ImageParameters. This parameter let you custom the visual signature (with text, with image or with image and text). Below is an example of code to perform a PADES-BASELINE-B type signature with a visible signature:
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.awt.Color; import java.awt.Font; import java.io.IOException;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.parameter.SignatureImageParameters; import eu.europa.ec.markt.dss.parameter.SignatureImageTextParameters; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.pades.PAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to sign PDF Document with PAdES-BASELINE-B and include a visual representation */ public class SignPdfPadesBVisible extends Cookbook {
public static void main(final String[] args) throws IOException { // GET document to be signed - // Return DSSDocument toSignDocument preparePdfDoc();
// Get a token connection based on a pkcs12 file commonly used to store private // keys with accompanying public key certificates, protected with a password-based // symmetric key - // Return AbstractSignatureTokenConnection signingToken
// and it's first private key entry from the PKCS12 store // Return DSSPrivateKeyEntry privateKey ***** preparePKCS12TokenAndKey();
// Preparing parameters for the PAdES signature SignatureParameters parameters = new SignatureParameters(); // We choose the level of the signature (-B, -T, -LT, -LTA). parameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B); // We choose the type of the signature packaging (ENVELOPING, DETACHED). parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED);
// Initialize visual signature SignatureImageParameters imageParameters = new SignatureImageParameters(); // the origin is the left and top corner of the page imageParameters.setxAxis(200);
Date: 05/03/2015 52 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
imageParameters.setyAxis(500);
// Initialize text to generate for visual signature SignatureImageTextParameters textParameters = new SignatureImageTextParameters(); textParameters.setFont(new Font("serif", Font.PLAIN, 14)); textParameters.setTextColor(Color.BLUE); textParameters.setText("My visual signature"); imageParameters.setTextParameters(textParameters);
parameters.setImageParameters(imageParameters);
// We choose the private key with the certificate and corresponding certificate // chain. parameters.setPrivateKeyEntry(privateKey);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create PAdESService for signature PAdESService service = new PAdESService(commonCertificateVerifier);
// Get the SignedInfo segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm DigestAlgorithm digestAlgorithm = parameters. getDigestAlgorithm (); byte[] signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);
// We invoke the xadesService to sign the document with the signature value obtained // in the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
// We use the DSSUtils to Save to file DSSUtils.saveToFile(signedDocument.openStream(), "target/signedPdfPadesBVisible.pdf");
} }
Code 17: cookbook.example.sign. SignPdfPadesBVisible.java
Date: 05/03/2015 53 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
8 ASIC SIGNATURE AND VALIDATION
When creating a digital signature, the user must choose between different packaging elements, namely enveloping, enveloped or detached. This choice is not obvious, because in one case the signature will alter the signed document and in the other case it is possible to lose the association between the signed document and its signature. That's where the standard ETSI TS 102 918 (cf. [R12]) offers a standardized use of container forms to establish a common way for associating data objects with advanced signatures or time-stamp tokens. A number of application environments use ZIP based container formats to package sets of files together with meta-information. ASiC technical specification is designed to operate with a range of such ZIP based application environments. Rather than enforcing a single packaging structure, ASiC describes how these package formats can be used to associate advanced electronic signatures with any data objects. The standard defines two types of containers; the first (ASiC-S) allows you to associate one or more signatures with a single data element. In this case the structure of the signature can be based (in a general way) on a single CAdES signature or on multiple XAdES signatures or finally on a single TST; the second is an extended container (ASiC-E) that includes multiple data objects. Each data object may be signed by one or more signatures which structure is similar to ASiC-S. This second type of container is compatible with OCF, UCF and ODF formats. For the moment the DSS framework uses only ASIC-S based on XAdES signature type of containers. This is an example of the source code for signing a document using ASiCS-S based on XAdES-BES:
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.asic.ASiCService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to sign with ASiC-BASELINE-B */ public class SignPdfAsicB extends Cookbook {
public static void main(final String[] args) throws IOException {
// GET document to be signed - // Return DSSDocument toSignDocument preparePdfDoc();
// Get a token connection based on a pkcs12 file commonly used to store private // keys with accompanying public key certificates, protected with a password-based // symmetric key - // Return AbstractSignatureTokenConnection signingToken
// and it's first private key entry from the PKCS12 store // Return DSSPrivateKeyEntry privateKey ***** preparePKCS12TokenAndKey();
// Preparing parameters for the AsicS signature SignatureParameters parameters = new SignatureParameters(); // We choose the level of the signature (-B, -T, -LT). parameters.setSignatureLevel(SignatureLevel.ASiC_S_BASELINE_B); // We set the digest algorithm to use with the signature algorithm. You must use the // same parameter when you invoke the method sign on the token. The default value is // SHA256
Date: 05/03/2015 54 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
parameters. setDigestAlgorithm (DigestAlgorithm. SHA256 ); // We choose the private key with the certificate and corresponding certificate // chain. parameters.setPrivateKeyEntry(privateKey);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create ASiCS service for signature ASiCService service = new ASiCService(commonCertificateVerifier);
// Get the SignedInfo segment that need to be signed. byte[] dataToSign = service.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm DigestAlgorithm digestAlgorithm = parameters. getDigestAlgorithm (); byte[] signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);
// We invoke the xadesService to sign the document with the signature value obtained // in the previous step. DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue); //DSSUtils.copy(signedDocument.openStream(), System.out); DSSUtils.saveToFile(signedDocument.openStream(), "signedPdfAsicB.asic"); } }
Code 18: cookbook.example.sign.SignPdfAsicB.java Please note that you need to pass only few parameters to the service. Other parameters, although are positioned, will be overwritten by the internal implementation of the service. Therefore, the obtained signature is always based on XAdES and of DETACHED packaging. It is also possible with the framework DSS to make an extension of an ASICS signature to the level XAdES- BASELINE-T or –LT. To implement the validation of a signature on a PDF document please refer to the “” chapter.
Date: 05/03/2015 55 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
9 MANAGEMENT OF SIGNATURE TOKENS
The DSS framework is able to create signatures from PKCS#11, PKCS#12 and MS CAPI. Java 6 is inherently capable of communicating with these kinds of KeyStores. To be independent of the signing media, DSS framework uses an interface named SignatureTokenConnection to manage different implementations of the signing process. The base implementation is able to sign a stream of the data in one step. That means that all the data to be signed needs to be sent to the SSCD. This is the case for MS CAPI. As to the PKCS#11 and PKCS#12, which give to the developer a finer control in the signature operation, the DSS framework implements the AsyncSignatureTokenConnection abstract class that permits to execute the digest operation and signature operation in two different threads or even two different hardwares. This design permits also other card providers/adopters to create own implementations. For example, this can be used for a direct connection to the Smartcard through Java 6 PC/SC.
1.17 PKCS#11
PKCS#11 is widely used to access smart cards and HSMs. Most commercial software uses PKCS#11 to access the signature key of the CA or to enrol user certificates. In the SD-DSS framework, this standard is encapsulated in the class Pkcs11SignatureToken. It exposes the following methods:
Figure 2: Pkcs11SignatureToken interface The method getKeys retrieves all the available keys (private keys entries) from the SSCD. The method sign signs the stream with the private key and the chosen algorithm. The method close closes the connection to the SSCD.
Date: 05/03/2015 56 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
1.18 PKCS#12
This standard defines a file format commonly used to store the private key and corresponding public key certificate protecting them by password. It brings together: Pair of public / private key; X.509 public key certificate; X.509 signing certificate; Chain of certificates to the ROOT certificate (may not be present). In order to use this format with the DSS framework you have to go through the class Pkcs12SignatureToken. It provides four public methods and proposes some different constructors:
Figure 3: Pkcs12SignatureToken interface The method getKeys retrieves all the available keys (private keys entries) from the PKCS#12 keystore. The method sign signs the stream with the private key and the chosen algorithm. The method close does nothing.
Date: 05/03/2015 57 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
1.19 MS CAPI
If the middleware for communicating with an SSDC provides a CSP based on MS CAPI specification, then to sign the documents you can use MSCAPISignatureToken class. It provides three public methods:
Figure 4: MSCAPISignatureToken interface The method getKeys retrieves all the available keys (private keys entries) from the SSCD. The method sign signs the stream with the private key and the chosen algorithm. The method close closes the connection to the SSCD. Below is an example of using MS CAPI to sign a document:
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException; import java.util.List;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.token.DSSPrivateKeyEntry; import eu.europa.ec.markt.dss.signature.token.MSCAPISignatureToken; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
/** * How to sign using MS-CAPI. */ public class SignXmlXadesBWithMSCAPI extends Cookbook {
public static void main(String[] args) throws DSSException, IOException { // GET document to be signed - // Return DSSDocument toSignDocument prepareXmlDoc();
Date: 05/03/2015 58 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
// Creation of MS-CAPI signature token signingToken = new MSCAPISignatureToken(); List
// Preparing parameters for the PAdES signature SignatureParameters parameters = new SignatureParameters(); // We choose the level of the signature (-B, -T, -LT, -LTA). parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B); // We choose the type of the signature packaging (ENVELOPING, DETACHED). parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED); // We set the digest algorithm to use with the signature algorithm. You must use the // same parameter when you invoke the method sign on the token. parameters. setDigestAlgorithm (DigestAlgorithm. SHA1 ); // We choose the private key with the certificate and corresponding certificate // chain. parameters.setPrivateKeyEntry(privateKey);
// Create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); // Create XAdES xadesService for signature XAdESService xadesService = new XAdESService(commonCertificateVerifier);
// Get the SignedInfo segment that need to be signed. byte[] dataToSign = xadesService.getDataToSign(toSignDocument, parameters);
// This function obtains the signature value for signed information using the // private key and specified algorithm DigestAlgorithm digestAlgorithm = parameters. getDigestAlgorithm (); byte[] signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);
// We invoke the xadesService to sign the document with the signature value obtained // in the previous step. DSSDocument signedDocument = xadesService.signDocument(toSignDocument, parameters, signatureValue);
//DSSUtils.copy(signedDocument.openStream(), System.out); DSSUtils.saveToFile(signedDocument.openStream(), "signedXmlXadesMSCapi.xml"); } }
Code 19: cookbook.example.sign.SignXmlXadesBWithMSCAPI.java
1.20 Other Implementations
As you can see, it is easy to add another implementation of the SignatureTokenConnection, thus enabling the framework to use other API than the provided three (PKCS#11, PKCS#12 and MS CAPI). For example, it is likely that in the future PC/SC will be the preferred way of accessing a Smartcard. Although PKCS#11 is currently the most used API, DSS framework is extensible and can use PC/SC. For our design example we propose to use PC/SC to communicate with the Smartcard. A PC/SC implementation of the signature token should extend AsyncSignatureTokenConnection class.
Date: 05/03/2015 59 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
class Signature API
«interface» token::SignatureTokenConnection + close() : void + getKeys() : List
token::AsyncSignatureTokenConnection
+ encryptDigest(byte[], SignatureAlgorithm, DigestAlgorithm, PrivateKeyEntry) : byte[] + sign(InputStream , SignatureAlgorithm, DigestAlgorithm , PrivateKeyEntry) : byte[]
token::EidNativeSignatureTokenConnection
+ close() : void + encryptDigest(byte[], SignatureAlgorithm , DigestAlgorithm , PrivateKeyEntry) : byte[] + getKeys() : List
Figure 5: Implementation of SignatureTokenConnection for Java 6 IO PC/SC Sample source-code is provided for the Belgian eID smartcard. To handle the messages between the DSS framework and the layer managing eID over PC/SC (PcscEid class) we must implement an adapter: EidNativeSignatureTokenConnection. All the PC/SC aspects are handled by the maven module eid-applet- core. EidNativeSignatureTokenConnection.java
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger;
import javax.smartcardio.CardException;
import be.fedict.eid.applet.Messages; import be.fedict.eid.applet.sc.PcscEid; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.sources.AppletView; import eu.europa.ec.markt.dss.cookbook.sources.EidPrivateKeyEntry; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.signature.token.AbstractSignatureTokenConnection; import eu.europa.ec.markt.dss.signature.token.DSSPrivateKeyEntry; import eu.europa.ec.markt.dss.validation102853.CertificateToken;
public class EidNativeSignatureTokenConnection extends AbstractSignatureTokenConnection {
private PcscEid eid;
/** * The default constructor for EidNativeSignatureTokenConnection. */
Date: 05/03/2015 60 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
public EidNativeSignatureTokenConnection(AppletView view) { this.eid = new PcscEid(view, new Messages(Locale.ENGLISH)); }
@Override public void close() { eid.close(); }
@Override public List
List
Logger.getLogger(EidNativeSignatureTokenConnection.class.getName()).log(Level.SEVERE, null, ex); throw new DSSException(ex); } catch (IOException ex) {
Logger.getLogger(EidNativeSignatureTokenConnection.class.getName()).log(Level.SEVERE, null, ex); throw new DSSException(ex); } catch (CertificateException ex) {
Logger.getLogger(EidNativeSignatureTokenConnection.class.getName()).log(Level.SEVERE, null, ex); throw new DSSException(ex); } }
// @Override public byte[] encryptDigest(byte[] digestValue, DigestAlgorithm digestAlgo, DSSPrivateKeyEntry keyEntry) throws NoSuchAlgorithmException { try { eid.isEidPresent(); return eid.sign(digestValue, digestAlgo.getName()); } catch (CardException ex) {
Logger.getLogger(EidNativeSignatureTokenConnection.class.getName()).log(Level.SEVERE, null, ex); throw new RuntimeException(ex); } catch (IOException ex) {
Logger.getLogger(EidNativeSignatureTokenConnection.class.getName()).log(Level.SEVERE, null, ex); throw new RuntimeException(ex); } catch (InterruptedException ex) {
Logger.getLogger(EidNativeSignatureTokenConnection.class.getName()).log(Level.SEVERE, null, ex); throw new RuntimeException(ex); } }
}
Code 20: cookbook.example.sign.EidNativeSignatureTokenConnection.java EidPrivateKeyEntry.java
package eu.europa.ec.markt.dss.cookbook.sources;
import java.security.PrivateKey;
Date: 05/03/2015 61 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
import java.security.cert.X509Certificate; import java.util.List;
import eu.europa.ec.markt.dss.EncryptionAlgorithm; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.signature.token.DSSPrivateKeyEntry; import eu.europa.ec.markt.dss.validation102853.CertificateToken;
/** * Sample for eID * */ public class EidPrivateKeyEntry implements DSSPrivateKeyEntry {
private CertificateToken certificate;
private CertificateToken[] certificateChain;
public EidPrivateKeyEntry(CertificateToken certificate, List
@Override public CertificateToken getCertificate() {
return certificate; }
@Override public CertificateToken[] getCertificateChain() {
return certificateChain; }
@Override public EncryptionAlgorithm getEncryptionAlgorithm() throws DSSException { return null; }
@Override public PrivateKey getPrivateKey() { return null; } }
Code 21: cookbook.example.sources.EidPrivateKeyEntry.java AppletView.java
package eu.europa.ec.markt.dss.cookbook.sources;
import java.awt.Component;
import javax.swing.JApplet;
import be.fedict.eid.applet.DiagnosticTests; import be.fedict.eid.applet.Messages; import be.fedict.eid.applet.Status; import be.fedict.eid.applet.View;
public class AppletView implements View {
private JApplet applet;
/** * The default constructor for AppletView. */ public AppletView(JApplet applet) {
Date: 05/03/2015 62 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
this.applet = applet; }
@Override public void addDetailMessage(String detailMessage) { }
@Override public Component getParentComponent() {
return applet; }
@Override public boolean privacyQuestion(boolean includeAddress, boolean includePhoto, String identityDataUsage) {
return false; }
@Override public void setStatusMessage(Status status, Messages.MESSAGE_ID messageId) { }
@Override public void setProgressIndeterminate() { }
@Override public void resetProgress(int max) { }
@Override public void increaseProgress() { }
@Override public void addTestResult(DiagnosticTests arg0, boolean arg1, String arg2) { } }
Code 22: cookbook.example.sources.AppletView.java
Date: 05/03/2015 63 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
10 MANAGEMENT OF CERTIFICATES SOURCES
The validation of a certificate requires the access to some other certificates from multiple sources like trusted lists, trust store, the signature itself: certificates can be contained inside or any other source. Within the framework an X509 certificate is modelled through the class: eu.europa.ec.markt.dss.validation102853.CertificateToken This encapsulation helps make certificate handling more suited to the needs of the validation in the context of trust. Each certificate is unambiguously identified by its issuer DN and serial number. The framework associates a unique internal identifier to each certificate but this identifier is not calculated on the data contained in the certificate and therefore varies from one application to another. However, it is independent of its source. It allows to easily comparing certificates issued by different sources. Certificate tokens are grouped into pools. A certificate token can be declared in several pools. The class that models a pool is called: eu.europa.ec.markt.dss.validation102853.CertificatePool This class allows keeping only one occurrence of the certificate in the given context (i.e. validation). Two pools of certificates can be merged using the method: eu.europa.ec.markt.dss.validation102853.CertificatePool#merge The CertificateSource interface provides abstraction for accessing a certificate, regardless of the source. However, each source has its own type: eu.europa.ec.markt.dss.validation.certificate.CertificateSourceType This information is used, for example, to distinguish between the certificate from a trusted source and the others. A source has one and only one type, but a certificate token can be found in multiple sources. The DSS framework supplies some standard implementations, but also gives the possibility to implement owner solutions. Among the standard solutions you can find: eu.europa.ec.markt.dss.validation102853.CommonCertificateSource This is the superclass of almost of the certificate sources. It implements the common method CommonCertificateSource#get returns the list of CertificateToken(s) corresponding to the given subject distinguished name. Note that the content of the encapsulated certificates pool can be different from the content of the source. Only CertificateToken(s) present in the source are taken into account. It exposes also the method CommonCertificateSource#addCertificate which gives the possibility to add manually any X509Certificate as a part of this source and as a part of the encapsulated pool. If the certificate is already present in the pool its source type is associated to the token. eu.europa.ec.markt.dss.validation102853.SignatureCertificateSource Some certificate sources are based on data encapsulated within the signature. That means that the set of certificates is available and the software only needs to find the certificate using its subject name. This class adds also new methods to obtain specialized list of certificates contained in the source:. o SignatureCertificateSource#getKeyInfoCertificates o SignatureCertificateSource#getEncapsulatedCertificates eu.europa.ec.markt.dss.validation102853.tsl.TrustedListsCertificateSource Certificates coming from the list of Trusted Lists. This class gives the mechanism to define the set of trusted certificates (trust anchors). They are used in the validation process to decide if the prospective certificate chain has a trust anchor. See chapter 1.12 to know more about EU Trusted Lists.
Date: 05/03/2015 64 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
TrustedListsCertificateSource tslsource = new TrustedListsCertificateSource(); tslsource.setTslLoader(new CommonsHttpDataLoader()); // false It does not check the signature of the list, as this can be done once to increase performance. tslsource.setCheckSignature(false); tslsource.setLotlUrl("https://ec.europa.eu/information_society/policy/esignature/trusted-list/tl-mp.xml"); tslsource.init();
You can use this class as an example if you want to implement your own trusted certificates source. eu.europa.ec.markt.dss.validation102853.tsl.ReloadableTrustedListCertificateSource This CertificateSource reloads the list of trusted lists when the method refresh() is called. It can be used in the context of web app.
Figure 6: CertificateSource interface (not trusted part)
Figure 7: CertificateSource interface (trusted part)
Date: 05/03/2015 65 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
11 MANAGEMENT OF CRL AND OCSP SOURCES
A CRL is a time-stamped list identifying revoked certificates. It is signed by a Certificate Authority (CA) and made freely available in a public repository. Each revoked certificate is identified in a CRL by its certificate serial number. The Online Certificate Status Protocol (OCSP) is an Internet protocol used for obtaining the revocation status of an X.509 digital certificate. For every certificate, the validity has to be checked via CRL or OCSP responses. The information may originate from different CRLSources or OCSPSources: For easing the usage of such sources, DSS implements a CRLSource and OCSPSource interfaces, which offer a generic, uniform way of accessing CRL and OCSP sources. Furthermore, a caching mechanism can be easily attached to those sources, optimizing the access time to revocation information by reducing network connections to online servers. The interface CRLSource defines the method which returns X509CRL for the given certificate/issuer certificate couple:
X509CRL findCrl(X509Certificate certificate, X509Certificate issuerCertificate) throws DSSException;
The X509CRL abstract class represents an X.509 Certificate Revocation List (CRL). The interface OCSPSource defines the method which returns BasicOCSPResp for the given certificate/issuer certificate couple:
BasicOCSPResp getOCSPResponse(X509Certificate certificate, X509Certificate issuerCertificate) throws DSSException;
The BasicOCSPResp class represents an OCSP response (cf. [R08]). We use these classes during the certificate validation process through “validationContext” object (based on ValidationContext class) which is a "cache" for one validation request that contains every object retrieved so far. This object in turn instantiates a “verifier” based on CSPAndCRLCertificateVerifier class whose role is to fetch revocation data by querying an OCSP server first and then a CRL server if no OCSP response could be retrieved. In general we can distinguish three main sources: Offline sources; Online sources; Sources with the cache mechanism.
1.21 Other implementations of CRL and OCSP Sources
Such sources find the status of a certificate either from a list stored locally or using the information contained in the advanced signature or online way. Here is the list of sources already implemented in the DSS framework: CRL sources JdbcCacheCRLSource Retrieves information from a JDBC datasource OfflineCRLSource This class that implements in a generic way the findCrl method that operates on the different CRLs implemented in children calasses. o ListCRLSource
Date: 05/03/2015 66 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
This source maintains a list of X509CRL. o SignatureCRLSource The advanced signature contains a list of CRL that was needed to validate the signature. This class is a basic skeleton that is able to retrieve the needed CRL from a list. The child needs to retrieve the list of wrapped CRLs. . CAdESCRLSource Retrieves information from a CAdES signature. . PAdESCRLSource Retrieves information from a PAdES signature. . XAdESCRLSource Retrieves information from a XAdES signature. . MockCRLSource A class of test that can instantiate a list of certificate revocation lists from a directory where should be the individual lists (each individual list file must end with the extension “.crl”). OnlineCRLSource This is a representation of an Online CRL repository. This implementation will contact using HTTP protocol the CRL Responder to download the CRLs from the given URI. Note that certificate’s Authority Information Access (AIA) extension is used to find issuer's resources location like CRT file and/or Online Certificate Status Protocol (OCSP). The URIs of CRL server will be extracted from this property (OID value: 1.3.6.1.5.5.7.48.1.3). Here is the class diagram representing the hierarchy issued by CRLSource interface.
Figure 8: CRLSource interface OCSP sources o OfflineOCSPSource An abstract class that helps to implement OCSPSource with an already loaded list of BasicOCSPResp. It implements in a generic way the getOCSPResponse method that operates on the different OCSP implementations in children classes. . ListOCSPSource Implements an OCSPSource from a list of BasicOCSPResp. . SignatureOCSPSource
Date: 05/03/2015 67 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
The advanced signature contains a list of OCSPResp that was needed to validate the signature. This class is a basic skeleton that is able to retrieve the needed OCSPResp from a list. The children need to retrieve the list of wrapped OCSPResp. CAdESOCSPSource Retrieves information from a CAdES signature. PAdESOCSPSource Retrieves information from a PAdES signature. XAdESOCSPSource Retrieves information from a XAdES signature. MockOCSPSource A class of test that can instantiate a list of OCSPResp from a directory where should be the individual DER Encoded X509 certificates files (each individual file must end with the extension “.der”). o OnlineOCSPSource This is a representation of an Online OCSP repository. This implementation will contact using HTTP protocol the OCSP Responder to retrieve the OCSP response. Note that certificate’s Authority Information Access (AIA) extension is used to find issuer's resources location like CRT file and/or Online Certificate Status Protocol (OCSP). The URIs of OCSP server will be extracted from this property (OID value: 1.3.6.1.5.5.7.48.1).
Figure 9: OCSPSource interface
Date: 05/03/2015 68 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
12 TSP SOURCES
The Time Stamp Authority by creating time-stamp tokens provides independent and irrefutable proof of time for business transactions, e-documents and digital signatures. The TSA must comply with the IETF RFC 3161 specifications (cf. [R14]). A time-stamp is obtained by sending the digest value of the given data and digest algorithm to the Time Stamp Authority. The returned time-stamp is a signed data that contains the digest value, the identity of the TSA, and the time of stamping. This proves that the given data existed before the time of stamping. The DSS framework proposes TSPSource interface to implement the communication with TSA. The class OnlineTSPSource is the default implementation of TSP using HTTP(S) communication layer. The following bit of Java code illustrates how you might use this class:
package eu.europa.ec.markt.dss.cookbook.sources;
import java.io.IOException;
import org.bouncycastle.tsp.TimeStampToken;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.validation102853.tsp.OnlineTSPSource; import eu.europa.ec.markt.dss.validation102853.tsp.TSPSource;
/** * How to initialize online TSP source. */ public class InitOnlineTSPSource extends Cookbook {
public static void main(String[] args) throws IOException {
final String tspServer = "http://services.globaltrustfinder.com/adss/tsa"; TSPSource tspSource = new OnlineTSPSource(tspServer); tspSource.setPolicyOid("1.2.3.4.5");
final DigestAlgorithm digestAlgorithm = DigestAlgorithm.SHA256; final byte[] toDigest = "digest value".getBytes(); final byte[] digestValue = DSSUtils.digest(digestAlgorithm, toDigest); final TimeStampToken tsr = tspSource.getTimeStampResponse(digestAlgorithm, digestValue);
System.out.println(DSSUtils.toHex(tsr.getEncoded())); } }
Code 23: cookbook.example.sources.InitOnlineTSPSource.java
Time-stamp policy: A time-stamp policy is a "named set of rules that indicates the applicability of a time-stamp token to a particular community and/or class of application with common security requirements". A TSA may define its own policy which enhances the policy defined in RFC 3628. Such a policy shall incorporate or further constrain the requirements identified in RFC 3628. A time-stamp policy may be defined by the user of times- stamp services.
Date: 05/03/2015 69 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
13 WEB SERVICES
The version 4 of the SD-DSS framework covers the full JAVA API concerning signing and validating. The following webservices are provided:
1.22 Available SOAP services:
SignatureService Endpoint address: http://localhost:8080/dss-webapp/wservice/signatureService signDocument extendSignature WSDL : {http://impl.ws.dss.markt.ec.europa.eu/}SignatureService
getDataToSign Target namespace: http://impl.ws.dss.markt.ec.europa.eu/
ValidationService Endpoint address: http://localhost:8080/dss-webapp/wservice/validationService validateDocument WSDL : {http://impl.ws.dss.markt.ec.europa.eu/}ValidationService
Target namespace: http://impl.ws.dss.markt.ec.europa.eu/
1.23 SignatureService
This is the signature service WSDL with the three methods:
Date: 05/03/2015 70 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
Here below the example of use of this service with generated in Java client:
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.File; import java.util.Date; import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import eu.europa.ec.markt.dss.DSSXMLUtils; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.parameter.ChainCertificate; import eu.europa.ec.markt.dss.parameter.DSSReference; import eu.europa.ec.markt.dss.parameter.DSSTransform; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.FileDocument; import eu.europa.ec.markt.dss.signature.InMemoryDocument; import eu.europa.ec.markt.dss.signature.MimeType; import eu.europa.ec.markt.dss.signature.token.DSSPrivateKeyEntry; import eu.europa.ec.markt.dss.signature.token.SignatureTokenConnection; import eu.europa.ec.markt.dss.ws.signature.DSSException_Exception; import eu.europa.ec.markt.dss.ws.signature.DigestAlgorithm; import eu.europa.ec.markt.dss.ws.signature.DssTransform; import eu.europa.ec.markt.dss.ws.signature.EncryptionAlgorithm; import eu.europa.ec.markt.dss.ws.signature.ObjectFactory; import eu.europa.ec.markt.dss.ws.signature.SignatureLevel; import eu.europa.ec.markt.dss.ws.signature.SignaturePackaging;
Date: 05/03/2015 71 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
import eu.europa.ec.markt.dss.ws.signature.SignatureService; import eu.europa.ec.markt.dss.ws.signature.SignatureService_Service; import eu.europa.ec.markt.dss.ws.signature.WsChainCertificate; import eu.europa.ec.markt.dss.ws.signature.WsDocument; import eu.europa.ec.markt.dss.ws.signature.WsParameters; import eu.europa.ec.markt.dss.ws.signature.WsdssReference;
public class SignWithWS {
private static ObjectFactory FACTORY;
static {
System.setProperty("javax.xml.bind.JAXBContext", "com.sun.xml.internal.bind.v2.ContextFactory"); FACTORY = new ObjectFactory(); }
public static DSSDocument signDocument(final String serviceURL, final File file, final SignatureParameters parameters) throws DSSException {
try {
final WsDocument wsDocument = toWsDocument(file);
final WsParameters wsParameters = new WsParameters();
prepareKeyParameters(parameters, wsParameters);
prepareCertificateChain(parameters, wsParameters);
prepareReferences(parameters, wsParameters); wsParameters.setDeterministicId(parameters.getDeterministicId());
SignatureService_Service.setROOT_SERVICE_URL(serviceURL); final SignatureService_Service signatureService_service = new SignatureService_Service(); final SignatureService signatureServiceImplPort = signatureService_service.getSignatureServiceImplPort();
final byte[] toBeSignedBytes = signatureServiceImplPort.getDataToSign(wsDocument, wsParameters);
final DSSPrivateKeyEntry privateKey = parameters. getPrivateKeyEntry (); final SignatureTokenConnection tokenConnection = parameters. getSigningToken (); final byte[] encrypted = tokenConnection.sign(toBeSignedBytes, parameters. getDigestAlgorithm (), privateKey);
final WsDocument wsSignedDocument = signatureServiceImplPort.signDocument(wsDocument, wsParameters, encrypted);
final InMemoryDocument inMemoryDocument = toInMemoryDocument(wsSignedDocument); return inMemoryDocument; } catch (DSSException_Exception e) { throw new DSSException(e); } catch (Throwable e) { e.printStackTrace(); throw new DSSException(e); } }
private static void prepareCertificateChain(SignatureParameters parameters, WsParameters wsParameters) {
final List
final List
Date: 05/03/2015 72 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
WsChainCertificate wsChainCertificate = new WsChainCertificate();
wsChainCertificate.setX509Certificate(chainCertificate.getX509Certificate().getEncoded());
wsChainCertificate.setSignedAttribute(chainCertificate.isSignedAttribute()); wsChainCertificateList.add(wsChainCertificate); } } }
private static void prepareKeyParameters(SignatureParameters parameters, WsParameters wsParameters) {
final String signatureLevelString = parameters.getSignatureLevel().name(); final SignatureLevel signatureLevel = SignatureLevel.fromValue(signatureLevelString); wsParameters.setSignatureLevel(signatureLevel);
final String signaturePackagingString = parameters.getSignaturePackaging().name(); final SignaturePackaging signaturePackaging = SignaturePackaging.valueOf(signaturePackagingString); wsParameters.setSignaturePackaging(signaturePackaging);
final String encryptionAlgorithmString = parameters. getEncryptionAlgorithm ().name(); final EncryptionAlgorithm encryptionAlgorithm = EncryptionAlgorithm.fromValue(encryptionAlgorithmString); wsParameters.setEncryptionAlgorithm(encryptionAlgorithm);
final String digestAlgorithmString = parameters. getDigestAlgorithm ().name(); final DigestAlgorithm digestAlgorithm = DigestAlgorithm.fromValue(digestAlgorithmString); wsParameters.setDigestAlgorithm(digestAlgorithm);
final XMLGregorianCalendar xmlGregorianCalendar = DSSXMLUtils.createXMLGregorianCalendar(new Date()); wsParameters.setSigningDate(xmlGregorianCalendar); final byte[] encoded = parameters.getSigningCertificate().getEncoded(); wsParameters.setSigningCertificateBytes(encoded); }
private static void prepareReferences(final SignatureParameters parameters, final WsParameters wsParameters) {
final List
final WsdssReference wsDssReference = FACTORY.createWsdssReference(); wsDssReference.setId(dssReference.getId()); wsDssReference.setType(dssReference.getType()); wsDssReference.setUri(dssReference.getUri()); final String name = dssReference.getDigestMethodAlgorithm().getName(); final DigestAlgorithm value = DigestAlgorithm.fromValue(name); wsDssReference.setDigestMethodAlgorithm(value);
final List
for (DSSTransform dssTransform : dssTransforms) {
final DssTransform wsDssTransform = FACTORY.createDssTransform(); wsDssTransform.setElementName(dssTransform.getElementName()); wsDssTransform.setTextContent(dssTransform.getTextContent()); wsDssTransform.setNamespace(dssTransform.getNamespace()); wsDssTransform.setAlgorithm(dssTransform.getAlgorithm()); final List
Date: 05/03/2015 73 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
} } wsDssReferences.add(wsDssReference); } }
public static WsDocument toWsDocument(final File file) {
final DSSDocument dssDocument = new FileDocument(file); final WsDocument wsDocument = new WsDocument(); wsDocument.setBytes(dssDocument.getBytes()); wsDocument.setName(dssDocument.getName()); wsDocument.setAbsolutePath(dssDocument.getAbsolutePath()); final MimeType mimeType = dssDocument.getMimeType(); final eu.europa.ec.markt.dss.ws.signature.MimeType wsMimeType = FACTORY.createMimeType(); final String mimeTypeString = mimeType.getMimeTypeString(); wsMimeType.setMimeTypeString(mimeTypeString); wsDocument.setMimeType(wsMimeType); return wsDocument; }
public static InMemoryDocument toInMemoryDocument(final WsDocument wsSignedDocument) {
final InMemoryDocument inMemoryDocument = new InMemoryDocument(wsSignedDocument.getBytes()); inMemoryDocument.setName(wsSignedDocument.getName()); inMemoryDocument.setAbsolutePath(wsSignedDocument.getAbsolutePath()); final eu.europa.ec.markt.dss.ws.signature.MimeType wsMimeType = wsSignedDocument.getMimeType(); final MimeType mimeType = MimeType.fromMimeTypeString(wsMimeType.getMimeTypeString()); inMemoryDocument.setMimeType(mimeType); return inMemoryDocument; }
}
Code 24: cookbook.example.sign.SignWithWS.java You can notice that the signature process is used in the exactly same way as when using the pure JAVA API.
1.24 ValidationService
This is the validation service WSDL with the main method:
Date: 05/03/2015 74 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
Date: 05/03/2015 75 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
14 HOW TO CHECK A SIMPLE CERTIFICATE
Here is an example that shows how to verify a simple certificate. The certificate must meet the following conditions to be valid: The reference date related to the validation (signing time or current time if the first one is not defined) must be in the validity range of the signing certificate, The certificate chain must be traceable up to the trust anchor, The signature of the certificate must be mathematically correct, The certificate must not be revoked. package eu.europa.ec.markt.dss.cookbook.sources; import java.util.Set; import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.cookbook.example.Cookbook; import eu.europa.ec.markt.dss.cookbook.mock.MockCRLSource; import eu.europa.ec.markt.dss.cookbook.mock.MockEmptyTSLCertificateSource; import eu.europa.ec.markt.dss.cookbook.mock.MockOCSPSource; import eu.europa.ec.markt.dss.validation102853.CertificatePool; import eu.europa.ec.markt.dss.validation102853.CertificateToken; import eu.europa.ec.markt.dss.validation102853.CertificateVerifier; import eu.europa.ec.markt.dss.validation102853.CommonCertificateSource; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier; import eu.europa.ec.markt.dss.validation102853.CommonTrustedCertificateSource; import eu.europa.ec.markt.dss.validation102853.RevocationToken; import eu.europa.ec.markt.dss.validation102853.SignatureValidationContext; import eu.europa.ec.markt.dss.validation102853.crl.OnlineCRLSource; import eu.europa.ec.markt.dss.validation102853.ocsp.OnlineOCSPSource;
/** * How to check a certificate */ public class CheckCertificate extends Cookbook {
public static void main(String[] args) {
checkMockCertificate();
checkRealCertificate(); }
private static void checkRealCertificate() {
CertificateToken toValidateX509Certificate = DSSUtils.loadCertificate("/toValidate.crt");
CertificateToken issuerCert = DSSUtils.loadCertificate("/trusted.crt"); CommonTrustedCertificateSource trustedCertificateSource = new CommonTrustedCertificateSource(); trustedCertificateSource.addCertificate(issuerCert);
CommonCertificateSource adjunctCertificateSource = new CommonCertificateSource(); CertificateToken intermediateCert = DSSUtils.loadCertificate("/intermediate.cer"); adjunctCertificateSource.addCertificate(intermediateCert); CertificateToken toValidateCertificateToken = adjunctCertificateSource.addCertificate(toValidateX509Certificate);
CertificateVerifier certificateVerifier = new CommonCertificateVerifier(); certificateVerifier.setTrustedCertSource(trustedCertificateSource); certificateVerifier.setAdjunctCertSource(adjunctCertificateSource); OnlineCRLSource crlSource = new OnlineCRLSource(); certificateVerifier.setCrlSource(crlSource); certificateVerifier.setOcspSource(new OnlineOCSPSource());
Date: 05/03/2015 76 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
final CertificatePool validationPool = certificateVerifier.createValidationPool(); SignatureValidationContext validationContext = new SignatureValidationContext(validationPool); validationContext.addCertificateTokenForVerification(toValidateCertificateToken); validationContext.validate();
System.out.println(toValidateCertificateToken);
toValidateCertificateToken.isRevoked(); final RevocationToken revocationToken = toValidateCertificateToken.getRevocationToken(); /// ...
Set
System.out.println(certToken); } }
public static void checkMockCertificate() {
final CertificateToken issuerCert = DSSUtils.loadCertificate("/belgiumrs2.crt"); MockEmptyTSLCertificateSource trustedCertificateSource = new MockEmptyTSLCertificateSource(); trustedCertificateSource.addCertificate(issuerCert);
CommonCertificateSource adjunctCertificateSource = new CommonCertificateSource(); final CertificateToken endUserCert = DSSUtils.loadCertificate("/citizen_ca.cer"); final CertificateToken endUserCertToken = adjunctCertificateSource.addCertificate(endUserCert);
final CertificateVerifier certificateVerifier = new CommonCertificateVerifier(); certificateVerifier.setTrustedCertSource(trustedCertificateSource); certificateVerifier.setAdjunctCertSource(adjunctCertificateSource); certificateVerifier.setCrlSource(new MockCRLSource("/revocation/belgium2.crl")); certificateVerifier.setOcspSource(new MockOCSPSource("/ocsp/1302521088270.der"));
final CertificatePool validationPool = certificateVerifier.createValidationPool(); final SignatureValidationContext validationContext = new SignatureValidationContext(validationPool); validationContext.addCertificateTokenForVerification(endUserCertToken); validationContext.validate();
System.out.println(endUserCertToken);
endUserCertToken.isRevoked();
final Set
System.out.println(certToken); } } }
Code 25: cookbook.example.sources.CheckCertificate.java After the execution of the validation process, the certificate token is enriched with information about its validity. You can simply print the certificate token on the console to visually monitor. There are also getters to perform automated check. See the java doc for more details. That's part of the result for the certificate to be verified:
CertificateToken[ [2]<--[1], source=OTHER, serial=155740314092809718017649570364321128026 Validity period : 2009-10-28T12:00:00Z - 2016-06-28T13:00:00Z Is expired : false Signature algorithm: SHA1WithRSAEncryption Signature validity : VALID Revocation data[ Status: true / Thu Jul 11 13:00:00 CEST 2013 / issuer's certificate [1] ] Issuer certificate[
Date: 05/03/2015 77 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
CertificateToken[ [1]<--CN=GlobalSign Root CA,… serial=4835703278459708194794110 Validity period : 2007-10-04T14:00:00Z - 2014-01-27T00:00:00Z Is expired : false Signature algorithm: SHA1WithRSAEncryption Signature validity : Signature verification is not needed: trusted certificate Verification of revocation data is not necessary: trusted certificate. ] ] ]
Date: 05/03/2015 78 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
15 VALIDATION OF NON ADES SIGNATURES
Henceforth the framework is able to validate a digital signature that is not an Advanced Electronic Signature. To do this, simply set an adequate validation policy.
Code 26: Constraint file for non AdES signature validation And use the following validation Java code:
final DSSDocument toBeValidated = new FileDocument("src/test/resources/signature.xml"); final SignedDocumentValidator validator = SignedDocumentValidator.fromDocument(toBeValidated); final CertificateVerifier certificateVerifier = new CommonCertificateVerifier(); validator.setCertificateVerifier(certificateVerifier); validator.validateDocument("/102853/policy/constraint-core-validation.xml"); validator.printReports();
Code 27: Example of the Java code to validate non AdES signature This is an example of the simple signature:
/KaCzo4Syrom78z3EQ5 SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0ImbzRMqzVDZkVG9 xD7nN1kuFw==li7dzDacuo67Jg7mtqEm2TRuOMU=
QW5QvnlMpA==
Code 28: Example of the simple (non AdES) XML signature And here, the obtained validation result:
Code 29: Example of the Simple Report associated to the non AdES signature
Date: 05/03/2015 79 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
16 HANDLING THE SCOPE OF THE SIGNATURE
The process of validating a digital signature faces the problem of how to tell the validator what was signed. The framework now offers to every implementer the possibility to address this problem by means of the abstract class: SignatureScope. Below are the different specializations of this class proposed by the framework:
Figure 10: SignatureScope default specializations To decide what is the perimeter of a signature SignatureScopeFinder interface must be used through its various implementations:
Figure 11: SignatureScopeFinder and its specializations As you can see that, for each type of signature there exists at least one implementation of SignatureScopeFinder. Each developer is free to define its own implementations of SignatureScopeFinder for each type of signature. It is possible to dynamically add them via the class SignatureScopeFinderFactory.
Figure 12: SignatureScopeFinderFactory class To do this the method getSignatureScopeFinderMap() must be invoked. It returns the Map containing for each signature type its associated SignatureScopeFinder. The rules defined in the SignatureScopeFinder are materialized in the DiagnosticData by the XML expressed by the following XSD description:
Date: 05/03/2015 80 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
17 TESTING FACILITY CLASSES
The following classes are used in the examples given further above and have to be made available when compiling the examples.
Mock CRL Sources
This class allows to provide a mock CRL source based on the list of individual CRL(s). The class is in /dss- cookbook/src/main/java/eu/europa/ec/markt/dss/cookbook/mock/MockCRLSource.java
Mock OCSP Sources
The class is in /dss-cookbook/src/main/java/eu/europa/ec/markt/dss/cookbook/mock/MockOCSPSource.java
AlwaysValidOCSPSource
The class is in /dss- cookbook/src/main/java/eu/europa/ec/markt/dss/cookbook/sources/AlwaysValidOCSPSource.java
MockTSLCertificateSource
This trusted list certificates source allows providing dummy trusted lists. You need to save on your file system some real trusted lists and change their content to fit your needs. The class is in /dss-cookbook/src/main/java/eu/europa/ec/markt/dss/cookbook/mock/MockTSLCertificateSource.java It is also possible to use another implementation of an empty trusted list. It allows adding manually any certificate. There is no loading of trusted list what is very time consuming. The class is in /dss- cookbook/src/main/java/eu/europa/ec/markt/dss/cookbook/mock/MockEmptyTSLCertificateSource.java
MockTSPSource
The class is in /dss-cookbook/src/main/java/eu/europa/ec/markt/dss/cookbook/mock/MockTSPSource.java
Date: 05/03/2015 81 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
18 ACCESSING A STANDARD JAVA KEYSTORE
1.25 JavaKeyStore
This class gives the access to the Java KeyStore and allows extracting a certificate and a KSPrivateKeyEntry.
package eu.europa.ec.markt.dss.cookbook.sources;
import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.signature.token.KSPrivateKeyEntry;
public class JavaKeyStoreTool {
protected KeyStore ks = null;
public JavaKeyStoreTool(final String ksUrlLocation, final String ksPassword) {
InputStream ksStream = null; try { final URL ksLocation = new URL(ksUrlLocation); ks = KeyStore.getInstance(KeyStore.getDefaultType()); ksStream = ksLocation.openStream(); ks.load(ksStream, (ksPassword == null) ? null : ksPassword.toCharArray()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } finally { DSSUtils. closeQuietly ( ksStream ); } }
public X509Certificate getCertificate(String certAlias, String password) {
try {
Certificate cert = ks.getCertificate(certAlias); if (cert == null) { return null; } if (!(cert instanceof X509Certificate)) { return null; } return (X509Certificate) cert; } catch (KeyStoreException e) {
throw new DSSException(e); } }
Date: 05/03/2015 82 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
public KSPrivateKeyEntry getPrivateKey(String certAlias, String password) {
try {
final Key key = ks.getKey(certAlias, password.toCharArray()); if (key == null) { return null; } if (!(key instanceof PrivateKey)) { return null; } final Certificate[] certificateChain = ks.getCertificateChain(certAlias); KeyStore.PrivateKeyEntry privateKey = new KeyStore.PrivateKeyEntry((PrivateKey) key, certificateChain); KSPrivateKeyEntry ksPrivateKey = new KSPrivateKeyEntry(privateKey); return ksPrivateKey; } catch (KeyStoreException e) { throw new DSSException(e); } catch (UnrecoverableKeyException e) { throw new DSSException(e); } catch (NoSuchAlgorithmException e) { throw new DSSException(e); } } }
Code 31: cookbook.example.sources.JavaKeyStoreTool.java
1.26 Signing „Application“
This example shows how to sign a document using a Java KeyStore.
package eu.europa.ec.markt.dss.cookbook.example.sign;
import java.io.IOException; import java.util.Date;
import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.FileDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.token.JKSSignatureToken; import eu.europa.ec.markt.dss.signature.token.KSPrivateKeyEntry; import eu.europa.ec.markt.dss.signature.xades.XAdESService; import eu.europa.ec.markt.dss.validation102853.CommonCertificateVerifier;
public class SigningApplication {
public static void main(String[] args) throws IOException {
//GET THE LOCATION OF YOUR JKS FILE String location = "yourFile.jks"; JavaKeyStoreTool jks = new JavaKeyStoreTool(location, "password");
JKSSignatureToken signingToken = new JKSSignatureToken(location, "password");
KSPrivateKeyEntry privateKey = jks.getPrivateKey("dss", "password");
DSSDocument toBeSigned = new FileDocument("src/test/resources/xml_example.xml");
SignatureParameters params = new SignatureParameters();
params.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B); params.setSignaturePackaging(SignaturePackaging.ENVELOPED); params.setSigningCertificate(privateKey.getCertificate()); params.setCertificateChain(privateKey.getCertificateChain()); params.bLevel().setSigningDate(new Date());
CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();
Date: 05/03/2015 83 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
XAdESService service = new XAdESService(commonCertificateVerifier); byte[] dataToSign = service.getDataToSign(toBeSigned, params); byte[] signatureValue = signingToken.sign(dataToSign, params. getDigestAlgorithm (), privateKey); DSSDocument signedDocument = service.signDocument(toBeSigned, params, signatureValue); DSSUtils. copy ( signedDocument .openStream(), System. out ); } }
Code 32: cookbook.example.sign.SigningApplication.java
Date: 05/03/2015 84 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
1.27 Root class „Cookbook“
This example shows how to sign a document using a Java KeyStore.
/*** DSS - Digital Signature Services * Copyright (C) 2015 European Commission, provided under the CEF programme * * This file is part of the "DSS - Digital Signature Services" project. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package eu.europa.ec.markt.dss.cookbook.example;
import java.net.URL;
import eu.europa.ec.markt.dss.cookbook.mock.MockTSPSource; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.FileDocument; import eu.europa.ec.markt.dss.signature.token.AbstractSignatureTokenConnection; import eu.europa.ec.markt.dss.signature.token.DSSPrivateKeyEntry; import eu.europa.ec.markt.dss.signature.token.Pkcs12SignatureToken;
/** * Super-class for all cookbook examples. */ public class Cookbook {
/** * The document to sign */ static protected DSSDocument toSignDocument;
/** * The document to extend */ static protected DSSDocument toExtendDocument;
/** * The object which is in charge of digesting and encrypting the data to sign. */ static protected AbstractSignatureTokenConnection signingToken;
/** * This object contains the private key associated to the signing certificate. */ static protected DSSPrivateKeyEntry privateKey;
/** * This method converts the resource path to the absolute path. * * @param resourcePath * resource path * @return */ public static String getPathFromResource(final String resourcePath) {
URL uri = Cookbook.class.getResource(resourcePath); String absolutePath = uri.getPath(); return absolutePath;
Date: 05/03/2015 85 / 86 Doc. Version: V2.7 CEF eSignature Building Block DSS Cookbook
}
/** * This method sets the common parameters. */ protected static void prepareXmlDoc() { String toSignFilePath = getPathFromResource("/xml_example.xml"); toSignDocument = new FileDocument(toSignFilePath); }
/** * This method sets the common parameters. */ protected static void preparePdfDoc() { String toSignFilePath = getPathFromResource("/hello-world.pdf"); toSignDocument = new FileDocument(toSignFilePath); }
/** * This method sets the common parameters. */ protected static void preparePKCS12TokenAndKey() { String pkcs12TokenFile = getPathFromResource("/user_a_rsa.p12"); signingToken = new Pkcs12SignatureToken("password", pkcs12TokenFile); privateKey = signingToken.getKeys().get(0); }
protected static MockTSPSource getMockTSPSource() { return new MockTSPSource(); } }
Code 33: cookbook.example.Cookbook.java
Date: 05/03/2015 86 / 86 Doc. Version: V2.7