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: DcmSignature 20 * 21 */ 22 23 #ifndef DCMSIGN_H 24 #define DCMSIGN_H 25 26 #include "dcmtk/config/osconfig.h" 27 28 #ifdef WITH_OPENSSL 29 30 #include "dcmtk/dcmsign/sitypes.h" 31 #include "dcmtk/dcmdata/dcxfer.h" /* for E_TransferSyntax */ 32 #include "dcmtk/dcmsign/sipurpos.h" /* for E_SignaturePurposeType */ 33 34 #define INCLUDE_CSTDIO 35 #include "dcmtk/ofstd/ofstdinc.h" 36 37 class DcmAttributeTag; 38 class DcmDateTime; 39 class DcmItem; 40 class DcmSequenceOfItems; 41 class DcmStack; 42 class DcmTagKey; 43 class SiPrivateKey; 44 class SiCertificate; 45 class SiSecurityProfile; 46 class SiMAC; 47 class SiTimeStamp; 48 49 /** this class provides the main interface to the dcmsign module - it allows 50 * to create, examine and verify digital signatures in DICOM datasets or 51 * items. The methods in this class do not handle digital signatures 52 * embedded in sequence items within the dataset, other than providing 53 * helper functions that allow to locate and attach the sub-items 54 * separately. 55 * @remark this class is only available if DCMTK is compiled with 56 * OpenSSL support enabled. 57 */ 58 class DCMTK_DCMSIGN_EXPORT DcmSignature 59 { 60 public: 61 /** initializes the dcmsign library including the underlying OpenSSL library. 62 * this method should be called by main() before any object of the dcmsign 63 * library is created or used. 64 */ 65 static void initializeLibrary(); 66 67 /// default constructor 68 DcmSignature(); 69 70 /// destructor 71 virtual ~DcmSignature(); 72 73 /** attaches a DICOM dataset or item to the signature object. 74 * The dataset is detached by a call to detach() or by destruction 75 * of the signature object. This object may modify but never deletes 76 * an attached dataset. 77 * @param dataset dataset or item to be attached 78 */ 79 void attach(DcmItem *dataset); 80 81 /** detaches an attached DICOM dataset from the signature object. 82 */ 83 void detach(); 84 85 /** creates a new digital signature in the current dataset. 86 * Checks whether private and public key match and whether 87 * all requirements of the given security profile are fulfilled. 88 * @param key private key for signature creation 89 * @param cert certificate with public key 90 * @param mac MAC algorithm to be used for signature creation 91 * @param profile security profile for signature creation 92 * @param xfer transfer syntax to use when serializing DICOM data 93 * @param tagList pointer to list of attribute tags to sign, may be NULL. 94 * If this parameter is nonzero, it contains a list of attribute sign. 95 * The real list of attributes signed is derived from this parameter plus the 96 * requirements of the security profile. If NULL, a universal match is assumed, 97 * i.e. all signable attributes in the data set are signed. 98 * @param timeStamp pointer to time stamp client used to create timestamps 99 * for the digital signature. 100 * @param sigPurpose digital signature purpose 101 * @return status code 102 */ 103 OFCondition createSignature( 104 SiPrivateKey& key, 105 SiCertificate& cert, 106 SiMAC& mac, 107 SiSecurityProfile& profile, 108 E_TransferSyntax xfer=EXS_LittleEndianExplicit, 109 const DcmAttributeTag *tagList=NULL, 110 SiTimeStamp *timeStamp=NULL, 111 SiSignaturePurpose::E_SignaturePurposeType sigPurpose=SiSignaturePurpose::ESP_none); 112 113 /** returns the number of signatures in the dataset. Does not count 114 * signatures embedded in sequence items within the dataset. 115 */ 116 unsigned long numberOfSignatures(); 117 118 /** removes a signature from the dataset. 119 * @param i index, must be < numberOfSignatures(). 120 * @return status code 121 */ 122 OFCondition removeSignature(unsigned long i); 123 124 /** selects one of the digital signatures from the attached dataset for reading. 125 * @param i index, must be < numberOfSignatures() 126 * @return status code 127 */ 128 OFCondition selectSignature(unsigned long i); 129 130 /** verifies the current signature. 131 * Current signature must be selected with selectSignature(). 132 * @return SI_EC_Normal if signature is complete and valid, an error code 133 * describing the type of verification failure otherwise. 134 */ 135 OFCondition verifyCurrent(); 136 137 /** returns the MAC ID of the current signature. 138 * Current signature must be selected with selectSignature(). 139 * @param macID MAC ID returned in this parameter upon success 140 * @return status code 141 */ 142 OFCondition getCurrentMacID(Uint16& macID); 143 144 /** returns the MAC Calculation Transfer Syntax of the current signature. 145 * If the transfer syntax is well-known, the UID is replaced by the 146 * transfer syntax name preceded by '='. 147 * Current signature must be selected with selectSignature(). 148 * @param str transfer syntax name or UID returned in this parameter upon success 149 * @return status code 150 */ 151 OFCondition getCurrentMacXferSyntaxName(OFString& str); 152 153 /** returns the MAC Algorithm Name of the current signature. 154 * Current signature must be selected with selectSignature(). 155 * @param str MAC algorithm name returned in this parameter upon success 156 * @return status code 157 */ 158 OFCondition getCurrentMacName(OFString& str); 159 160 /** returns the Digital Signature UID of the current signature. 161 * Current signature must be selected with selectSignature(). 162 * @param str signature UID returned in this parameter upon success 163 * @return status code 164 */ 165 OFCondition getCurrentSignatureUID(OFString& str); 166 167 /** returns the Signature Date/Time of the current signature. 168 * Current signature must be selected with selectSignature(). 169 * @param str signature date/time returned in this parameter upon success 170 * @return status code 171 */ 172 OFCondition getCurrentSignatureDateTime(OFString& str); 173 174 /** returns a pointer to the object representing Signature Date/Time 175 * of the current signature. 176 * Current signature must be selected with selectSignature(). 177 * @return pointer to signature datetime if present, NULL otherwise 178 */ 179 DcmDateTime *getCurrentSignatureDateTime(); 180 181 /** returns the Data Elements Signed attribute of the current signature if present. 182 * Current signature must be selected with selectSignature(). 183 * If a valid signature is selected but the signature does not contain 184 * the Data Elements Signed element (i.e. all attributes are signed), this method 185 * returns an error code. 186 * @param desig data elements signed returned in this parameter upon success 187 * @return status code 188 */ 189 OFCondition getCurrentDataElementsSigned(DcmAttributeTag& desig); 190 191 /** returns the signature purpose code of the current signature if present. 192 * Current signature must be selected with selectSignature(). 193 * If a valid signature is selected but the signature does not contain 194 * a valid SignaturePurposeCodeSequence, this method returns an error code. 195 * @param codeValue signature purpose code value returned in this parameter upon success 196 * @param codeMeaning signature purpose code meaning returned in this parameter upon success 197 * @param codingSchemeDesignator signature purpose coding scheme designator returned in this parameter upon success 198 * @return status code 199 */ 200 OFCondition getCurrentSignaturePurpose(OFString& codeValue, OFString& codeMeaning, OFString& codingSchemeDesignator); 201 202 /** verifies whether the currently selected signature within the 203 * currently attached dataset matches the requirements of the 204 * given signature profile. 205 * @param sprof security profile 206 * @return EC_Normal if signature matches, an error code otherwise 207 */ 208 OFCondition verifySignatureProfile(SiSecurityProfile &sprof); 209 210 /** returns the certificate of the current signature if present. 211 * Current signature must be selected with selectSignature(). 212 * May return NULL if certificate is unavailable. 213 * @return pointer to current certificate, NULL if unavailable. 214 */ 215 SiCertificate *getCurrentCertificate(); 216 217 /** returns the certified timestamp of the current signature if present. 218 * Current signature must be selected with selectSignature(). 219 * May return NULL if timestamp is unavailable. 220 * @return pointer to current timestamp, NULL if unavailable. 221 */ 222 SiTimeStamp *getCurrentTimestamp(); 223 224 /** returns the item of the DigitalSignaturesSequence selected by the last call 225 * to selectSignature(), or NULL if no signature has been selected. 226 * @return pointer to current signature item, may be NULL 227 */ 228 DcmItem *getSelectedSignatureItem(); 229 230 /** dump all data that is fed into the MAC algorithm into the given file, 231 * which must be opened and closed by caller. 232 * @param f pointer to file already opened for writing; may be NULL. 233 */ 234 void setDumpFile(FILE *f); 235 236 /** recursively browses through the given dataset and searches the first 237 * occurrence of the DigitalSignaturesSequence. If found, returns 238 * a pointer to the Item in which the sequence is contained. 239 * @param item dataset to be browsed 240 * @param stack search stack, must be passed to findNextSignatureItem() later on. 241 * @return pointer to Item containing a DigitalSignatureSequence if found, NULL otherwise. 242 */ 243 static DcmItem *findFirstSignatureItem(DcmItem& item, DcmStack& stack); 244 245 /** recursively browses through the given dataset and searches the next 246 * occurrence of the DigitalSignaturesSequence. If found, returns 247 * a pointer to the Item in which the sequence is contained. 248 * @param item dataset to be browsed 249 * @param stack search stack as returned by findFirstSignatureItem() or the last call to this method. 250 * @return pointer to Item containing a DigitalSignatureSequence if found, NULL otherwise. 251 */ 252 static DcmItem *findNextSignatureItem(DcmItem& item, DcmStack& stack); 253 254 /** check a DER encoded ASN.1 SEQUENCE structure for a possible pad byte 255 * and, if a pad byte is detected, remove it by decreasing buflen. 256 * This will work for SEQUENCEs with one byte and two byte encoding 257 * (i.e. max 64 kBytes). 258 * @param buf pointer to DER encoded ASN.1 data 259 * @param buflen length of buffer pointed to, in bytes. The variable is 260 * decreased by one if a pad byte is detected. 261 */ 262 static void adjustASN1SequenceLength(const unsigned char *buf, unsigned long& buflen); 263 264 private: 265 266 /// private undefined copy constructor 267 DcmSignature(DcmSignature& arg); 268 269 /// private undefined copy assignment operator 270 DcmSignature& operator=(DcmSignature& arg); 271 272 /// removes the selection of a current signature if present 273 void deselect(); 274 275 /** allocates a new mac ID number for a new signature. 276 * examines all mac ID numbers in the digital signatures sequence 277 * and in the mac parameters sequence and returns an unused number. 278 * @param newID upon successful return, new number is passed in this parameter 279 * @return status code 280 */ 281 OFCondition allocateMACID(Uint16& newID); 282 283 /** searches a given item for the DCM_MACIDnumber element and returns 284 * its value if present 285 * @param item item to be searched 286 * @param macid MAC ID returned in this parameter upon success 287 * @return EC_Normal if successful, an error code otherwise 288 */ 289 static OFCondition getMACIDnumber(DcmItem &item, Uint16& macid); 290 291 /** checks if all tags from tagList are present in tagListOut, 292 * which is the list of attribute tags actually included in a signature, 293 * including tags added due to a signature profile, and without tags 294 * that were absent in the dataset. 295 * @param tagList list of attribute tags that should be present in the signature, may be NULL 296 * @param tagListOut list of attribute tags actually present in the signature, must not be NULL 297 * @return EC_Normal if check succeeds, an error code otherwise 298 */ 299 static OFCondition checkListOfSignedTags(const DcmAttributeTag *tagList, const DcmAttributeTag *tagListOut); 300 301 /** checks if the given tag key is present in tagList 302 * @param tag tag key 303 * @param tagList list of tag keys 304 * @return OFTrue of tag is present in tagList, OFFalse otherwise 305 */ 306 static OFBool inTagList(const DcmTagKey &tag, const DcmAttributeTag& tagList); 307 308 /** returns the current date and time as a DICOM DT string. 309 * @param str date/time returned in this string. 310 */ 311 static void currentDateTime(OFString &str); 312 313 /// pointer to current item if attached, NULL otherwise 314 DcmItem *currentItem; 315 316 /// pointer to mac parameters sequence of attached item, may be NULL if not attached or not yet present 317 DcmSequenceOfItems *macParametersSq; 318 319 /// pointer to digital signatures sequence of attached item, may be NULL if not attached or not yet present 320 DcmSequenceOfItems *signatureSq; 321 322 /// if nonzero, the data fed to the MAC algorithm is also stored in this file. 323 FILE *dumpFile; 324 325 /// pointer to currently selected signature item 326 DcmItem *selectedSignatureItem; 327 328 /// pointer to currently selected mac parameters item 329 DcmItem *selectedMacParametersItem; 330 331 /// pointer to certificate for currently selected signature item 332 SiCertificate *selectedCertificate; 333 334 /// pointer to certified timestamp for currently selected signature item 335 SiTimeStamp *selectedTimestamp; 336 }; 337 338 #endif 339 #endif 340