1 /*
2  *
3  *  Copyright (C) 1998-2019, OFFIS e.V.
4  *  All rights reserved.  See COPYRIGHT file for details.
5  *
6  *  This software and supporting documentation were developed by
7  *
8  *    OFFIS e.V.
9  *    R&D Division Health
10  *    Escherweg 2
11  *    D-26121 Oldenburg, Germany
12  *
13  *
14  *  Module: dcmsign
15  *
16  *  Author: Marco Eichelberg
17  *
18  *  Purpose:
19  *    classes: SiTimeStamp
20  *
21  */
22 
23 #ifndef SITSTAMP_H
24 #define SITSTAMP_H
25 
26 #include "dcmtk/config/osconfig.h"
27 
28 #ifdef WITH_OPENSSL
29 
30 #include "dcmtk/dcmsign/sitypes.h"
31 #include "dcmtk/ofstd/ofstring.h"
32 
33 // forward declarations
34 class DcmItem;
35 class SiCertificateVerifier;
36 class SiCertificate;
37 struct TS_req_st;
38 struct TS_resp_st;
39 struct TS_tst_info_st;
40 typedef struct TS_req_st TS_REQ;
41 typedef struct TS_resp_st TS_RESP;
42 typedef struct TS_tst_info_st TS_TST_INFO;
43 typedef struct pkcs7_st PKCS7;
44 
45 /** Base class for a timestamp client.
46  *  Instances of derived classes are able to request timestamps from a timestamp service.
47  *  This class implements the code needed to create a timestamp request and to insert
48  *  a timestamp reply into a DICOM dataset, but not the protocol for actually
49  *  interacting with a timestamp authority.
50  *  @remark this class is only available if DCMTK is compiled with OpenSSL support enabled.
51  */
52 class DCMTK_DCMSIGN_EXPORT SiTimeStamp
53 {
54 public:
55 
56   /// default constructor
57   SiTimeStamp();
58 
59   /// destructor
60   virtual ~SiTimeStamp();
61 
62   /** takes a block of raw data and requests a time stamp for this raw data.
63    *  @param inputData pointer to raw data
64    *  @param inputDataSize length of raw data block in bytes
65    *  @return status code
66    */
67   virtual OFCondition stamp(
68     const unsigned char *inputData,
69     unsigned long inputDataSize) = 0;
70 
71   /** reads the current timestamp from an item of the Digital Signatures Sequence
72    *  and creates a timestamp ticket object.
73    *  @param item item of the DigitalSignatureSQ from which the timestamp is read
74    *  @return status code
75    */
76   virtual OFCondition read(DcmItem& item);
77 
78   /** writes the current timestamp into an item of the Digital Signatures Sequence
79    *  and creates the timestamp type information in the item.
80    *  @param item item of the DigitalSignatureSQ to which the timestamp is written
81    *  @return status code
82    */
83   virtual OFCondition write(DcmItem& item) = 0;
84 
85   /** set the requested policy OID to be included into the time stamp query
86    *  @param oid policy OID, NULL for no policy (which is the default).
87    */
88   virtual void setPolicyOID(const char *oid);
89 
90   /** sets the flag controlling whether or not a nonce is included
91    *  into the timestamp query. Since a nonce is a protection against replay
92    *  attack, normally it should be included, and this is also the default.
93    *  @param nonce OFTrue if nonce should be included, OFFalse otherwise
94    */
95   virtual void setNonce(OFBool nonce);
96 
97   /** sets the flag controlling whether the timestamp authority will be
98    *  requested to include its certificate into the timestamp reply.
99    *  A timestamp reply with certificate is easier to verify, as less
100    *  external key material is required, but somewhat larger.
101    *  Default is OFTrue;
102    *  @param creq OFTrue if certificate should be requested, OFFalse otherwise
103    */
104   virtual void setCertificateRequested(OFBool creq);
105 
106   /** sets the message authentication code to be used for creating
107    *  the hash value in the timestamp query. Default is SHA256.
108    *  @param creq OFTrue if certificate should be requested, OFFalse otherwise
109    */
110   virtual void setMAC(E_MACType mac);
111 
112   // methods that return the various attributes of a timestamp ticket
113 
114   /** checks if this object contains a timestamp ticket info object
115    *  @return OFTrue if timestamp ticket info available, OFFalse otherwise
116    */
117   virtual OFBool have_tsinfo() const;
118 
119   /** returns the timestamp ticket info version number
120    *  @return tsinfo version number if available, -1 otherwise
121    */
122   virtual long get_tsinfo_version() const;
123 
124   /** returns the timestamp ticket info policy OID
125    *  @param oid upon return, contains the policy OID if available, an empty string otherwise
126    */
127   virtual void get_tsinfo_policy_oid(OFString& oid) const;
128 
129   /** returns the timestamp ticket info MAC algorithm name
130    *  @param mac upon return, contains the MAC algorithm name if available, an empty string otherwise
131    */
132   virtual void get_tsinfo_imprint_algorithm_name(OFString& mac) const;
133 
134   /** returns the timestamp ticket info serial number
135    *  @param serial upon return, contains the serial number if available, an empty string otherwise
136    */
137   virtual void get_tsinfo_serial_number(OFString& serial) const;
138 
139   /** returns the timestamp ticket info nonce, if present
140    *  @param nonce upon return, contains the nonce if available, an empty string otherwise
141    */
142   virtual void get_tsinfo_nonce(OFString& nonce) const;
143 
144   /** returns the timestamp ticket info timestamp authority (TSA) name, if present
145    *  @param tsa upon return, contains the TSA name if available, an empty string otherwise
146    */
147   virtual void get_tsinfo_tsa_name(OFString& tsa) const;
148 
149   /** returns the timestamp ticket info ordering flag
150    *  @return OFTrue if timestamp ticket is present and contains an ordering flag with value "true", OFFalse otherwise
151    */
152   virtual OFBool get_tsinfo_ordering() const;
153 
154   /** returns the timestamp ticket info accuracy, if present
155    *  @param accuracy upon return, contains the accuracy if available, an empty string otherwise
156    */
157   virtual void get_tsinfo_accuracy(OFString& accuracy) const;
158 
159   /** returns the timestamp date/time information, if present
160    *  @param ts upon return, contains the timestamp date/time information, an empty string otherwise
161    */
162   virtual void get_tsinfo_timestamp(OFString& ts) const;
163 
164   /** returns the number of extensions in the timestamp ticket
165    *  @return number of extensions in the timestamp ticket
166    */
167   virtual int get_tsinfo_numextensions() const;
168 
169   /** returns one timestamp extension, if present
170    *  @param ext upon return, contains the timestamp extension if present, an empty string otherwise
171    *  @param idx number of the extension, 0 <= idx < get_tsinfo_numextensions().
172    */
173   virtual void get_tsinfo_extension(OFString& ext, int idx) const;
174 
175   /** this method performs the following functions:
176    *  - it checks if there is one and only one signer.
177    *  - it identifies the signer certificate (which may be embedded in the timestamp, or loaded in the SiCertificateVerifier store)
178    *  - it checks the extended key usage and key usage fields of the signer certificate
179    *  - it verifies the certificate path
180    *  - it checks if the certificate path meets the requirements of the
181    *    SigningCertificate ESS signed attribute.
182    *  - it verifies the signature value (against the imprint in the timestamp token
183    *  - it prints the contents of the signer certificate to the logger
184    *  @param cv container for the certificates used during verification
185    *  @return EC_Normal upon success, an error code otherwise.
186    */
187   virtual OFCondition verifyTSSignature(SiCertificateVerifier& cv);
188 
189   /** Verify the timestamp token by checking that its imprint is
190    *  indeed a hash of the DICOM signature, that the version number
191    *  is as expected and that the TSA name, if provided in the timestamp
192    *  ticket structure, matches the name of the TSA given in the TSA
193    *  certificate.
194    *  @param cv container for the certificates used during verification
195    *  @param ditem item of the Digital Signatures Sequence containing the timestamp
196    *  @param cert certificate of the signer of the DICOM signature, used to check
197    *    the date/time of the timestamp against the validity period of the certificate
198    *  @return EC_Normal upon success, an error code otherwise.
199    */
200   virtual OFCondition verifyTSToken(
201     SiCertificateVerifier& cv,
202     DcmItem& ditem,
203     SiCertificate& cert);
204 
205   /** returns an error string containing a textual description of the result
206    *  of the last call to verifyTSSignature() or verifyTSToken()
207    *  if that call returned SI_EC_TimestampSignatureVerificationFailed.
208    *  @param err text string returned in this parameter
209    */
210   void lastError(OFString& err) const;
211 
212 protected:
213 
214   /** takes a block of raw data, computes a message digest and creates
215    *  a time stamp query object.
216    *  @param inputData pointer to raw data
217    *  @param inputDataSize length of raw data block in bytes
218    *  @return status code
219    */
220   virtual OFCondition create_ts_query(
221     const unsigned char *inputData,
222     unsigned long inputDataSize);
223 
224   /** return pointer to timestamp query object, may be NULL.
225    *  @return pointer to timestamp query object, may be NULL.
226    */
getTSQ()227   virtual TS_REQ *getTSQ() { return tsq_; }
228 
229   /** return pointer to timestamp response object, may be NULL.
230    *  @return pointer to timestamp response object, may be NULL.
231    */
getTSR()232   virtual TS_RESP *getTSR() { return tsr_; }
233 
234   /** return pointer to timestamp ticket object, may be NULL.
235    *  @return pointer to timestamp ticket object, may be NULL.
236    */
getTS()237   virtual PKCS7 *getTS() { return ts_; }
238 
239   /** return pointer to timestamp ticket info object, may be NULL.
240    *  @return pointer to timestamp ticket info object, may be NULL.
241    */
getTSInfo()242   virtual TS_TST_INFO *getTSInfo() { return tsinfo_; }
243 
244   /** load timestamp query from file
245    *  @param fname filename, must not be NULL
246    *  @return status code
247    */
248   virtual OFCondition load_ts_query(const char *fname);
249 
250   /** load timestamp response from file
251    *  @param fname filename, must not be NULL
252    *  @return status code
253    */
254   virtual OFCondition load_ts_response(const char *fname);
255 
256   /** check consistency between timestamp query (if available), timestamp
257    *  response and DICOM digital signature.
258    *  @param tsq pointer to timestamp query, may be NULL
259    *  @param tsr pointer to timestamp response, must not be NULL
260    *  @param ditem item of the DigitalSignaturesSequence to which this timestamp belongs
261    *  @return status code
262    */
263   static OFCondition check_ts_response(
264     TS_REQ *tsq,
265     TS_RESP *tsr,
266     DcmItem& ditem);
267 
268   /** insert timestamp token into DICOM dataset
269    *  The timestamp response must have been checked prior to this method call.
270    *  @param tsr pointer to timestamp response, must not be NULL
271    *  @param ditem item of the DigitalSignaturesSequence to which this timestamp is written
272    *  @return status code
273    */
274   static OFCondition write_ts_token(
275     TS_RESP *tsr,
276     DcmItem& ditem);
277 
278 private:
279 
280   /// time stamping policy OID to be included in the time stamp query. Default is empty.
281   OFString tsq_policy_;
282 
283   /// MAC algorithm for creating the hash key to be timestamped. Default is SHA-256.
284   E_MACType tsq_mac_;
285 
286   /// Use a pseudo-random nonce in the time stamp query. Default is OFTrue.
287   OFBool tsq_use_nonce_;
288 
289   /// Request the TSA certificate to be embedded into the time stamp reply. Default is OFTrue.
290   OFBool tsq_certificate_requested_;
291 
292   /// pointer to time stamp request object, may be NULL
293   TS_REQ *tsq_;
294 
295   /// pointer to time stamp response object, may be NULL
296   TS_RESP *tsr_;
297 
298   /// pointer to time stamp ticket object, may be NULL
299   PKCS7 *ts_;
300 
301   /// pointer to time stamp ticket info object (extracted from the timestamp ticket), may be NULL
302   TS_TST_INFO *tsinfo_;
303 
304   /// OpenSSL X.509 certificate verification error code for the last operation
305   long errorCode_;
306 
307   /// error string for the last operation, valid if errorCode_ < 0
308   const char *errorString_;
309 
310 };
311 
312 #endif
313 #endif
314