├── .codeinventory.yml ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── apple ├── GSA_Signing_Tool_User_Guide-Mac.pdf ├── LICENSE.txt ├── OpenSC │ └── lib │ │ └── libopensc.3.dylib ├── README.md ├── drivers │ └── opensc-pkcs11.so ├── lib │ ├── bcmail-jdk15on-152.jar │ ├── bcpg-jdk15on-152.jar │ ├── bcpkix-jdk15on-152.jar │ ├── bcprov-ext-jdk15on-152.jar │ ├── bcprov-jdk15on-152.jar │ └── commons-io-2.4.jar └── src │ └── com │ └── gsa │ └── signingtool │ └── app │ ├── CheckRevocationStatus.java │ ├── Gui.java │ ├── SelectSlot.java │ ├── SigningTool.java │ ├── SigningToolVerifier.java │ ├── StatusUpdater.java │ ├── SwingWorkerService.java │ └── images │ ├── close.png │ ├── exelogo.png │ ├── icon.png │ ├── info.png │ ├── logo.png │ ├── open.png │ └── text.png └── microsoft ├── GSA_Signing_Tool_User_Guide-64bit.pdf ├── LICENSE.txt ├── README.md ├── README.txt ├── drivers ├── 32-bit │ └── opensc-pkcs11.dll └── 64-bit │ └── opensc-pkcs11.dll ├── icon.ico ├── lib ├── bcmail-jdk15on-152.jar ├── bcpg-jdk15on-152.jar ├── bcpkix-jdk15on-152.jar ├── bcprov-ext-jdk15on-152.jar ├── bcprov-jdk15on-152.jar └── commons-io-2.4.jar └── src └── com └── gsa └── signingtool ├── app ├── CheckRevocationStatus.java ├── Gui.java ├── SelectSlot.java ├── SigningTool.java ├── SigningToolVerifier.java ├── StatusUpdater.java └── SwingWorkerService.java └── images ├── close.png ├── exelogo.png ├── icon.png ├── info.png ├── logo.png ├── open.png └── text.png /.codeinventory.yml: -------------------------------------------------------------------------------- 1 | name: 'GSA Document Signing Tools' 2 | description: 'Tools used for digitally signing documents and files with Personal Identity Verification (PIV) credentials' 3 | license: 'https://github.com/GSA/gsa-doc-digital-signature/blob/platforms/LICENSE.md' 4 | openSourceProject: 1 5 | governmentWideReuseProject: 1 6 | tags: 7 | - piv 8 | - digital-signature 9 | contact: 10 | email: icam@gsa.gov 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Welcome 2 | 3 | Thank you for considering contributing to the Document Signing Tool. 4 | 5 | Before contributing, we encourage you to read our LICENSE, and our README, all of which are in this repository. 6 | 7 | ## Public domain 8 | 9 | This project is in the public domain within the United States, and 10 | copyright and related rights in the work worldwide are waived through 11 | the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/). 12 | 13 | All contributions to this project will be released under the CC0 14 | dedication. By submitting a pull request, you are agreeing to comply 15 | with this waiver of copyright interest. 16 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This project is in the 2 | public domain within the United States. 3 | 4 | We waive copyright and related rights in the work 5 | worldwide through the CC0 1.0 Universal public domain dedication. 6 | 7 | ## CC0 1.0 Universal Summary 8 | 9 | This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode). 10 | 11 | ### No Copyright 12 | 13 | The person who associated a work with this deed has dedicated the work to 14 | the public domain by waiving all of his or her rights to the work worldwide 15 | under copyright law, including all related and neighboring rights, to the 16 | extent allowed by law. 17 | 18 | You can copy, modify, distribute and perform the work, even for commercial 19 | purposes, all without asking permission. 20 | 21 | ### Other Information 22 | 23 | In no way are the patent or trademark rights of any person affected by CC0, 24 | nor are the rights that other persons may have in the work or in how the 25 | work is used, such as publicity or privacy rights. 26 | 27 | Unless expressly stated otherwise, the person who associated a work with 28 | this deed makes no warranties about the work, and disclaims liability for 29 | all uses of the work, to the fullest extent permitted by applicable law. 30 | When using or citing the work, you should not imply endorsement by the 31 | author or the affirmer. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This tool is deprecated. Please follow these new procedures - https://playbooks.idmanagement.gov/signfedregister/ 2 | 3 | ### Description 4 | This repository contains the General Services Administration (GSA) Document Signing tools used for digitally signing documents and files with Personal Identity Verification (PIV) credentials. 5 | 6 | The main purpose of the tool is for Federal agencies to use for digitally signing documents to be submitted to the Office of the Federal Register's (OFR) document submission web portal. The tool was developed using Java 8. It relies on Bouncy Castle libraries for the signing operations, Apache Commons for file operations, and OpenSC for PIV operations. 7 | 8 | 9 | ### How does it work? 10 | The GSA Document Signing Tool includes a simple, 508-compliant Graphical User Interface (GUI) to assist in the signing of your desired document. The tool allows the user to select the desired file they'd like signed, a field to enter the user's PIV application PIN, and a "Sign" button to initiate the signing. The tool automatically detects any smart card readers and PIV cards connected to the system. The tool utilizes PKCS#11 to interact with the reader and PIV card. The signed file is formatted in an enveloped PKCS#7 (.p7m) file, which is the required format for the OFR's document submission portal. In order for the tool to sign correctly, the PIV card MUST contain a valid digital signing certificate (i.e. Key usage of Digital Signature and Non-repudiation). If it doesn't contain a valid digital signing certificate, the application will provide a descriptive error messages. 11 | 12 | ### Installation/Usage Instructions 13 | 14 | The GSA Document Signing Tool includes a Windows 32-bit, 64-bit, and MacOS version. Verify your system's operating system before installing. 15 | 16 | The installation files (executables) can be found under [Releases](https://github.com/GSA/gsa-doc-digital-signature/releases). 17 | 18 | Use the following User Guides below for guiding you through the installation process: 19 | 20 | * Windows Installation Guide - https://github.com/GSA/gsa-doc-digital-signature/blob/platforms/microsoft/GSA_Signing_Tool_User_Guide-64bit.pdf 21 | * MacOS Installation Guides - https://github.com/GSA/gsa-doc-digital-signature/blob/platforms/apple/GSA_Signing_Tool_User_Guide-Mac.pdf 22 | 23 | ### Developer Install Instructions 24 | 25 | For developers, the source code, 3rd party libraries, and drivers can be imported into a Java IDE (i.e. Eclipse, NetBeans). 26 | 27 | **NOTE:** This tool will only compile correctly using Java 8. Lower Java versions are not compatible with the development of this tool. 28 | 29 | Initial setup: 30 | * Import initial source code in the "/src" directory to your Java IDE project source code directory. 31 | * Add the specific OpenSC driver for the system type you will be developing for (i.e. if you are developing on a 64-bit system, copy the opensc driver in the 64-bit directory, and paste the driver in the "lib" directory with the Bouncy Castle libraries. 32 | * Import "lib" directory to your Java IDE project. 33 | * Use the "GUI" class, as your main executable class for executing the tool. 34 | 35 | ### Dependencies 36 | 37 | The GSA Document Signing Tool leverages 3rd party libraries including: 38 | * [Oracle Java] http://www.oracle.com/ 39 | * [Bouncy Castle] https://www.bouncycastle.org/ 40 | * [opensc] https://github.com/OpenSC/OpenSC 41 | * [commons-io] http://commons.apache.org/proper/commons-io/ 42 | 43 | The tool has not been tested with alternate versions of Java such as OpenJDK. Contributors are welcome to determine compatibility and update this README and dependencies appropriately. 44 | 45 | On Windows, the installer was built using [inno setup] http://www.jrsoftware.org/ 46 | 47 | ### License 48 | This project is in the public domain within the United States. 49 | 50 | We waive copyright and related rights in the work worldwide through the CC0 1.0 Universal public domain dedication. 51 | 52 | Please review the License found in this repository. 53 | 54 | ### Contact Information 55 | 56 | For issues, please open an Issue in this repository. Contact icam at gsa.gov for any additional questions on contributing. 57 | -------------------------------------------------------------------------------- /apple/GSA_Signing_Tool_User_Guide-Mac.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/GSA_Signing_Tool_User_Guide-Mac.pdf -------------------------------------------------------------------------------- /apple/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The General Services Administration(GSA) is currently distributing this computer program. 2 | This computer program was built using Java 8. Additional third party libraries, include: 3 | 4 | * [Bouncy Castle] https://www.bouncycastle.org/ 5 | * [opensc] https://github.com/OpenSC/OpenSC 6 | * [Java] http://www.oracle.com/ 7 | * [commons-io] http://commons.apache.org/proper/commons-io/ 8 | 9 | On Windows, the installer was built using [inno setup] http://www.jrsoftware.org/ 10 | Each of these libraries is licensed under an open source license. 11 | 12 | The computer program is provided by GSA as a public service and is expressly provided "AS IS." 13 | GSA MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED, IN FACT OR ARISING BY OPERATION OF LAW, 14 | INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 15 | PURPOSE, NON-INFRINGEMENT AND DATA ACCURACY. GSA NEITHER REPRESENTS NOR WARRANTS THAT THE 16 | OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE 17 | CORRECTED. GSA DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE 18 | OR THE RESULTS THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, 19 | OR USEFULNESS OF THE SOFTWARE. 20 | 21 | 22 | ## opensc ## 23 | 24 | GNU LESSER GENERAL PUBLIC LICENSE 25 | Version 2.1, February 1999 26 | 27 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 28 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 29 | Everyone is permitted to copy and distribute verbatim copies 30 | of this license document, but changing it is not allowed. 31 | 32 | [This is the first released version of the Lesser GPL. It also counts 33 | as the successor of the GNU Library Public License, version 2, hence 34 | the version number 2.1.] 35 | 36 | Preamble 37 | 38 | The licenses for most software are designed to take away your 39 | freedom to share and change it. By contrast, the GNU General Public 40 | Licenses are intended to guarantee your freedom to share and change 41 | free software--to make sure the software is free for all its users. 42 | 43 | This license, the Lesser General Public License, applies to some 44 | specially designated software packages--typically libraries--of the 45 | Free Software Foundation and other authors who decide to use it. You 46 | can use it too, but we suggest you first think carefully about whether 47 | this license or the ordinary General Public License is the better 48 | strategy to use in any particular case, based on the explanations 49 | below. 50 | 51 | When we speak of free software, we are referring to freedom of use, 52 | not price. Our General Public Licenses are designed to make sure that 53 | you have the freedom to distribute copies of free software (and charge 54 | for this service if you wish); that you receive source code or can get 55 | it if you want it; that you can change the software and use pieces of 56 | it in new free programs; and that you are informed that you can do 57 | these things. 58 | 59 | To protect your rights, we need to make restrictions that forbid 60 | distributors to deny you these rights or to ask you to surrender these 61 | rights. These restrictions translate to certain responsibilities for 62 | you if you distribute copies of the library or if you modify it. 63 | 64 | For example, if you distribute copies of the library, whether gratis 65 | or for a fee, you must give the recipients all the rights that we gave 66 | you. You must make sure that they, too, receive or can get the source 67 | code. If you link other code with the library, you must provide 68 | complete object files to the recipients, so that they can relink them 69 | with the library after making changes to the library and recompiling 70 | it. And you must show them these terms so they know their rights. 71 | 72 | We protect your rights with a two-step method: (1) we copyright the 73 | library, and (2) we offer you this license, which gives you legal 74 | permission to copy, distribute and/or modify the library. 75 | 76 | To protect each distributor, we want to make it very clear that 77 | there is no warranty for the free library. Also, if the library is 78 | modified by someone else and passed on, the recipients should know 79 | that what they have is not the original version, so that the original 80 | author's reputation will not be affected by problems that might be 81 | introduced by others. 82 | 83 | Finally, software patents pose a constant threat to the existence of 84 | any free program. We wish to make sure that a company cannot 85 | effectively restrict the users of a free program by obtaining a 86 | restrictive license from a patent holder. Therefore, we insist that 87 | any patent license obtained for a version of the library must be 88 | consistent with the full freedom of use specified in this license. 89 | 90 | Most GNU software, including some libraries, is covered by the 91 | ordinary GNU General Public License. This license, the GNU Lesser 92 | General Public License, applies to certain designated libraries, and 93 | is quite different from the ordinary General Public License. We use 94 | this license for certain libraries in order to permit linking those 95 | libraries into non-free programs. 96 | 97 | When a program is linked with a library, whether statically or using 98 | a shared library, the combination of the two is legally speaking a 99 | combined work, a derivative of the original library. The ordinary 100 | General Public License therefore permits such linking only if the 101 | entire combination fits its criteria of freedom. The Lesser General 102 | Public License permits more lax criteria for linking other code with 103 | the library. 104 | 105 | We call this license the "Lesser" General Public License because it 106 | does Less to protect the user's freedom than the ordinary General 107 | Public License. It also provides other free software developers Less 108 | of an advantage over competing non-free programs. These disadvantages 109 | are the reason we use the ordinary General Public License for many 110 | libraries. However, the Lesser license provides advantages in certain 111 | special circumstances. 112 | 113 | For example, on rare occasions, there may be a special need to 114 | encourage the widest possible use of a certain library, so that it 115 | becomes a de-facto standard. To achieve this, non-free programs must 116 | be allowed to use the library. A more frequent case is that a free 117 | library does the same job as widely used non-free libraries. In this 118 | case, there is little to gain by limiting the free library to free 119 | software only, so we use the Lesser General Public License. 120 | 121 | In other cases, permission to use a particular library in non-free 122 | programs enables a greater number of people to use a large body of 123 | free software. For example, permission to use the GNU C Library in 124 | non-free programs enables many more people to use the whole GNU 125 | operating system, as well as its variant, the GNU/Linux operating 126 | system. 127 | 128 | Although the Lesser General Public License is Less protective of the 129 | users' freedom, it does ensure that the user of a program that is 130 | linked with the Library has the freedom and the wherewithal to run 131 | that program using a modified version of the Library. 132 | 133 | The precise terms and conditions for copying, distribution and 134 | modification follow. Pay close attention to the difference between a 135 | "work based on the library" and a "work that uses the library". The 136 | former contains code derived from the library, whereas the latter must 137 | be combined with the library in order to run. 138 | 139 | GNU LESSER GENERAL PUBLIC LICENSE 140 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 141 | 142 | 0. This License Agreement applies to any software library or other 143 | program which contains a notice placed by the copyright holder or 144 | other authorized party saying it may be distributed under the terms of 145 | this Lesser General Public License (also called "this License"). 146 | Each licensee is addressed as "you". 147 | 148 | A "library" means a collection of software functions and/or data 149 | prepared so as to be conveniently linked with application programs 150 | (which use some of those functions and data) to form executables. 151 | 152 | The "Library", below, refers to any such software library or work 153 | which has been distributed under these terms. A "work based on the 154 | Library" means either the Library or any derivative work under 155 | copyright law: that is to say, a work containing the Library or a 156 | portion of it, either verbatim or with modifications and/or translated 157 | straightforwardly into another language. (Hereinafter, translation is 158 | included without limitation in the term "modification".) 159 | 160 | "Source code" for a work means the preferred form of the work for 161 | making modifications to it. For a library, complete source code means 162 | all the source code for all modules it contains, plus any associated 163 | interface definition files, plus the scripts used to control 164 | compilation and installation of the library. 165 | 166 | Activities other than copying, distribution and modification are not 167 | covered by this License; they are outside its scope. The act of 168 | running a program using the Library is not restricted, and output from 169 | such a program is covered only if its contents constitute a work based 170 | on the Library (independent of the use of the Library in a tool for 171 | writing it). Whether that is true depends on what the Library does 172 | and what the program that uses the Library does. 173 | 174 | 1. You may copy and distribute verbatim copies of the Library's 175 | complete source code as you receive it, in any medium, provided that 176 | you conspicuously and appropriately publish on each copy an 177 | appropriate copyright notice and disclaimer of warranty; keep intact 178 | all the notices that refer to this License and to the absence of any 179 | warranty; and distribute a copy of this License along with the 180 | Library. 181 | 182 | You may charge a fee for the physical act of transferring a copy, 183 | and you may at your option offer warranty protection in exchange for a 184 | fee. 185 | 186 | 2. You may modify your copy or copies of the Library or any portion 187 | of it, thus forming a work based on the Library, and copy and 188 | distribute such modifications or work under the terms of Section 1 189 | above, provided that you also meet all of these conditions: 190 | 191 | a) The modified work must itself be a software library. 192 | 193 | b) You must cause the files modified to carry prominent notices 194 | stating that you changed the files and the date of any change. 195 | 196 | c) You must cause the whole of the work to be licensed at no 197 | charge to all third parties under the terms of this License. 198 | 199 | d) If a facility in the modified Library refers to a function or a 200 | table of data to be supplied by an application program that uses 201 | the facility, other than as an argument passed when the facility 202 | is invoked, then you must make a good faith effort to ensure that, 203 | in the event an application does not supply such function or 204 | table, the facility still operates, and performs whatever part of 205 | its purpose remains meaningful. 206 | 207 | (For example, a function in a library to compute square roots has 208 | a purpose that is entirely well-defined independent of the 209 | application. Therefore, Subsection 2d requires that any 210 | application-supplied function or table used by this function must 211 | be optional: if the application does not supply it, the square 212 | root function must still compute square roots.) 213 | 214 | These requirements apply to the modified work as a whole. If 215 | identifiable sections of that work are not derived from the Library, 216 | and can be reasonably considered independent and separate works in 217 | themselves, then this License, and its terms, do not apply to those 218 | sections when you distribute them as separate works. But when you 219 | distribute the same sections as part of a whole which is a work based 220 | on the Library, the distribution of the whole must be on the terms of 221 | this License, whose permissions for other licensees extend to the 222 | entire whole, and thus to each and every part regardless of who wrote 223 | it. 224 | 225 | Thus, it is not the intent of this section to claim rights or contest 226 | your rights to work written entirely by you; rather, the intent is to 227 | exercise the right to control the distribution of derivative or 228 | collective works based on the Library. 229 | 230 | In addition, mere aggregation of another work not based on the Library 231 | with the Library (or with a work based on the Library) on a volume of 232 | a storage or distribution medium does not bring the other work under 233 | the scope of this License. 234 | 235 | 3. You may opt to apply the terms of the ordinary GNU General Public 236 | License instead of this License to a given copy of the Library. To do 237 | this, you must alter all the notices that refer to this License, so 238 | that they refer to the ordinary GNU General Public License, version 2, 239 | instead of to this License. (If a newer version than version 2 of the 240 | ordinary GNU General Public License has appeared, then you can specify 241 | that version instead if you wish.) Do not make any other change in 242 | these notices. 243 | 244 | Once this change is made in a given copy, it is irreversible for 245 | that copy, so the ordinary GNU General Public License applies to all 246 | subsequent copies and derivative works made from that copy. 247 | 248 | This option is useful when you wish to copy part of the code of 249 | the Library into a program that is not a library. 250 | 251 | 4. You may copy and distribute the Library (or a portion or 252 | derivative of it, under Section 2) in object code or executable form 253 | under the terms of Sections 1 and 2 above provided that you accompany 254 | it with the complete corresponding machine-readable source code, which 255 | must be distributed under the terms of Sections 1 and 2 above on a 256 | medium customarily used for software interchange. 257 | 258 | If distribution of object code is made by offering access to copy 259 | from a designated place, then offering equivalent access to copy the 260 | source code from the same place satisfies the requirement to 261 | distribute the source code, even though third parties are not 262 | compelled to copy the source along with the object code. 263 | 264 | 5. A program that contains no derivative of any portion of the 265 | Library, but is designed to work with the Library by being compiled or 266 | linked with it, is called a "work that uses the Library". Such a 267 | work, in isolation, is not a derivative work of the Library, and 268 | therefore falls outside the scope of this License. 269 | 270 | However, linking a "work that uses the Library" with the Library 271 | creates an executable that is a derivative of the Library (because it 272 | contains portions of the Library), rather than a "work that uses the 273 | library". The executable is therefore covered by this License. 274 | Section 6 states terms for distribution of such executables. 275 | 276 | When a "work that uses the Library" uses material from a header file 277 | that is part of the Library, the object code for the work may be a 278 | derivative work of the Library even though the source code is not. 279 | Whether this is true is especially significant if the work can be 280 | linked without the Library, or if the work is itself a library. The 281 | threshold for this to be true is not precisely defined by law. 282 | 283 | If such an object file uses only numerical parameters, data 284 | structure layouts and accessors, and small macros and small inline 285 | functions (ten lines or less in length), then the use of the object 286 | file is unrestricted, regardless of whether it is legally a derivative 287 | work. (Executables containing this object code plus portions of the 288 | Library will still fall under Section 6.) 289 | 290 | Otherwise, if the work is a derivative of the Library, you may 291 | distribute the object code for the work under the terms of Section 6. 292 | Any executables containing that work also fall under Section 6, 293 | whether or not they are linked directly with the Library itself. 294 | 295 | 6. As an exception to the Sections above, you may also combine or 296 | link a "work that uses the Library" with the Library to produce a 297 | work containing portions of the Library, and distribute that work 298 | under terms of your choice, provided that the terms permit 299 | modification of the work for the customer's own use and reverse 300 | engineering for debugging such modifications. 301 | 302 | You must give prominent notice with each copy of the work that the 303 | Library is used in it and that the Library and its use are covered by 304 | this License. You must supply a copy of this License. If the work 305 | during execution displays copyright notices, you must include the 306 | copyright notice for the Library among them, as well as a reference 307 | directing the user to the copy of this License. Also, you must do one 308 | of these things: 309 | 310 | a) Accompany the work with the complete corresponding 311 | machine-readable source code for the Library including whatever 312 | changes were used in the work (which must be distributed under 313 | Sections 1 and 2 above); and, if the work is an executable linked 314 | with the Library, with the complete machine-readable "work that 315 | uses the Library", as object code and/or source code, so that the 316 | user can modify the Library and then relink to produce a modified 317 | executable containing the modified Library. (It is understood 318 | that the user who changes the contents of definitions files in the 319 | Library will not necessarily be able to recompile the application 320 | to use the modified definitions.) 321 | 322 | b) Use a suitable shared library mechanism for linking with the 323 | Library. A suitable mechanism is one that (1) uses at run time a 324 | copy of the library already present on the user's computer system, 325 | rather than copying library functions into the executable, and (2) 326 | will operate properly with a modified version of the library, if 327 | the user installs one, as long as the modified version is 328 | interface-compatible with the version that the work was made with. 329 | 330 | c) Accompany the work with a written offer, valid for at least 331 | three years, to give the same user the materials specified in 332 | Subsection 6a, above, for a charge no more than the cost of 333 | performing this distribution. 334 | 335 | d) If distribution of the work is made by offering access to copy 336 | from a designated place, offer equivalent access to copy the above 337 | specified materials from the same place. 338 | 339 | e) Verify that the user has already received a copy of these 340 | materials or that you have already sent this user a copy. 341 | 342 | For an executable, the required form of the "work that uses the 343 | Library" must include any data and utility programs needed for 344 | reproducing the executable from it. However, as a special exception, 345 | the materials to be distributed need not include anything that is 346 | normally distributed (in either source or binary form) with the major 347 | components (compiler, kernel, and so on) of the operating system on 348 | which the executable runs, unless that component itself accompanies 349 | the executable. 350 | 351 | It may happen that this requirement contradicts the license 352 | restrictions of other proprietary libraries that do not normally 353 | accompany the operating system. Such a contradiction means you cannot 354 | use both them and the Library together in an executable that you 355 | distribute. 356 | 357 | 7. You may place library facilities that are a work based on the 358 | Library side-by-side in a single library together with other library 359 | facilities not covered by this License, and distribute such a combined 360 | library, provided that the separate distribution of the work based on 361 | the Library and of the other library facilities is otherwise 362 | permitted, and provided that you do these two things: 363 | 364 | a) Accompany the combined library with a copy of the same work 365 | based on the Library, uncombined with any other library 366 | facilities. This must be distributed under the terms of the 367 | Sections above. 368 | 369 | b) Give prominent notice with the combined library of the fact 370 | that part of it is a work based on the Library, and explaining 371 | where to find the accompanying uncombined form of the same work. 372 | 373 | 8. You may not copy, modify, sublicense, link with, or distribute 374 | the Library except as expressly provided under this License. Any 375 | attempt otherwise to copy, modify, sublicense, link with, or 376 | distribute the Library is void, and will automatically terminate your 377 | rights under this License. However, parties who have received copies, 378 | or rights, from you under this License will not have their licenses 379 | terminated so long as such parties remain in full compliance. 380 | 381 | 9. You are not required to accept this License, since you have not 382 | signed it. However, nothing else grants you permission to modify or 383 | distribute the Library or its derivative works. These actions are 384 | prohibited by law if you do not accept this License. Therefore, by 385 | modifying or distributing the Library (or any work based on the 386 | Library), you indicate your acceptance of this License to do so, and 387 | all its terms and conditions for copying, distributing or modifying 388 | the Library or works based on it. 389 | 390 | 10. Each time you redistribute the Library (or any work based on the 391 | Library), the recipient automatically receives a license from the 392 | original licensor to copy, distribute, link with or modify the Library 393 | subject to these terms and conditions. You may not impose any further 394 | restrictions on the recipients' exercise of the rights granted herein. 395 | You are not responsible for enforcing compliance by third parties with 396 | this License. 397 | 398 | 11. If, as a consequence of a court judgment or allegation of patent 399 | infringement or for any other reason (not limited to patent issues), 400 | conditions are imposed on you (whether by court order, agreement or 401 | otherwise) that contradict the conditions of this License, they do not 402 | excuse you from the conditions of this License. If you cannot 403 | distribute so as to satisfy simultaneously your obligations under this 404 | License and any other pertinent obligations, then as a consequence you 405 | may not distribute the Library at all. For example, if a patent 406 | license would not permit royalty-free redistribution of the Library by 407 | all those who receive copies directly or indirectly through you, then 408 | the only way you could satisfy both it and this License would be to 409 | refrain entirely from distribution of the Library. 410 | 411 | If any portion of this section is held invalid or unenforceable under 412 | any particular circumstance, the balance of the section is intended to 413 | apply, and the section as a whole is intended to apply in other 414 | circumstances. 415 | 416 | It is not the purpose of this section to induce you to infringe any 417 | patents or other property right claims or to contest validity of any 418 | such claims; this section has the sole purpose of protecting the 419 | integrity of the free software distribution system which is 420 | implemented by public license practices. Many people have made 421 | generous contributions to the wide range of software distributed 422 | through that system in reliance on consistent application of that 423 | system; it is up to the author/donor to decide if he or she is willing 424 | to distribute software through any other system and a licensee cannot 425 | impose that choice. 426 | 427 | This section is intended to make thoroughly clear what is believed to 428 | be a consequence of the rest of this License. 429 | 430 | 12. If the distribution and/or use of the Library is restricted in 431 | certain countries either by patents or by copyrighted interfaces, the 432 | original copyright holder who places the Library under this License 433 | may add an explicit geographical distribution limitation excluding those 434 | countries, so that distribution is permitted only in or among 435 | countries not thus excluded. In such case, this License incorporates 436 | the limitation as if written in the body of this License. 437 | 438 | 13. The Free Software Foundation may publish revised and/or new 439 | versions of the Lesser General Public License from time to time. 440 | Such new versions will be similar in spirit to the present version, 441 | but may differ in detail to address new problems or concerns. 442 | 443 | Each version is given a distinguishing version number. If the Library 444 | specifies a version number of this License which applies to it and 445 | "any later version", you have the option of following the terms and 446 | conditions either of that version or of any later version published by 447 | the Free Software Foundation. If the Library does not specify a 448 | license version number, you may choose any version ever published by 449 | the Free Software Foundation. 450 | 451 | 14. If you wish to incorporate parts of the Library into other free 452 | programs whose distribution conditions are incompatible with these, 453 | write to the author to ask for permission. For software which is 454 | copyrighted by the Free Software Foundation, write to the Free 455 | Software Foundation; we sometimes make exceptions for this. Our 456 | decision will be guided by the two goals of preserving the free status 457 | of all derivatives of our free software and of promoting the sharing 458 | and reuse of software generally. 459 | 460 | NO WARRANTY 461 | 462 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 463 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 464 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 465 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 466 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 467 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 468 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 469 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 470 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 471 | 472 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 473 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 474 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 475 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 476 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 477 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 478 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 479 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 480 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 481 | DAMAGES. 482 | 483 | ----- 484 | 485 | Copyright (c) 2000 - 2013 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) 486 | 487 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 488 | software and associated documentation files (the "Software"), to deal in the Software 489 | without restriction, including without limitation the rights to use, copy, modify, 490 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 491 | permit persons to whom the Software is furnished to do so, subject to the following 492 | conditions: 493 | 494 | The above copyright notice and this permission notice shall be included in all copies 495 | or substantial portions of the Software. 496 | 497 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 498 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 499 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 500 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 501 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 502 | DEALINGS IN THE SOFTWARE. 503 | 504 | ----- 505 | 506 | Oracle Binary Code License Agreement for the Java SE Platform Products and JavaFX 507 | 508 | ORACLE AMERICA, INC. ("ORACLE"), FOR AND ON BEHALF OF ITSELF AND ITS SUBSIDIARIES AND AFFILIATES UNDER COMMON CONTROL, IS WILLING TO LICENSE THE SOFTWARE TO YOU ONLY UPON THE CONDITION THAT YOU ACCEPT ALL OF THE TERMS CONTAINED IN THIS BINARY CODE LICENSE AGREEMENT AND SUPPLEMENTAL LICENSE TERMS (COLLECTIVELY "AGREEMENT"). PLEASE READ THE AGREEMENT CAREFULLY. BY SELECTING THE "ACCEPT LICENSE AGREEMENT" (OR THE EQUIVALENT) BUTTON AND/OR BY USING THE SOFTWARE YOU ACKNOWLEDGE THAT YOU HAVE READ THE TERMS AND AGREE TO THEM. IF YOU ARE AGREEING TO THESE TERMS ON BEHALF OF A COMPANY OR OTHER LEGAL ENTITY, YOU REPRESENT THAT YOU HAVE THE LEGAL AUTHORITY TO BIND THE LEGAL ENTITY TO THESE TERMS. IF YOU DO NOT HAVE SUCH AUTHORITY, OR IF YOU DO NOT WISH TO BE BOUND BY THE TERMS, THEN SELECT THE "DECLINE LICENSE AGREEMENT" (OR THE EQUIVALENT) BUTTON AND YOU MUST NOT USE THE SOFTWARE ON THIS SITE OR ANY OTHER MEDIA ON WHICH THE SOFTWARE IS CONTAINED. 509 | 510 | 1. DEFINITIONS. "Software" means the software identified above in binary form that you selected for download, install or use (in the version You selected for download, install or use) from Oracle or its authorized licensees, any other machine readable materials (including, but not limited to, libraries, source files, header files, and data files), any updates or error corrections provided by Oracle, and any user manuals, programming guides and other documentation provided to you by Oracle under this Agreement. "General Purpose Desktop Computers and Servers" means computers, including desktop and laptop computers, or servers, used for general computing functions under end user control (such as but not specifically limited to email, general purpose Internet browsing, and office suite productivity tools). The use of Software in systems and solutions that provide dedicated functionality (other than as mentioned above) or designed for use in embedded or function-specific software applications, for example but not limited to: Software embedded in or bundled with industrial control systems, wireless mobile telephones, wireless handheld devices, kiosks, TV/STB, Blu-ray Disc devices, telematics and network control switching equipment, printers and storage management systems, and other related systems are excluded from this definition and not licensed under this Agreement. "Programs" means (a) Java technology applets and applications intended to run on the Java Platform, Standard Edition platform on Java-enabled General Purpose Desktop Computers and Servers; and (b) JavaFX technology applications intended to run on the JavaFX Runtime on JavaFX-enabled General Purpose Desktop Computers and Servers. ?Commercial Features? means those features identified in Table 1-1 (Commercial Features In Java SE Product Editions) of the Java SE documentation accessible at http://www.oracle.com/technetwork/java/javase/documentation/index.html. ?README File? means the README file for the Software accessible at http://www.oracle.com/technetwork/java/javase/documentation/index.html. 511 | 512 | 2. LICENSE TO USE. Subject to the terms and conditions of this Agreement including, but not limited to, the Java Technology Restrictions of the Supplemental License Terms, Oracle grants you a non-exclusive, non-transferable, limited license without license fees to reproduce and use internally the Software complete and unmodified for the sole purpose of running Programs. THE LICENSE SET FORTH IN THIS SECTION 2 DOES NOT EXTEND TO THE COMMERCIAL FEATURES. YOUR RIGHTS AND OBLIGATIONS RELATED TO THE COMMERCIAL FEATURES ARE AS SET FORTH IN THE SUPPLEMENTAL TERMS ALONG WITH ADDITIONAL LICENSES FOR DEVELOPERS AND PUBLISHERS. 513 | 514 | 3. RESTRICTIONS. Software is copyrighted. Title to Software and all associated intellectual property rights is retained by Oracle and/or its licensors. Unless enforcement is prohibited by applicable law, you may not modify, decompile, or reverse engineer Software. You acknowledge that the Software is developed for general use in a variety of information management applications; it is not developed or intended for use in any inherently dangerous applications, including applications that may create a risk of personal injury. If you use the Software in dangerous applications, then you shall be responsible to take all appropriate fail-safe, backup, redundancy, and other measures to ensure its safe use. Oracle disclaims any express or implied warranty of fitness for such uses. No right, title or interest in or to any trademark, service mark, logo or trade name of Oracle or its licensors is granted under this Agreement. Additional restrictions for developers and/or publishers licenses are set forth in the Supplemental License Terms. 515 | 516 | 4. DISCLAIMER OF WARRANTY. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. ORACLE FURTHER DISCLAIMS ALL WARRANTIES, EXPRESS AND IMPLIED, INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. 517 | 518 | 5. LIMITATION OF LIABILITY. IN NO EVENT SHALL ORACLE BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE OR CONSEQUENTIAL DAMAGES, OR DAMAGES FOR LOSS OF PROFITS, REVENUE, DATA OR DATA USE, INCURRED BY YOU OR ANY THIRD PARTY, WHETHER IN AN ACTION IN CONTRACT OR TORT, EVEN IF ORACLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ORACLE'S ENTIRE LIABILITY FOR DAMAGES HEREUNDER SHALL IN NO EVENT EXCEED ONE THOUSAND DOLLARS (U.S. $1,000). 519 | 520 | 6. TERMINATION. This Agreement is effective until terminated. You may terminate this Agreement at any time by destroying all copies of Software. This Agreement will terminate immediately without notice from Oracle if you fail to comply with any provision of this Agreement. Either party may terminate this Agreement immediately should any Software become, or in either party's opinion be likely to become, the subject of a claim of infringement of any intellectual property right. Upon termination, you must destroy all copies of Software. 521 | 522 | 7. EXPORT REGULATIONS. You agree that U.S. export control laws and other applicable export and import laws govern your use of the Software, including technical data; additional information can be found on Oracle's Global Trade Compliance web site (http://www.oracle.com/us/products/export). You agree that neither the Software nor any direct product thereof will be exported, directly, or indirectly, in violation of these laws, or will be used for any purpose prohibited by these laws including, without limitation, nuclear, chemical, or biological weapons proliferation. 523 | 524 | 8. TRADEMARKS AND LOGOS. You acknowledge and agree as between you 525 | and Oracle that Oracle owns the ORACLE and JAVA trademarks and all ORACLE- and JAVA-related trademarks, service marks, logos and other brand 526 | designations ("Oracle Marks"), and you agree to comply with the Third 527 | Party Usage Guidelines for Oracle Trademarks currently located at 528 | http://www.oracle.com/us/legal/third-party-trademarks/index.html . Any use you make of the Oracle Marks inures to Oracle's benefit. 529 | 530 | 9. U.S. GOVERNMENT LICENSE RIGHTS. If Software is being acquired by or on behalf of the U.S. Government or by a U.S. Government prime contractor or subcontractor (at any tier), then the Government's rights in Software and accompanying documentation shall be only those set forth in this Agreement. 531 | 532 | 10. GOVERNING LAW. This agreement is governed by the substantive and procedural laws of California. You and Oracle agree to submit to the exclusive jurisdiction of, and venue in, the courts of San Francisco, or Santa Clara counties in California in any dispute arising out of or relating to this agreement. 533 | 534 | 11. SEVERABILITY. If any provision of this Agreement is held to be unenforceable, this Agreement will remain in effect with the provision omitted, unless omission would frustrate the intent of the parties, in which case this Agreement will immediately terminate. 535 | 536 | 12. INTEGRATION. This Agreement is the entire agreement between you and Oracle relating to its subject matter. It supersedes all prior or contemporaneous oral or written communications, proposals, representations and warranties and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement. No modification of this Agreement will be binding, unless in writing and signed by an authorized representative of each party. 537 | 538 | SUPPLEMENTAL LICENSE TERMS 539 | 540 | These Supplemental License Terms add to or modify the terms of the Binary Code License Agreement. Capitalized terms not defined in these Supplemental Terms shall have the same meanings ascribed to them in the Binary Code License Agreement. These Supplemental Terms shall supersede any inconsistent or conflicting terms in the Binary Code License Agreement, or in any license contained within the Software. 541 | 542 | A. COMMERCIAL FEATURES. You may not use the Commercial Features for running Programs, Java applets or applications in your internal business operations or for any commercial or production purpose, or for any purpose other than as set forth in Sections B, C, D and E of these Supplemental Terms. If You want to use the Commercial Features for any purpose other than as permitted in this Agreement, You must obtain a separate license from Oracle. 543 | 544 | B. SOFTWARE INTERNAL USE FOR DEVELOPMENT LICENSE GRANT. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the README File incorporated herein by reference, including, but not limited to the Java Technology Restrictions of these Supplemental Terms, Oracle grants you a non-exclusive, non-transferable, limited license without fees to reproduce internally and use internally the Software complete and unmodified for the purpose of designing, developing, and testing your Programs. 545 | 546 | C. LICENSE TO DISTRIBUTE SOFTWARE. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the README File, including, but not limited to the Java Technology Restrictions and Limitations on Redistribution of these Supplemental Terms, Oracle grants you a non-exclusive, non-transferable, limited license without fees to reproduce and distribute the Software, provided that (i) you distribute the Software complete and unmodified and only bundled as part of, and for the sole purpose of running, your Programs, (ii) the Programs add significant and primary functionality to the Software, (iii) you do not distribute additional software intended to replace any component(s) of the Software, (iv) you do not remove or alter any proprietary legends or notices contained in the Software, (v) you only distribute the Software subject to a license agreement that: (a) is a complete, unmodified reproduction of this Agreement; or (b) protects Oracle's interests consistent with the terms contained in this Agreement and that includes the notice set forth in Section H, and (vi) you agree to defend and indemnify Oracle and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that arises or results from the use or distribution of any and all Programs and/or Software. The license set forth in this Section C does not extend to the Software identified in Section G. 547 | 548 | D. LICENSE TO DISTRIBUTE REDISTRIBUTABLES. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the README File, including but not limited to the Java Technology Restrictions and Limitations on Redistribution of these Supplemental Terms, Oracle grants you a non-exclusive, non-transferable, limited license without fees to reproduce and distribute those files specifically identified as redistributable in the README File ("Redistributables") provided that: (i) you distribute the Redistributables complete and unmodified, and only bundled as part of Programs, (ii) the Programs add significant and primary functionality to the Redistributables, (iii) you do not distribute additional software intended to supersede any component(s) of the Redistributables (unless otherwise specified in the applicable README File), (iv) you do not remove or alter any proprietary legends or notices contained in or on the Redistributables, (v) you only distribute the Redistributables pursuant to a license agreement that: (a) is a complete, unmodified reproduction of this Agreement; or (b) protects Oracle's interests consistent with the terms contained in the Agreement and includes the notice set forth in Section H, (vi) you agree to defend and indemnify Oracle and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that arises or results from the use or distribution of any and all Programs and/or Software. The license set forth in this Section D does not extend to the Software identified in Section G. 549 | 550 | E. DISTRIBUTION BY PUBLISHERS. This section pertains to your distribution of the JavaTM SE Development Kit Software (?JDK?) with your printed book or magazine (as those terms are commonly used in the industry) relating to Java technology ("Publication"). Subject to and conditioned upon your compliance with the restrictions and obligations contained in the Agreement, Oracle hereby grants to you a non-exclusive, nontransferable limited right to reproduce complete and unmodified copies of the JDK on electronic media (the "Media") for the sole purpose of inclusion and distribution with your Publication(s), subject to the following terms: (i) You may not distribute the JDK on a stand-alone basis; it must be distributed with your Publication(s); (ii) You are responsible for downloading the JDK from the applicable Oracle web site; (iii) You must refer to the JDK as JavaTM SE Development Kit; (iv) The JDK must be reproduced in its entirety and without any modification whatsoever (including with respect to all proprietary notices) and distributed with your Publication subject to a license agreement that is a complete, unmodified reproduction of this Agreement; (v) The Media label shall include the following information: ?Copyright [YEAR], Oracle America, Inc. All rights reserved. Use is subject to license terms. ORACLE and JAVA trademarks and all ORACLE- and JAVA-related trademarks, service marks, logos and other brand designations are trademarks or registered trademarks of Oracle in the U.S. and other countries.? [YEAR] is the year of Oracle's release of the Software; the year information can typically be found in the Software?s ?About? box or screen. This information must be placed on the Media label in such a manner as to only apply to the JDK; (vi) You must clearly identify the JDK as Oracle's product on the Media holder or Media label, and you may not state or imply that Oracle is responsible for any third-party software contained on the Media; (vii) You may not include any third party software on the Media which is intended to be a replacement or substitute for the JDK; (viii) You agree to defend and indemnify Oracle and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that arises or results from the use or distribution of the JDK and/or the Publication; ; and (ix) You shall provide Oracle with a written notice for each Publication; such notice shall include the following information: (1) title of Publication, (2) author(s), (3) date of Publication, and (4) ISBN or ISSN numbers. Such notice shall be sent to Oracle America, Inc., 500 Oracle Parkway, Redwood Shores, California 94065 U.S.A , Attention: General Counsel. 551 | 552 | F. JAVA TECHNOLOGY RESTRICTIONS. You may not create, modify, or change the behavior of, or authorize your licensees to create, modify, or change the behavior of, classes, interfaces, or subpackages that are in any way identified as "java", "javax", "sun", ?oracle? or similar convention as specified by Oracle in any naming convention designation. 553 | 554 | G. LIMITATIONS ON REDISTRIBUTION. You may not redistribute or otherwise transfer patches, bug fixes or updates made available by Oracle through Oracle Premier Support, including those made available under Oracle's Java SE Support program. 555 | 556 | H. COMMERCIAL FEATURES NOTICE. For purpose of complying with Supplemental Term Section C.(v)(b) and D.(v)(b), your license agreement shall include the following notice, where the notice is displayed in a manner that anyone using the Software will see the notice: 557 | 558 | Use of the Commercial Features for any commercial or production purpose requires a separate license from Oracle. ?Commercial Features? means those features identified Table 1-1 (Commercial Features In Java SE Product Editions) of the Java SE documentation accessible at http://www.oracle.com/technetwork/java/javase/documentation/index.html 559 | 560 | 561 | 562 | I. SOURCE CODE. Software may contain source code that, unless expressly licensed for other purposes, is provided solely for reference purposes pursuant to the terms of this Agreement. Source code may not be redistributed unless expressly provided for in this Agreement. 563 | 564 | J. THIRD PARTY CODE. Additional copyright notices and license terms applicable to portions of the Software are set forth in the THIRDPARTYLICENSEREADME file accessible at http://www.oracle.com/technetwork/java/javase/documentation/index.html. In addition to any terms and conditions of any third party opensource/freeware license identified in the THIRDPARTYLICENSEREADME file, the disclaimer of warranty and limitation of liability provisions in paragraphs 4 and 5 of the Binary Code License Agreement shall apply to all Software in this distribution. 565 | 566 | K. TERMINATION FOR INFRINGEMENT. Either party may terminate this Agreement immediately should any Software become, or in either party's opinion be likely to become, the subject of a claim of infringement of any intellectual property right. 567 | 568 | L. INSTALLATION AND AUTO-UPDATE. The Software's installation and auto-update processes transmit a limited amount of data to Oracle (or its service provider) about those specific processes to help Oracle understand and optimize them. Oracle does not associate the data with personally identifiable information. You can find more information about the data Oracle collects as a result of your Software download at http://www.oracle.com/technetwork/java/javase/documentation/index.html. 569 | 570 | For inquiries please contact: Oracle America, Inc., 500 Oracle Parkway, 571 | 572 | Redwood Shores, California 94065, USA. 573 | 574 | Last updated 02 April 2013 575 | 576 | 577 | ----- 578 | 579 | Inno Setup License 580 | ================== 581 | 582 | Except where otherwise noted, all of the documentation and software included 583 | in the Inno Setup package is copyrighted by Jordan Russell. 584 | 585 | Copyright (C) 1997-2013 Jordan Russell. All rights reserved. 586 | Portions Copyright (C) 2000-2013 Martijn Laan. All rights reserved. 587 | 588 | This software is provided "as-is," without any express or implied warranty. 589 | In no event shall the author be held liable for any damages arising from the 590 | use of this software. 591 | 592 | Permission is granted to anyone to use this software for any purpose, 593 | including commercial applications, and to alter and redistribute it, 594 | provided that the following conditions are met: 595 | 596 | 1. All redistributions of source code files must retain all copyright 597 | notices that are currently in place, and this list of conditions without 598 | modification. 599 | 600 | 2. All redistributions in binary form must retain all occurrences of the 601 | above copyright notice and web site addresses that are currently in 602 | place (for example, in the About boxes). 603 | 604 | 3. The origin of this software must not be misrepresented; you must not 605 | claim that you wrote the original software. If you use this software to 606 | distribute a product, an acknowledgment in the product documentation 607 | would be appreciated but is not required. 608 | 609 | 4. Modified versions in source or binary form must be plainly marked as 610 | such, and must not be misrepresented as being the original software. 611 | 612 | 613 | Jordan Russell 614 | jr-2010 AT jrsoftware.org 615 | http://www.jrsoftware.org/ 616 | 617 | 618 | ----- 619 | 620 | Copyright 2015 General Services Administration (GSA) 621 | 622 | Licensed under the Apache License, Version 2.0 (the "License"); 623 | you may not use this file except in compliance with the License. 624 | You may obtain a copy of the License at 625 | 626 | http://www.apache.org/licenses/LICENSE-2.0 627 | 628 | Unless required by applicable law or agreed to in writing, software 629 | distributed under the License is distributed on an "AS IS" BASIS, 630 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 631 | See the License for the specific language governing permissions and 632 | limitations under the License. -------------------------------------------------------------------------------- /apple/OpenSC/lib/libopensc.3.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/OpenSC/lib/libopensc.3.dylib -------------------------------------------------------------------------------- /apple/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | This repo contains the General Services Administration (GSA) Document Signing tools used for digitally signing documents and files with Personal Identity Verification (PIV) cards. The main purpose of the tool is for Federal agencies to use for digitally signing documents to be submitted to the Office of the Federal Register's (OFR) document submission web portal. The tool was developed using Java 8. It relies on Bouncy Castle libraries for the signing operations, Apache Commons for file operations, and OpenSC for PIV operations. 3 | 4 | ### How does it work? 5 | The GSA Document Signing Tool includes a simple, 508-compliant Graphical User Interface (GUI) to assist in the signing of your desired document. The tool allows the user to select the desired file they'd like signed, a field to enter the user's PIV application PIN , and a "Sign" button to initiate the signing. The tool automatically detects any smart card readers and PIV cards connected to the system. The tool utilizes PKCS#11 to interact with the reader and PIV card. The signed file is formatted in an enveloped PKCS#7 (.p7m) file, which is the required format for the OFR's document submission portal. In order for the tool to sign correctly, the PIV card MUST contain a valid digital signing certificate (i.e. Key usage of Digital Signature and Non-repudiation). If it doesn't contain a valid digital signing certificate, the application will provide a descriptive error messages. 6 | 7 | ### Installation/Usage Instructions 8 | 9 | The GSA Document Signing Tool includes a Windows 32-bit, 64-bit, and MacOS version. Verify your system's operating system before installing. Use the following User Guides below for guiding you through the installation process: 10 | 11 | * Windows Installation Guide - https://github.com/GSA/gsa-doc-digital-signature/blob/platforms/microsoft/GSA_Signing_Tool_User_Guide-64bit.pdf 12 | * MacOS Installation Guides - https://github.com/GSA/gsa-doc-digital-signature/blob/platforms/apple/GSA_Signing_Tool_User_Guide-Mac.pdf 13 | 14 | ### Developer Install Instructions 15 | 16 | For developers, the source code, 3rd party libraries, and drivers can be imported into a Java IDE (i.e. Eclipse, NetBeans). 17 | 18 | **NOTE:** This tool will only compile correctly using Java 8. Lower Java versions are not compatible with the development of this tool. 19 | 20 | Initial setup: 21 | * Import initial source code in the "/src" directory to your Java IDE project source code directory. 22 | * Add the specific OpenSC driver for the system type you will be developing for (i.e. if you are developing on a 64-bit system, copy the opensc driver in the 64-bit directory, and paste the driver in the "lib" directory with the Bouncy Castle libraries. 23 | * Import "lib" directory to your Java IDE project. 24 | * Use the "GUI" class, as your main executable class for executing the tool. 25 | 26 | ### Dependencies 27 | 28 | The GSA Document Signing Tool leverages 3rd party libraries including: 29 | * [Oracle Java] http://www.oracle.com/ 30 | * [Bouncy Castle] https://www.bouncycastle.org/ 31 | * [opensc] https://github.com/OpenSC/OpenSC 32 | * [commons-io] http://commons.apache.org/proper/commons-io/ 33 | 34 | The tool has not been tested with alternate versions of Java such as OpenJDK. Contributors are welcome to determine compatibility and update this README and dependencies appropriately. 35 | 36 | On Windows, the installer was built using [inno setup] http://www.jrsoftware.org/ 37 | 38 | ### License 39 | This project is in the public domain within the United States. 40 | 41 | We waive copyright and related rights in the work worldwide through the CC0 1.0 Universal public domain dedication. 42 | 43 | Please review the License found in this repository. 44 | 45 | ### Contact Information 46 | 47 | For issues, please open an Issue in this repository. Contact icam at gsa.gov for any additional questions on contributing. -------------------------------------------------------------------------------- /apple/drivers/opensc-pkcs11.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/drivers/opensc-pkcs11.so -------------------------------------------------------------------------------- /apple/lib/bcmail-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/lib/bcmail-jdk15on-152.jar -------------------------------------------------------------------------------- /apple/lib/bcpg-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/lib/bcpg-jdk15on-152.jar -------------------------------------------------------------------------------- /apple/lib/bcpkix-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/lib/bcpkix-jdk15on-152.jar -------------------------------------------------------------------------------- /apple/lib/bcprov-ext-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/lib/bcprov-ext-jdk15on-152.jar -------------------------------------------------------------------------------- /apple/lib/bcprov-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/lib/bcprov-jdk15on-152.jar -------------------------------------------------------------------------------- /apple/lib/commons-io-2.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/lib/commons-io-2.4.jar -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/CheckRevocationStatus.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.net.URI; 7 | import java.net.URL; 8 | import java.security.cert.CertificateFactory; 9 | import java.security.cert.X509Certificate; 10 | import java.util.ArrayList; 11 | import java.util.Date; 12 | import java.util.Iterator; 13 | import java.util.logging.Level; 14 | import org.bouncycastle.asn1.ASN1InputStream; 15 | import org.bouncycastle.asn1.ASN1Primitive; 16 | import org.bouncycastle.asn1.ASN1Sequence; 17 | import org.bouncycastle.asn1.DERIA5String; 18 | import org.bouncycastle.asn1.DEROctetString; 19 | import org.bouncycastle.asn1.x509.AccessDescription; 20 | import org.bouncycastle.asn1.x509.AuthorityInformationAccess; 21 | import org.bouncycastle.asn1.x509.GeneralName; 22 | import static com.gsa.signingtool.app.Gui.dateFormat; 23 | import sun.security.provider.certpath.OCSP; 24 | 25 | public class CheckRevocationStatus { 26 | public static X509Certificate fetchIssuerCert(X509Certificate cert) { 27 | AuthorityInformationAccess authInfoAcc = null; 28 | AuthorityInformationAccess access = null; 29 | URI responderURI = null; 30 | X509Certificate issuerCert = null; 31 | String serviceAddr=null; 32 | ArrayList issuingCerts = new ArrayList(); 33 | X509Certificate exactIssuerCert = null; 34 | boolean issuerMatch = false; 35 | File issuerChain = null; 36 | 37 | //Get issuer certificate from the path to use for OCSP and 38 | //validating the end entity 39 | try { 40 | Gui.logger.info("Trying to create new file to store issuer p7c file"); 41 | String issuerChainPath = new File("").getAbsolutePath() 42 | + "/logs/issuer.p7b"; 43 | issuerChain = new File(issuerChainPath); 44 | Gui.logger.info("Successfully created issuer file: " 45 | + issuerChain.getAbsolutePath()); 46 | } catch (Exception e) { 47 | Gui.logger.severe("Error creating issuer p7b file"); 48 | Gui.logger.log(Level.FINEST, e.getMessage(), e); 49 | } 50 | try { 51 | Gui.logger.info("Trying to get AiA from end-entity certificate"); 52 | byte[] extensionValue = 53 | ((X509Certificate)cert).getExtensionValue("1.3.6.1.5.5.7.1.1"); 54 | DEROctetString string = 55 | (DEROctetString) 56 | (new ASN1InputStream(new ByteArrayInputStream(extensionValue)).readObject()); 57 | ASN1Sequence seq = 58 | ASN1Sequence.getInstance( 59 | ASN1Primitive.fromByteArray(DEROctetString.getInstance(string).getOctets())); 60 | access = 61 | AuthorityInformationAccess.getInstance(seq); 62 | Gui.logger.info("Successfully retrieved AiA instances"); 63 | } catch (Exception e) { 64 | Gui.logger.severe("Issue getting AiA instances"); 65 | Gui.logger.log(Level.FINEST, e.getMessage(), e); 66 | } 67 | 68 | try { 69 | Gui.logger.info("Setting the accessDescriptions"); 70 | AccessDescription[] accessDescriptions = 71 | access.getAccessDescriptions(); 72 | Gui.logger.info("Looping through the accessDescriptions to get the different end-points"); 73 | for (AccessDescription accessDescription : accessDescriptions) { 74 | GeneralName gn = accessDescription.getAccessLocation(); 75 | if(gn.getTagNo() == GeneralName.uniformResourceIdentifier) { 76 | DERIA5String str = DERIA5String.getInstance(gn.getName()); 77 | String accessLocation = str.getString(); 78 | serviceAddr = accessLocation; 79 | if (serviceAddr.toLowerCase().startsWith("http") 80 | && serviceAddr.toLowerCase().endsWith(".p7c") 81 | || serviceAddr.toLowerCase().endsWith(".p7b")) { 82 | try { 83 | Gui.logger.info("Setting the p7c URL"); 84 | URL url = new URL(serviceAddr); 85 | Gui.logger.info("Downloading the issuer cert p7c file"); 86 | org.apache.commons.io.FileUtils.copyURLToFile(url, issuerChain); 87 | Gui.logger.info("Saving the issuer cert p7c file"); 88 | FileInputStream fis = new FileInputStream(issuerChain); 89 | Gui.logger.info("File location: " 90 | + issuerChain.getAbsolutePath()); 91 | Gui.logger.info("Generating a new certificate to store issuer cert "); 92 | CertificateFactory cf = CertificateFactory.getInstance("x.509"); 93 | Iterator iter = cf.generateCertificates(fis).iterator(); 94 | Gui.logger.info("Iterating through the p7c file"); 95 | while (iter.hasNext()) { 96 | issuerCert = (X509Certificate)iter.next(); 97 | issuingCerts.add(issuerCert); 98 | Gui.logger.info("Seeing if their is a match between " 99 | + "the end-entity issuerDN and certificates in p7c file subjectDN"); 100 | if (issuerCert.getSubjectDN().equals(cert.getIssuerDN())) { 101 | issuerMatch = true; 102 | Gui.logger.info("Found a match! The issuer of" 103 | + " the end-entity cert's serial number is: " 104 | + issuerCert.getSerialNumber()); 105 | exactIssuerCert = issuerCert; 106 | } 107 | } 108 | if (issuerMatch = false) { 109 | Gui.logger.severe("Unable to check revocation " 110 | + "status. Issue finding issuer cert"); 111 | return null; 112 | } 113 | } catch (Exception e) { 114 | Gui.logger.log(Level.FINEST, e.getMessage(), e); 115 | } 116 | } 117 | } 118 | Gui.logger.info("AiA length: " + accessDescriptions.length); 119 | } 120 | } catch (Exception e) { 121 | Gui.logger.severe("Issue with obtaining issuer cert"); 122 | Gui.logger.log(Level.FINEST, e.getMessage(), e); 123 | } 124 | Gui.logger.info("Returning the cert with the following serial #: " 125 | + exactIssuerCert.getSerialNumber()); 126 | return exactIssuerCert; 127 | } 128 | 129 | public static String checkRevocation(X509Certificate end, X509Certificate issuer) { 130 | String revocationStatus = null; 131 | try { 132 | Gui.logger.info("Checking the revocation status"); 133 | revocationStatus = OCSP.check(end, issuer).getCertStatus().toString(); 134 | Gui.logger.info("Revocation Status is: " 135 | + revocationStatus); 136 | } catch (Exception ex) { 137 | if (SigningTool.expired == true) { 138 | Gui.status.append(dateFormat.format(new Date()) 139 | + " - Unable to sign. Revocation Status returned an error.\n" 140 | + dateFormat.format(new Date()) 141 | + " - The signing certificate is expired.\n" 142 | + dateFormat.format(new Date()) 143 | + " - Expiration Date: " 144 | + end.getNotAfter().toString() 145 | + "\n"); 146 | System.out.println("Unable to sign. The signing certificate is " 147 | + "expired. Also, unable revocation status returned an error."); 148 | Gui.logger.log(Level.FINEST, ex.getMessage(), ex); 149 | return null; 150 | } else { 151 | Gui.status.append(dateFormat.format(new Date()) 152 | + " - Unable to get revocation status.\n "); 153 | System.out.println("Unable to sign. The revocation check for " 154 | + "your signing cert failed. If you believe this is in " 155 | + "err, disable revocation checking in the menu."); 156 | Gui.logger.log(Level.FINEST, ex.getMessage(), ex); 157 | return null; 158 | } 159 | 160 | } 161 | Gui.logger.finest("Returning the following revocation status: " 162 | + revocationStatus); 163 | return revocationStatus; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/Gui.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Component; 5 | import java.awt.event.ActionEvent; 6 | import java.awt.event.ActionListener; 7 | import java.awt.event.WindowAdapter; 8 | import java.awt.event.WindowEvent; 9 | import java.util.List; 10 | import java.io.File; 11 | import java.text.DateFormat; 12 | import java.text.SimpleDateFormat; 13 | import java.util.Date; 14 | import java.util.logging.FileHandler; 15 | import java.util.logging.Level; 16 | import java.util.logging.Logger; 17 | import java.util.logging.SimpleFormatter; 18 | import javax.swing.GroupLayout; 19 | import javax.swing.ImageIcon; 20 | import javax.swing.JFileChooser; 21 | import javax.swing.JFrame; 22 | import javax.swing.JOptionPane; 23 | import javax.swing.JPanel; 24 | import javax.swing.JProgressBar; 25 | import javax.swing.SwingUtilities; 26 | import javax.swing.SwingWorker; 27 | 28 | public class Gui { 29 | protected static JFrame frame = new JFrame("GSA Document Signing Tool 2.0"); 30 | protected static Logger logger = Logger.getAnonymousLogger(); 31 | protected static String revocationStatus = "Not Checked"; 32 | protected static String serialNum = null; 33 | protected static String notAfterDate = null; 34 | protected File file = null; 35 | protected SigningTool pkcs7sign = null; 36 | protected SigningToolVerifier pkcs7unpack = null; 37 | protected static DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 38 | protected static Date date = new Date(); 39 | protected static DateFormat logDate = new SimpleDateFormat("yyyy-MM-dd"); 40 | protected static int counter = 0; 41 | protected JFileChooser fileChooser = new JFileChooser(); 42 | protected static boolean errors = false; 43 | private volatile boolean done = false; 44 | protected static int progressValue = 0; 45 | protected static SwingWorker worker; 46 | protected static FileHandler fh; 47 | 48 | private javax.swing.JButton browseButton; 49 | private javax.swing.JMenuItem closeApp; 50 | private javax.swing.JLabel fileDestLabel; 51 | private javax.swing.JTextField fileDestination; 52 | private javax.swing.JTextField fileInput; 53 | private javax.swing.JMenu fileMenu; 54 | private javax.swing.JMenu helpMenu; 55 | private javax.swing.JMenuBar menuBar; 56 | private javax.swing.JMenuItem aboutMenu; 57 | private javax.swing.JScrollPane statusScrollPane; 58 | private javax.swing.JMenu menuFile; 59 | private javax.swing.JMenuItem openFile; 60 | private javax.swing.JMenu optionsMenu; 61 | private javax.swing.JPasswordField pin; 62 | private javax.swing.JLabel pinLabel; 63 | protected static javax.swing.JProgressBar progress; 64 | protected static javax.swing.JCheckBoxMenuItem revocationCheckBox; 65 | protected javax.swing.JButton signButton; 66 | protected javax.swing.JButton verifyButton; 67 | protected static javax.swing.JTextArea status; 68 | private javax.swing.JLabel statusLabel; 69 | private GroupLayout layout; 70 | private JPanel pane; 71 | 72 | 73 | public Component createComponents(JFrame frame) { 74 | 75 | menuBar = new javax.swing.JMenuBar(); 76 | fileMenu = new javax.swing.JMenu(); 77 | browseButton = new javax.swing.JButton(); 78 | fileInput = new javax.swing.JTextField(); 79 | fileDestLabel = new javax.swing.JLabel(); 80 | fileDestination = new javax.swing.JTextField(); 81 | signButton = new javax.swing.JButton(); 82 | verifyButton = new javax.swing.JButton(); 83 | statusLabel = new javax.swing.JLabel(); 84 | statusScrollPane = new javax.swing.JScrollPane(); 85 | status = new javax.swing.JTextArea(); 86 | pin = new javax.swing.JPasswordField(); 87 | pinLabel = new javax.swing.JLabel(); 88 | progress = new javax.swing.JProgressBar(); 89 | menuBar = new javax.swing.JMenuBar(); 90 | menuFile = new javax.swing.JMenu(); 91 | openFile = new javax.swing.JMenuItem(); 92 | closeApp = new javax.swing.JMenuItem(); 93 | optionsMenu = new javax.swing.JMenu(); 94 | revocationCheckBox = new javax.swing.JCheckBoxMenuItem(); 95 | helpMenu = new javax.swing.JMenu(); 96 | aboutMenu = new javax.swing.JMenuItem(); 97 | pane = new JPanel(); 98 | layout = new GroupLayout(pane); 99 | 100 | // Settings for progress status bar 101 | progress.setIndeterminate(false); 102 | progress.setStringPainted(true); 103 | 104 | browseButton.setMnemonic('o'); 105 | browseButton.setText("Open"); 106 | browseButton.setToolTipText("Click to select a file to sign"); 107 | browseButton.addActionListener(new java.awt.event.ActionListener() { 108 | public void actionPerformed(java.awt.event.ActionEvent evt) { 109 | browseButtonActionPerformed(evt); 110 | } 111 | }); 112 | 113 | fileInput.setEditable(false); 114 | fileInput.setText("Please select a file to sign or unpack"); 115 | fileInput.setToolTipText("Click the open button to select a file"); 116 | 117 | fileDestLabel.setText("File Destination:"); 118 | fileDestLabel.setToolTipText("File Destination:"); 119 | 120 | fileDestination.setEditable(false); 121 | fileDestination.setText("No file selected"); 122 | fileDestination.setToolTipText("This is the file destination of the file you would like signed or unpacked."); 123 | 124 | signButton.setMnemonic('s'); 125 | signButton.setText("Sign"); 126 | signButton.setToolTipText("Click to sign file selected"); 127 | signButton.addActionListener(new ActionListener() { 128 | @Override 129 | public void actionPerformed(ActionEvent e) { 130 | progress.setValue(0); 131 | status.setText(dateFormat.format(new Date()) + " - Applying Signature\n"); 132 | progress.setValue(8); 133 | worker = createWorker(status, progress); 134 | worker.execute(); 135 | } 136 | }); 137 | 138 | verifyButton.setMnemonic('u'); 139 | verifyButton.setText("Unpack"); 140 | verifyButton.setToolTipText("Click to unpack file selected"); 141 | verifyButton.addActionListener(new ActionListener() { 142 | @Override 143 | public void actionPerformed(ActionEvent e) { 144 | progress.setValue(0); 145 | status.setText(dateFormat.format(new Date()) + " - Unpacking File\n"); 146 | progress.setValue(8); 147 | worker = createVerifyWorker(status, progress); 148 | worker.execute(); 149 | } 150 | }); 151 | 152 | statusLabel.setText("Status:"); 153 | 154 | status.setEditable(false); 155 | status.setColumns(20); 156 | status.setFont(new java.awt.Font("Tahoma", 0, 11)); 157 | status.setRows(5); 158 | status.setAutoscrolls(false); 159 | status.setText(dateFormat.format(date) 160 | + " - Select a file, enter your PIN #, and then Click the Sign button.\n"); 161 | 162 | statusScrollPane.setViewportView(status); 163 | 164 | pin.setToolTipText("Please Enter your card's PIN Number"); 165 | pin.setName("pin"); // NOI18N 166 | 167 | pinLabel.setText("Enter PIN:"); 168 | pinLabel.setToolTipText("Enter PIN Label"); 169 | 170 | menuFile.setMnemonic('f'); 171 | menuFile.setText("File"); 172 | 173 | openFile.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK)); 174 | openFile.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/gsa/signingtool/app/images/open.png"))); // NOI18N 175 | openFile.setMnemonic('o'); 176 | openFile.setText("Open"); 177 | openFile.setToolTipText("Open a file to sign"); 178 | openFile.setInheritsPopupMenu(true); 179 | openFile.addActionListener(new java.awt.event.ActionListener() { 180 | public void actionPerformed(java.awt.event.ActionEvent evt) { 181 | openFileActionPerformed(evt); 182 | } 183 | }); 184 | menuFile.add(openFile); 185 | 186 | closeApp.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_MASK)); 187 | closeApp.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/gsa/signingtool/app/images/close.png"))); 188 | closeApp.setText("Close"); 189 | closeApp.setToolTipText("Close Application"); 190 | closeApp.addActionListener(new java.awt.event.ActionListener() { 191 | public void actionPerformed(java.awt.event.ActionEvent evt) { 192 | System.exit(0); 193 | } 194 | }); 195 | menuFile.add(closeApp); 196 | closeApp.getAccessibleContext().setAccessibleParent(menuBar); 197 | 198 | optionsMenu.setMnemonic('p'); 199 | optionsMenu.setText("Options"); 200 | optionsMenu.setToolTipText("Options Menu Item"); 201 | revocationCheckBox.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_E, java.awt.event.InputEvent.CTRL_MASK)); 202 | revocationCheckBox.setSelected(true); 203 | revocationCheckBox.setText("Enable Revocation Checking"); 204 | revocationCheckBox.setToolTipText("Click to toggle revocation checking"); 205 | optionsMenu.add(revocationCheckBox); 206 | 207 | helpMenu.setMnemonic('h'); 208 | helpMenu.setText("Help"); 209 | helpMenu.setToolTipText("Help Menu Item"); 210 | 211 | aboutMenu.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.CTRL_MASK)); 212 | aboutMenu.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/gsa/signingtool/app/images/info.png"))); // NOI18N 213 | aboutMenu.setText("About"); 214 | aboutMenu.addActionListener(new java.awt.event.ActionListener() { 215 | public void actionPerformed(java.awt.event.ActionEvent evt) { 216 | aboutMenuActionPerformed(evt); 217 | } 218 | }); 219 | helpMenu.add(aboutMenu); 220 | 221 | 222 | // add menuBar items and menuBar to the frame 223 | menuBar.add(menuFile); 224 | menuBar.add(optionsMenu); 225 | menuBar.add(helpMenu); 226 | 227 | frame.setJMenuBar(menuBar); 228 | 229 | browseButton.getAccessibleContext().setAccessibleName("Open Button"); 230 | browseButton.getAccessibleContext().setAccessibleDescription("Click button to open a file to sign"); 231 | browseButton.getAccessibleContext().setAccessibleParent(frame); 232 | fileInput.getAccessibleContext().setAccessibleName("File selected"); 233 | fileInput.getAccessibleContext().setAccessibleDescription("Please select a file to sign"); 234 | fileInput.getAccessibleContext().setAccessibleParent(frame); 235 | fileDestLabel.getAccessibleContext().setAccessibleParent(frame); 236 | fileDestination.getAccessibleContext().setAccessibleName("File Destination"); 237 | signButton.getAccessibleContext().setAccessibleName("Sign Button"); 238 | signButton.getAccessibleContext().setAccessibleDescription("Click button to sign a file"); 239 | signButton.getAccessibleContext().setAccessibleParent(frame); 240 | verifyButton.getAccessibleContext().setAccessibleDescription("Click button to unpack a file"); 241 | verifyButton.getAccessibleContext().setAccessibleName("Unpack Button"); 242 | verifyButton.getAccessibleContext().setAccessibleParent(frame); 243 | pin.getAccessibleContext().setAccessibleName("PIN Number"); 244 | pin.getAccessibleContext().setAccessibleDescription("Text field for entering your PIN Number"); 245 | pin.getAccessibleContext().setAccessibleParent(frame); 246 | pinLabel.getAccessibleContext().setAccessibleName("PIN Label"); 247 | pinLabel.getAccessibleContext().setAccessibleParent(frame); 248 | status.getAccessibleContext().setAccessibleName("Status"); 249 | status.getAccessibleContext().setAccessibleParent(frame); 250 | status.getAccessibleContext().setAccessibleDescription("Scroll pane that shows the status of the signing tool"); 251 | 252 | // Set application default parameters 253 | frame.getAccessibleContext().setAccessibleDescription("GSA PKCS#7 Signing Tool"); 254 | frame.setIconImage(new ImageIcon(getClass().getResource("/com/gsa/signingtool/app/images/icon.png")).getImage()); 255 | 256 | pane.setLayout(layout); 257 | layout.setHorizontalGroup( 258 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 259 | .addGroup(layout.createSequentialGroup() 260 | .addGap(18, 18, 18) 261 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) 262 | .addComponent(signButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 263 | .addComponent(verifyButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 264 | .addComponent(fileDestLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 265 | .addComponent(statusLabel, javax.swing.GroupLayout.Alignment.TRAILING) 266 | .addComponent(pinLabel, javax.swing.GroupLayout.Alignment.TRAILING) 267 | .addComponent(browseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE)) 268 | .addGap(18, 18, 18) 269 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 270 | .addComponent(progress, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE) 271 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) 272 | .addComponent(pin, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) 273 | .addComponent(fileInput) 274 | .addComponent(fileDestination, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE)) 275 | .addComponent(statusScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE)) 276 | .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 277 | ); 278 | 279 | layout.setVerticalGroup( 280 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 281 | .addGroup(layout.createSequentialGroup() 282 | .addContainerGap() 283 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 284 | .addComponent(fileInput, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 285 | .addComponent(browseButton)) 286 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 287 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 288 | .addComponent(fileDestLabel) 289 | .addComponent(fileDestination, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) 290 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 291 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 292 | .addComponent(pinLabel) 293 | .addComponent(pin, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) 294 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 295 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 296 | .addComponent(statusLabel) 297 | .addComponent(progress, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) 298 | .addGap(18, 18, 18) 299 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 300 | .addGroup(layout.createSequentialGroup() 301 | .addComponent(signButton) 302 | .addGap(18,18,18) 303 | .addComponent(verifyButton) 304 | .addGap(0, 0, Short.MAX_VALUE)) 305 | .addComponent(statusScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 174, Short.MAX_VALUE)) 306 | .addContainerGap() 307 | )); 308 | 309 | frame.pack(); 310 | 311 | return pane; 312 | } 313 | 314 | private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) { 315 | int returnVal = fileChooser.showOpenDialog(frame); 316 | if(returnVal == JFileChooser.APPROVE_OPTION) { 317 | file = fileChooser.getSelectedFile(); 318 | fileInput.setText(file.getAbsolutePath()); 319 | fileDestination.setText(file.getAbsolutePath().substring(0,file.getAbsolutePath().lastIndexOf(File.separator))); 320 | 321 | 322 | } 323 | } 324 | 325 | private void openFileActionPerformed(java.awt.event.ActionEvent evt) { 326 | int returnVal = fileChooser.showOpenDialog(frame); 327 | if(returnVal == JFileChooser.APPROVE_OPTION) { 328 | file = fileChooser.getSelectedFile(); 329 | fileInput.setText(file.getAbsolutePath()); 330 | fileDestination.setText(file.getAbsolutePath().substring(0,file.getAbsolutePath().lastIndexOf(File.separator))); 331 | } 332 | } 333 | 334 | private void aboutMenuActionPerformed(java.awt.event.ActionEvent evt) { 335 | JOptionPane.showMessageDialog(frame, "The PKCS#7 Signing Tool is a free tool provided\n" 336 | + " by the General Services Agency (GSA). The primary\n" 337 | + " use of this tool is intended for users to be able to\n" 338 | + " digitally sign a file using their PIV card and submit\n" 339 | + " this file to the Federal Register.\n\n" 340 | + " Please use the contact us form on idmanagement.gov\n" 341 | + " to submit any questions regarding this tool.\n\n", "About the PKCS#7 Signing Tool", 1); 342 | 343 | } 344 | 345 | public SwingWorker createVerifyWorker(final javax.swing.JTextArea status, final JProgressBar progress) { 346 | return new SwingWorker() { 347 | @Override 348 | protected Boolean doInBackground() throws Exception { 349 | if (file == null) { 350 | logger.severe("No file was selected"); 351 | String updateText = (dateFormat.format(new Date()) 352 | + " - No file selected. Please select a file to sign.\n"); 353 | errors=true; 354 | progress.setValue(100); 355 | publish(updateText); 356 | } else { 357 | errors=false; 358 | pkcs7unpack = new SigningToolVerifier(file); 359 | } 360 | return true; 361 | } 362 | 363 | @Override 364 | protected void process(List chunks) { 365 | super.process(chunks); 366 | for (String chunk : chunks) { 367 | status.append(chunk); 368 | progress.setValue(progress.getValue() + 1); 369 | } 370 | } 371 | @Override 372 | protected void done() { 373 | try { 374 | Boolean ack = get(); 375 | if (Boolean.TRUE.equals(ack)) { 376 | if (errors == false) { 377 | logger.info("File was verified/unpacked successfully with no errors."); 378 | status.append(dateFormat.format(new Date()) 379 | + " - File has been successfully unpacked."); 380 | } else { 381 | logger.severe("Errors were found while unpacking action was running"); 382 | } 383 | } 384 | } catch (Exception e) { 385 | e.printStackTrace(); 386 | } 387 | } 388 | }; 389 | } 390 | public SwingWorker createWorker(final javax.swing.JTextArea status, final JProgressBar progress) { 391 | return new SwingWorker() { 392 | @Override 393 | protected Boolean doInBackground() throws Exception { 394 | revocationStatus = "Not Checked"; 395 | if (pin.getPassword().length ==0) { 396 | logger.severe("PIN is empty"); 397 | String updateText = dateFormat.format(new Date()) 398 | + " - PIN field is empty. Please enter a valid PIN #.\n"; 399 | errors=true; 400 | progress.setValue(100); 401 | publish(updateText); 402 | 403 | } else if(file == null) { 404 | logger.severe("No file was selected"); 405 | String updateText = (dateFormat.format(new Date()) 406 | + " - No file selected. Please select a file to sign.\n"); 407 | errors=true; 408 | progress.setValue(100); 409 | publish(updateText); 410 | 411 | } else { 412 | errors=false; 413 | pkcs7sign = new SigningTool(file, pin.getPassword()); 414 | } 415 | return true; 416 | } 417 | 418 | @Override 419 | protected void process(List chunks) { 420 | super.process(chunks); 421 | for (String chunk : chunks) { 422 | status.append(chunk); 423 | progress.setValue(progress.getValue() + 1); 424 | } 425 | } 426 | 427 | @Override 428 | protected void done() { 429 | try { 430 | Boolean ack = get(); 431 | if (Boolean.TRUE.equals(ack)) { 432 | if (errors == false) { 433 | logger.info("File was signed successfully with no errors."); 434 | 435 | status.append(dateFormat.format(new Date()) 436 | + " - Signing Cert Expiration Date: " 437 | + notAfterDate 438 | + "\n" + dateFormat.format(new Date()) 439 | + " - Signing Cert Revocation Status: " 440 | + revocationStatus 441 | + "\n" 442 | + dateFormat.format(new Date()) 443 | + " - File has been successfully signed."); 444 | } else { 445 | logger.severe("Errors were found when signing action was completed"); 446 | } 447 | } 448 | } catch (Exception e) { 449 | e.printStackTrace(); 450 | 451 | } 452 | 453 | } 454 | }; 455 | } 456 | public static void main(String args[]) { 457 | try { 458 | fh = new FileHandler("logs/log-" 459 | + logDate.format(new Date()) 460 | + ".txt", true); 461 | logger.addHandler(fh); 462 | fh.setFormatter(new SimpleFormatter()); 463 | logger.setLevel(Level.FINEST); 464 | SwingUtilities.invokeLater(new Runnable() { 465 | public void run() { 466 | 467 | Gui gui = new Gui(); 468 | Component content = gui.createComponents(frame); 469 | frame.getContentPane().add(content, BorderLayout.CENTER); 470 | 471 | frame.addWindowListener(new WindowAdapter() { 472 | public void windowClosing(WindowEvent e) { 473 | fh.close(); 474 | System.exit(0); 475 | } 476 | }); 477 | 478 | frame.pack(); 479 | frame.setLocationRelativeTo(null); 480 | frame.setVisible(true); 481 | } 482 | }); 483 | } catch(Exception e) { 484 | e.printStackTrace(); 485 | } 486 | logger.info("Launching the PKCS#7 Signing Tool Application..."); 487 | /* Create and display the form */ 488 | 489 | } 490 | 491 | } 492 | -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/SelectSlot.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.Date; 6 | import java.util.List; 7 | import java.util.ListIterator; 8 | import java.util.logging.Level; 9 | import javax.smartcardio.CardException; 10 | import javax.smartcardio.CardTerminal; 11 | import javax.smartcardio.TerminalFactory; 12 | import static com.gsa.signingtool.app.Gui.dateFormat; 13 | import static com.gsa.signingtool.app.Gui.logger; 14 | import sun.security.pkcs11.wrapper.CK_C_INITIALIZE_ARGS; 15 | import sun.security.pkcs11.wrapper.CK_INFO; 16 | import sun.security.pkcs11.wrapper.CK_SLOT_INFO; 17 | import sun.security.pkcs11.wrapper.CK_TOKEN_INFO; 18 | import sun.security.pkcs11.wrapper.PKCS11; 19 | 20 | public class SelectSlot { 21 | private static PKCS11 pkcs11 = null; 22 | private static long[] slotList = null; 23 | private static ArrayList slotReturn = new ArrayList(); 24 | private static TerminalFactory factory = null; 25 | private static List terminals = null; 26 | private static ListIterator terminalsIterator = null; 27 | private static CardTerminal terminal = null; 28 | private static boolean cardPresent = false; 29 | private static ArrayList readers = new ArrayList(); 30 | private static int slotCount = 0; 31 | private static CK_C_INITIALIZE_ARGS initArgs = null; 32 | private static CK_SLOT_INFO slotInfo = null; 33 | private static CK_TOKEN_INFO tokenInfo = null; 34 | private static CK_INFO info = null; 35 | private static String compareReader = null; 36 | 37 | protected static ArrayList selectCardTerminal() { 38 | try { 39 | try { 40 | logger.info("Retrieving the list of readers available on system."); 41 | factory = TerminalFactory.getDefault(); 42 | terminals = factory.terminals().list(); 43 | } catch (CardException ex) { 44 | logger.severe("No readers found. Please verify " 45 | + "your card reader is connected."); 46 | Gui.status.append(dateFormat.format(new Date()) 47 | + " - No readers found.\n" 48 | + dateFormat.format(new Date()) 49 | + " - Please verify your card reader is connected.\n"); 50 | Gui.errors = true; 51 | logger.log(Level.FINEST, ex.getMessage(), ex); 52 | Gui.progress.setValue(100); 53 | return null; 54 | } 55 | 56 | terminalsIterator = terminals.listIterator(); 57 | logger.info("Checking # of readers on system connected"); 58 | if(terminals.size() == 1) { 59 | logger.info("Found only 1 reader connected on the system"); 60 | while(terminalsIterator.hasNext()) { 61 | terminal = terminalsIterator.next(); 62 | logger.info("Checking to see if a card is inserted " 63 | + "into the reader"); 64 | cardPresent = terminal.isCardPresent(); 65 | Gui.status.append(dateFormat.format(new Date()) 66 | + " - Verifying card is inserted into the reader.\n"); 67 | Gui.progress.setValue(30); 68 | if(cardPresent) { 69 | logger.info("Found a card present in: " 70 | + terminal.getName()); 71 | Gui.status.append(dateFormat.format(new Date()) 72 | + " - Found reader with card present.\n" 73 | + dateFormat.format(new Date()) + " - " 74 | + terminal.getName() + "\n"); 75 | readers.add(terminal.getName()); 76 | Gui.progress.setValue(40); 77 | } else { 78 | logger.severe("No card present, please insert card"); 79 | Gui.status.append(dateFormat.format(new Date()) 80 | + " - No card present, please insert card.\n"); 81 | Gui.errors = true; 82 | Gui.progress.setValue(100); 83 | return null; 84 | } 85 | } 86 | } else { 87 | logger.info("More than 1 reader found connected on system"); 88 | int i = 0; 89 | while(terminalsIterator.hasNext()) { 90 | terminal = terminalsIterator.next(); 91 | cardPresent = terminal.isCardPresent(); 92 | logger.info("Detecting if more than 1 reader has a card inserted"); 93 | if (cardPresent) { 94 | readers.add(terminal.getName()); 95 | System.out.println("Inside If = "+ i); 96 | logger.info("Found a card present in: " 97 | + terminal.getName()); 98 | Gui.status.append(dateFormat.format(new Date()) 99 | + " - Found reader with card present.\n" 100 | + dateFormat.format(new Date()) 101 | + " - " 102 | + terminal.getName() 103 | + "\n"); 104 | Gui.progress.setValue(40); 105 | break; 106 | } else { 107 | System.out.println("Outside If = " + i); 108 | logger.info("No card found in the following reader: " 109 | + terminal.getName()); 110 | System.err.println("No card present in this reader" 111 | + terminal.getName()); 112 | //Gui.progress.setValue(100); 113 | //return null; 114 | } 115 | i++; 116 | } 117 | 118 | } 119 | 120 | if (readers.size() == 1) { 121 | logger.info("Found 1 reader and determining slot id#"); 122 | // Setting up the items necessary for determining the # of slots 123 | logger.info("initializing reader arguements"); 124 | initArgs = new CK_C_INITIALIZE_ARGS(); 125 | initArgs.flags = 0; 126 | 127 | String libFile = new File("").getAbsolutePath() 128 | + "/lib/opensc-pkcs11.so"; 129 | //libFile = libFile.replace("\\", "/"); 130 | pkcs11 = PKCS11.getInstance(libFile, "C_GetFunctionList", initArgs, false); 131 | slotList = pkcs11.C_GetSlotList(true); 132 | slotCount = slotList.length; 133 | //loop through the available slots and return slot id 134 | logger.info("looping through the available slots"); 135 | if (slotCount >= 1) { 136 | for (long slot : slotList) { 137 | slotInfo = pkcs11.C_GetSlotInfo(slot); 138 | tokenInfo = pkcs11.C_GetTokenInfo(slot); 139 | info = pkcs11.C_GetInfo(); 140 | compareReader = new String(slotInfo.slotDescription); 141 | for (String readerMatch : readers) { 142 | long[] temp = null; 143 | readerMatch = readerMatch.replaceAll("\\s+",""); 144 | compareReader =compareReader.replaceAll("\\s",""); 145 | if (readerMatch.equals(compareReader)) { 146 | slotReturn.add(slot); 147 | } 148 | } 149 | } 150 | } else { 151 | logger.severe("Unable to find a slot id"); 152 | Gui.status.append(dateFormat.format(new Date()) 153 | + " - Issue with card reader.\n" 154 | + dateFormat.format(new Date()) 155 | + " - Please check connection or try a new reader.\n"); 156 | Gui.errors = true; 157 | Gui.progress.setValue(100); 158 | return null; 159 | } 160 | } 161 | } catch (Exception e) { 162 | logger.log(Level.FINEST, e.getMessage(), e); 163 | Gui.status.append(dateFormat.format(new Date()) 164 | + " - Error Getting Card Information From Reader.\n" 165 | + dateFormat.format(new Date()) 166 | + " - Please check reader and card connection.\n"); 167 | Gui.errors = true; 168 | Gui.progress.setValue(100); 169 | return null; 170 | } 171 | logger.info("Returning an ArrayList of slot IDs"); 172 | return slotReturn; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/SigningTool.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.security.KeyStore; 8 | import java.security.PrivateKey; 9 | import java.security.Provider; 10 | import java.security.Security; 11 | import java.security.cert.Certificate; 12 | import java.security.cert.X509Certificate; 13 | import java.util.ArrayList; 14 | import java.util.Date; 15 | import java.util.Enumeration; 16 | import java.util.logging.Level; 17 | import org.bouncycastle.cert.jcajce.JcaCertStore; 18 | import org.bouncycastle.cms.CMSProcessableByteArray; 19 | import org.bouncycastle.cms.CMSSignedData; 20 | import org.bouncycastle.cms.CMSSignedDataGenerator; 21 | import org.bouncycastle.cms.CMSTypedData; 22 | import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; 23 | import org.bouncycastle.operator.ContentSigner; 24 | import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; 25 | import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; 26 | import org.bouncycastle.util.Store; 27 | import static com.gsa.signingtool.app.Gui.dateFormat; 28 | import static com.gsa.signingtool.app.Gui.logger; 29 | import sun.security.pkcs11.SunPKCS11; 30 | 31 | 32 | public class SigningTool { 33 | 34 | //public static boolean errors = false; 35 | protected String errorDesc = null; 36 | protected String filenameDest = null; 37 | protected String readerStatus = null; 38 | protected String cardStatus = null; 39 | protected String fileStatus = null; 40 | protected long slotID = 0; 41 | protected X509Certificate userCert = null; 42 | private PrivateKey privateKey = null; 43 | private Provider sun = null; 44 | private Provider bc = null; 45 | protected ArrayList readers = null; 46 | private KeyStore piv = null; 47 | protected byte[] fileBytes = null; 48 | protected StringBuffer sb = new StringBuffer(); 49 | protected ArrayList signingCerts = new ArrayList(); 50 | protected static boolean expired = false; 51 | 52 | protected SigningTool(File file, char[] pin) { 53 | if (file != null) { 54 | logger.info("Converting selected file to bytes"); 55 | fileBytes = getFileContentBytes(file); 56 | } else { 57 | logger.severe("File selected is empty"); 58 | Gui.status.append(dateFormat.format(new Date()) 59 | + " - File is empty.\n"); 60 | return; 61 | } 62 | try { 63 | if (sun != null) { 64 | logger.info("Sun Provider is not null. Logging out of card"); 65 | ((SunPKCS11) sun).logout(); 66 | } 67 | logger.info("Initiating communication with reader"); 68 | Gui.progress.setValue(15); 69 | Gui.status.append(dateFormat.format(new Date()) 70 | + " - Detecting card reader.\n"); 71 | readers = SelectSlot.selectCardTerminal(); 72 | 73 | logger.info("Selecting the first card reader slot found in ArrayList"); 74 | if (readers.isEmpty()) { 75 | logger.severe("Issue selecting card reader and verifying card is inserted."); 76 | Gui.status.append(dateFormat.format(new Date()) 77 | + " - Issue detecting card reader and/or if card is inserted.\n"); 78 | Gui.errors = true; 79 | Gui.progress.setValue(100); 80 | return; 81 | } else { 82 | slotID = readers.get(0); 83 | } 84 | 85 | String libFile = "\"" + new File("").getAbsolutePath() 86 | + "/lib/opensc-pkcs11.so"; 87 | libFile = libFile.replace("\\", "/"); 88 | logger.info(libFile); 89 | String configName = "name=" 90 | + "opensc" 91 | + "\n" 92 | + "library=" 93 | + libFile 94 | + "\n" 95 | + "slot=" 96 | + slotID; 97 | logger.info("Output of information needed to connect SunPKCS11 Provider.\n" 98 | + configName); 99 | byte[] pkcs11configBytes = configName.getBytes(); 100 | ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11configBytes); 101 | bc = new org.bouncycastle.jce.provider.BouncyCastleProvider(); 102 | logger.info("Adding a Bouncy Castle provider"); 103 | Security.addProvider(bc); 104 | logger.info("Trying to add SunPKCS11 provider"); 105 | sun = new sun.security.pkcs11.SunPKCS11(confStream); 106 | Security.addProvider(sun); 107 | try { 108 | //KeyStore.PasswordProtection pp = new KeyStore.PasswordProtection(pin); 109 | piv = KeyStore.getInstance("PKCS11", sun); 110 | 111 | logger.info("Trying to connect to smart card using SunPKCS11 and user PIN"); 112 | 113 | piv.load(null, pin); 114 | 115 | Gui.progress.setValue(60); 116 | Gui.status.append(dateFormat.format(new Date()) 117 | + " - Validating PIN number.\n"); 118 | } catch (Exception ex) { 119 | logger.log(Level.FINEST, ex.getMessage(), ex); 120 | ((SunPKCS11) sun).logout(); 121 | Security.removeProvider(sun.getName()); 122 | Security.removeProvider(bc.getName()); 123 | Gui.status.append(dateFormat.format(new Date()) 124 | + " - Unable to validate PIN. Verify PIN is correct.\n"); 125 | Gui.progress.setValue(100); 126 | Gui.errors = true; 127 | return; 128 | } 129 | 130 | Gui.logger.info("Looping through certificates on card"); 131 | Enumeration aliasesEnum = piv.aliases(); 132 | while (aliasesEnum.hasMoreElements()) { 133 | boolean[] keyUsage = null; 134 | String alias = (String)aliasesEnum.nextElement(); 135 | Certificate[] certificationChain = piv.getCertificateChain(alias); 136 | 137 | for (X509Certificate certificate : (X509Certificate[]) certificationChain) { 138 | Gui.logger.finest(certificate.getSubjectDN().toString()); 139 | } 140 | Certificate cert = piv.getCertificate(alias); 141 | X509Certificate x509 = (X509Certificate)cert; 142 | keyUsage = x509.getKeyUsage(); 143 | if (keyUsage[0] && keyUsage[1]) { 144 | logger.info("Found a signing certificate with Digital Signature & Non-repudiation!"); 145 | logger.info("Serial Number of Signing Certificate: " 146 | + x509.getSerialNumber()); 147 | privateKey = (PrivateKey) piv.getKey(alias, null); 148 | Gui.notAfterDate = x509.getNotAfter().toString(); 149 | Gui.serialNum = x509.getSerialNumber().toString(); 150 | signingCerts.add(x509); 151 | Gui.progress.setValue(70); 152 | Gui.status.append(dateFormat.format(new Date()) 153 | + " - Found a signing certificate.\n"); 154 | } 155 | } 156 | 157 | if (signingCerts.size()==1) { 158 | logger.info("Found only 1 signing certificate"); 159 | byte[] envelopedBytes = null; 160 | userCert = (X509Certificate)signingCerts.get(0); 161 | X509Certificate issuerCert = null; 162 | String revokeStatus = null; 163 | 164 | try { 165 | logger.info("Checking the expiration date of the signing certificate"); 166 | userCert.checkValidity(); 167 | Gui.progress.setValue(80); 168 | Gui.status.append(dateFormat.format(new Date()) 169 | + " - Checking expiration date of signing certificate.\n"); 170 | } catch (Exception exc) { 171 | Gui.logger.log(Level.FINEST, exc.getMessage(), exc); 172 | Gui.errors = true; 173 | expired = true; 174 | Gui.status.append(dateFormat.format(new Date()) 175 | + " - Unable to sign. The signing certificate is expired.\n" 176 | + dateFormat.format(new Date()) 177 | + " - Expires: " 178 | + userCert.getNotAfter() 179 | + "\n"); 180 | ((SunPKCS11) sun).logout(); 181 | Security.removeProvider(sun.getName()); 182 | Security.removeProvider(bc.getName()); 183 | Gui.progress.setValue(100); 184 | return; 185 | } 186 | if (Gui.revocationCheckBox.getState()) { 187 | try { 188 | logger.info("Checking Revocation Status of signing certificate..."); 189 | issuerCert = CheckRevocationStatus.fetchIssuerCert(userCert); 190 | revokeStatus = CheckRevocationStatus.checkRevocation(userCert, issuerCert); 191 | 192 | Gui.revocationStatus = revokeStatus; 193 | if (revokeStatus == "REVOKED") { 194 | Gui.status.append(dateFormat.format(new Date()) 195 | + " - Unable to sign. Signing Certificate is REVOKED"); 196 | } 197 | } catch (Exception e) { 198 | Gui.status.append(dateFormat.format(new Date()) 199 | + " - Signing Certificate Revocation Status: " 200 | + revokeStatus + "\n"); 201 | logger.log(Level.FINEST, e.getMessage(), e); 202 | 203 | // ((SunPKCS11) sun).logout(); 204 | // Security.removeProvider(sun.getName()); 205 | // Security.removeProvider(bc.getName()); 206 | } 207 | } 208 | Store signers = new JcaCertStore(signingCerts); 209 | CMSTypedData msg = new CMSProcessableByteArray(fileBytes); 210 | CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); 211 | logger.info("Trying to create a ContentSigner using SHA256RSA " 212 | + "algorithm, SunPKCS11 Provider, and Signing Cert Private Key..."); 213 | ContentSigner sha2 = 214 | new JcaContentSignerBuilder("SHA256withRSA").setProvider("SunPKCS11-opensc").build(privateKey); 215 | logger.info("Trying to add SignerInfo data to CMSSignedDataGenerator..."); 216 | gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder( 217 | new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha2, userCert)); 218 | Gui.progress.setValue(90); 219 | gen.addCertificates(signers); 220 | logger.info("Trying to generate CMSSignedData object..."); 221 | 222 | 223 | CMSSignedData sigData = gen.generate(msg, true); 224 | logger.info("Completed sigData"); 225 | Gui.errors = false; 226 | 227 | envelopedBytes = sigData.getEncoded(); 228 | logger.info("Logging out of card/reader"); 229 | ((SunPKCS11) sun).logout(); 230 | Security.removeProvider(sun.getName()); 231 | Security.removeProvider(bc.getName()); 232 | 233 | if (envelopedBytes != null) { 234 | filenameDest = file.toString() + ".p7m"; 235 | String result = writeBytes(envelopedBytes, filenameDest); 236 | if (result == null) { 237 | System.out.println("Done"); 238 | } else { 239 | System.out.println(result + "\n"); 240 | } 241 | Gui.progress.setValue(100); 242 | } 243 | } else if (signingCerts.size() > 1) { 244 | String tooManySigners = "Unable to sign. More than 1 signing certificate found."; 245 | Gui.errors = true; 246 | errorDesc = tooManySigners; 247 | Gui.status.append(dateFormat.format(new Date()) 248 | + " - " + tooManySigners + "\n"); 249 | logger.severe(tooManySigners); 250 | Gui.progress.setValue(100); 251 | return; 252 | } else { 253 | Gui.errors = true; 254 | errorDesc = "Unable to sign. No signing certificates found on the card."; 255 | Gui.status.append(dateFormat.format(new Date()) 256 | + " - " + errorDesc 257 | + "\n"); 258 | logger.severe(errorDesc); 259 | Gui.progress.setValue(100); 260 | return; 261 | } 262 | } catch(Exception e) { 263 | logger.log(Level.FINEST, e.getMessage(), e); 264 | Gui.errors=true; 265 | Gui.progress.setValue(100); 266 | return; 267 | } 268 | } 269 | 270 | public byte[] getFileContentBytes(File file) { 271 | byte[] fileBytes = null; 272 | try { 273 | FileInputStream fis = new FileInputStream(file); 274 | fileBytes = new byte[(int)file.length()]; 275 | fis.read(fileBytes); 276 | fis.close(); 277 | } 278 | catch (Exception x) { 279 | Gui.errors=true; 280 | logger.log(Level.FINEST, x.getMessage(), x); 281 | } 282 | return fileBytes; 283 | } 284 | 285 | public String writeBytes(byte[] dataToSign, String outputFilename) { 286 | try { 287 | FileOutputStream fos = new FileOutputStream(outputFilename); 288 | fos.write(dataToSign); 289 | fos.close(); 290 | return null; 291 | } catch(Exception x) { 292 | Gui.errors=true; 293 | logger.log(Level.FINEST, x.getMessage(), x); 294 | Gui.status.append(dateFormat.format(new Date()) 295 | + " - Error Writing File " 296 | + outputFilename + ": " 297 | + x.toString() + "\n"); 298 | return "Error Writing File " 299 | + outputFilename 300 | + ": " 301 | + x.toString(); 302 | } 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/SigningToolVerifier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.gsa.signingtool.app; 7 | 8 | import static com.gsa.signingtool.app.Gui.logger; 9 | import java.io.ByteArrayOutputStream; 10 | import java.io.File; 11 | import java.io.FileInputStream; 12 | import java.io.FileOutputStream; 13 | import java.util.Date; 14 | import org.bouncycastle.cms.CMSProcessable; 15 | import org.bouncycastle.cms.CMSSignedData; 16 | import static com.gsa.signingtool.app.Gui.dateFormat; 17 | import org.apache.commons.io.FilenameUtils; 18 | 19 | /** 20 | * 21 | * @author jorpac01 22 | */ 23 | public class SigningToolVerifier { 24 | protected SigningToolVerifier(File file) { 25 | byte[] fileBytes = null; 26 | 27 | if (file != null) { 28 | fileBytes = getFileContentBytes(file); 29 | } 30 | System.out.println(fileBytes.length); 31 | 32 | //Object selectFile = unpackP7(fileBytes, file.toString()); 33 | System.out.println(unpackP7(fileBytes, file.toString())); 34 | Gui.progress.setValue(100); 35 | } 36 | 37 | public byte[] getFileContentBytes(File file) { 38 | byte[] fileBytes = null; 39 | 40 | try { 41 | FileInputStream fos = new FileInputStream(file); 42 | fileBytes = new byte[(int)file.length()]; 43 | fos.read(fileBytes); 44 | fos.close(); 45 | } catch (Exception x) { 46 | System.out.println("Unable to open " + file); 47 | } 48 | return fileBytes; 49 | } 50 | 51 | public String unpackP7(byte[] bytesToUnpack, String filename) 52 | { 53 | String str = null; 54 | StringBuffer response = new StringBuffer(); 55 | boolean verified = false; 56 | int lastPeriodPos = filename.lastIndexOf('.'); 57 | int flag = 0; 58 | String ext = ""; 59 | try { 60 | ext = FilenameUtils.getExtension(filename); 61 | System.out.println("File Type is: " + ext); 62 | if (ext.equals("p7m")) { 63 | System.out.println("Valid .p7m file."); 64 | CMSSignedData signedData = new CMSSignedData(bytesToUnpack); 65 | CMSProcessable signedContent = signedData.getSignedContent(); 66 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 67 | signedContent.write(baos); 68 | 69 | byte[] fileBytes = baos.toByteArray(); 70 | str = filename.substring(0, lastPeriodPos); 71 | writeBytes(fileBytes, str); 72 | response.append("\n\nUnpacked to " + str + "\n"); 73 | Gui.status.append(dateFormat.format(new Date()) + " - " + str + "\n"); 74 | } else { 75 | flag = 1; 76 | throw new Exception(); 77 | } 78 | } catch (Exception e) { 79 | response.append("Unable to unpack " + filename + ": " + e + "\n"); 80 | if (flag == 1) { 81 | logger.severe("File selected does not have the appropriate file " 82 | + "extension.\n File should end in a .p7m file extension."); 83 | Gui.status.append(dateFormat.format(new Date()) 84 | + " - File selected does not have the appropriate file extension (.p7m).\n"); 85 | Gui.errors = true; 86 | Gui.progress.setValue(100); 87 | } else { 88 | logger.severe(e.getMessage()); 89 | Gui.status.append(dateFormat.format(new Date()) 90 | + " - Issue unpacking the signed file. See log file for more details.\n"); 91 | Gui.errors = true; 92 | Gui.progress.setValue(100); 93 | } 94 | } 95 | return response.toString(); 96 | } 97 | 98 | public Boolean errMessage (String filename) { 99 | int lastPeriodPos = filename.lastIndexOf('.'); 100 | if (!filename.substring(0, lastPeriodPos).equals(".p7m")) { 101 | String errMesg = "Not a valid .p7m file."; 102 | } 103 | return true; 104 | } 105 | public String writeBytes(byte[] bytesToWrite, String paramString) 106 | { 107 | try 108 | { 109 | FileOutputStream fos = new FileOutputStream(paramString); 110 | fos.write(bytesToWrite); 111 | fos.close(); 112 | return null; 113 | } catch (Exception x) { 114 | x.printStackTrace(); 115 | return "Error Writing File " + paramString + ": " + x.toString(); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/StatusUpdater.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.gsa.signingtool.app; 7 | 8 | import javax.swing.SwingWorker; 9 | import static com.gsa.signingtool.app.Gui.status; 10 | 11 | /** 12 | * 13 | * @author jorpac01 14 | */ 15 | public class StatusUpdater extends SwingWorker{ 16 | 17 | @Override 18 | protected String doInBackground() throws Exception { 19 | System.out.println(Thread.currentThread().getName()); 20 | String update = "Applying Signature\n"; 21 | status.append(update); 22 | return update; 23 | } 24 | 25 | @Override 26 | public void done() { 27 | try { 28 | System.out.println("DONE"); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/SwingWorkerService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.gsa.signingtool.app; 7 | 8 | import javax.swing.JCheckBox; 9 | import javax.swing.JFrame; 10 | import javax.swing.JLabel; 11 | import javax.swing.JProgressBar; 12 | import javax.swing.SwingWorker; 13 | import java.awt.BorderLayout; 14 | import java.awt.EventQueue; 15 | import java.lang.reflect.InvocationTargetException; 16 | import java.util.List; 17 | import java.util.concurrent.ExecutionException; 18 | 19 | public class SwingWorkerService { 20 | private static JProgressBar PROGRESS_BAR; 21 | private static JLabel OUTPUT_LABEL; 22 | private static JFrame createGUI(){ 23 | JFrame testFrame = new JFrame( "TestFrame" ); 24 | 25 | PROGRESS_BAR = new JProgressBar( ); 26 | PROGRESS_BAR.setMinimum( 0 ); 27 | PROGRESS_BAR.setMaximum( 100 ); 28 | 29 | OUTPUT_LABEL = new JLabel( "Processing" ); 30 | 31 | testFrame.getContentPane().add( PROGRESS_BAR, BorderLayout.CENTER ); 32 | testFrame.getContentPane().add( OUTPUT_LABEL, BorderLayout.SOUTH ); 33 | 34 | //add a checkbox as well to proof the UI is still responsive 35 | testFrame.getContentPane().add( 36 | new JCheckBox( "Click me to proof UI is responsive" ), BorderLayout.NORTH ); 37 | 38 | 39 | 40 | testFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 41 | return testFrame; 42 | } 43 | 44 | public static void main( String[] args ) throws InvocationTargetException, InterruptedException { 45 | EventQueue.invokeAndWait( new Runnable() { 46 | @Override 47 | public void run() { 48 | JFrame frame = createGUI(); 49 | 50 | frame.pack(); 51 | frame.setVisible( true ); 52 | } 53 | } ); 54 | //start the SwingWorker outside the EDT 55 | MySwingWorker worker = new MySwingWorker( PROGRESS_BAR ); 56 | worker.execute(); 57 | } 58 | private static class MySwingWorker extends SwingWorker{ 59 | private final JProgressBar fProgressBar; 60 | private MySwingWorker( JProgressBar aProgressBar ) { 61 | fProgressBar = aProgressBar; 62 | } 63 | 64 | @Override 65 | protected String doInBackground() throws Exception { 66 | int maxNumber = 10; 67 | for( int i = 0; i < maxNumber; i++ ){ 68 | Thread.sleep( 2000 );//simulate long running process 69 | double factor = ((double)(i+1) / maxNumber); 70 | System.out.println("Intermediate results ready"); 71 | publish( factor );//publish the progress 72 | } 73 | return "Finished"; 74 | } 75 | 76 | @Override 77 | protected void process( List aDoubles ) { 78 | //update the percentage of the progress bar that is done 79 | int amount = fProgressBar.getMaximum() - fProgressBar.getMinimum(); 80 | fProgressBar.setValue( ( int ) (fProgressBar.getMinimum() 81 | + ( amount * aDoubles.get( aDoubles.size() - 1 ))) ); 82 | } 83 | 84 | } 85 | } -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/src/com/gsa/signingtool/app/images/close.png -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/images/exelogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/src/com/gsa/signingtool/app/images/exelogo.png -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/src/com/gsa/signingtool/app/images/icon.png -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/src/com/gsa/signingtool/app/images/info.png -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/src/com/gsa/signingtool/app/images/logo.png -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/images/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/src/com/gsa/signingtool/app/images/open.png -------------------------------------------------------------------------------- /apple/src/com/gsa/signingtool/app/images/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/apple/src/com/gsa/signingtool/app/images/text.png -------------------------------------------------------------------------------- /microsoft/GSA_Signing_Tool_User_Guide-64bit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/GSA_Signing_Tool_User_Guide-64bit.pdf -------------------------------------------------------------------------------- /microsoft/LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/LICENSE.txt -------------------------------------------------------------------------------- /microsoft/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | This repo contains the General Services Administration (GSA) Document Signing tools used for digitally signing documents and files with Personal Identity Verification (PIV) cards. The main purpose of the tool is for Federal agencies to use for digitally signing documents to be submitted to the Office of the Federal Register's (OFR) document submission web portal. The tool was developed using Java 8. It relies on Bouncy Castle libraries for the signing operations, Apache Commons for file operations, and OpenSC for PIV operations. 3 | 4 | ### How does it work? 5 | The GSA Document Signing Tool includes a simple, 508-compliant Graphical User Interface (GUI) to assist in the signing of your desired document. The tool allows the user to select the desired file they'd like signed, a field to enter the user's PIV application PIN , and a "Sign" button to initiate the signing. The tool automatically detects any smart card readers and PIV cards connected to the system. The tool utilizes PKCS#11 to interact with the reader and PIV card. The signed file is formatted in an enveloped PKCS#7 (.p7m) file, which is the required format for the OFR's document submission portal. In order for the tool to sign correctly, the PIV card MUST contain a valid digital signing certificate (i.e. Key usage of Digital Signature and Non-repudiation). If it doesn't contain a valid digital signing certificate, the application will provide a descriptive error messages. 6 | 7 | ### Installation/Usage Instructions 8 | 9 | The GSA Document Signing Tool includes a Windows 32-bit, 64-bit, and MacOS version. Verify your system's operating system before installing. Use the following User Guides below for guiding you through the installation process: 10 | 11 | * Windows Installation Guide - https://github.com/GSA/gsa-doc-digital-signature/blob/platforms/microsoft/GSA_Signing_Tool_User_Guide-64bit.pdf 12 | * MacOS Installation Guides - https://github.com/GSA/gsa-doc-digital-signature/blob/platforms/apple/GSA_Signing_Tool_User_Guide-Mac.pdf 13 | 14 | ### Developer Install Instructions 15 | 16 | For developers, the source code, 3rd party libraries, and drivers can be imported into a Java IDE (i.e. Eclipse, NetBeans). 17 | 18 | **NOTE:** This tool will only compile correctly using Java 8. Lower Java versions are not compatible with the development of this tool. 19 | 20 | Initial setup: 21 | * Import initial source code in the "/src" directory to your Java IDE project source code directory. 22 | * Add the specific OpenSC driver for the system type you will be developing for (i.e. if you are developing on a 64-bit system, copy the opensc driver in the 64-bit directory, and paste the driver in the "lib" directory with the Bouncy Castle libraries. 23 | * Import "lib" directory to your Java IDE project. 24 | * Use the "GUI" class, as your main executable class for executing the tool. 25 | 26 | ### Dependencies 27 | 28 | The GSA Document Signing Tool leverages 3rd party libraries including: 29 | * [Oracle Java] http://www.oracle.com/ 30 | * [Bouncy Castle] https://www.bouncycastle.org/ 31 | * [opensc] https://github.com/OpenSC/OpenSC 32 | * [commons-io] http://commons.apache.org/proper/commons-io/ 33 | 34 | The tool has not been tested with alternate versions of Java such as OpenJDK. Contributors are welcome to determine compatibility and update this README and dependencies appropriately. 35 | 36 | On Windows, the installer was built using [inno setup] http://www.jrsoftware.org/ 37 | 38 | ### License 39 | This project is in the public domain within the United States. 40 | 41 | We waive copyright and related rights in the work worldwide through the CC0 1.0 Universal public domain dedication. 42 | 43 | Please review the License found in this repository. 44 | 45 | ### Contact Information 46 | 47 | For issues, please open an Issue in this repository. Contact icam at gsa.gov for any additional questions on contributing. -------------------------------------------------------------------------------- /microsoft/README.txt: -------------------------------------------------------------------------------- 1 | Intro 2 | ----- 3 | This Document Signing Tool application will digitally sign documents and files 4 | using digital certificates. It will store the document 5 | and signature together in a single PKCS7 enveloped file. The 6 | signed file will appear in the same directory as the original file, 7 | with the same filename with an added extension of ".p7m". 8 | 9 | 10 | Quick start: 11 | ------------ 12 | 1. Start the program from your Desktop Shortcut or from Start -> ICAM -> PKCS7 Signing Tool 13 | 2. Click the Open button to select a file to sign 14 | 3. Select a file and click Open 15 | 3. Enter your PIN 16 | 4. Click the Sign button 17 | 18 | Your file should now be signed. 19 | 20 | 21 | Change Log: 22 | ----------- 23 | v2.0.0 - new GUI improvements 24 | - included 508 compliance 25 | - fixed certificate selection issue by relying on PKCS#11 instead of using the MSCAPI key store 26 | - added check for certificate expiration 27 | - added check for certificate revocation status 28 | - updated Java to version 1.8.0_25 29 | - updated Bouncy Castle libraries to 1.51 30 | - removed PKCS7Unpack.exe 31 | v1.5.0 - no file association for signing, just unpack 32 | v1.4.0 - fixes PKCS7Unpack.exe error 33 | v1.3.0 - fixes problem on certain service packs of WinXP where the 34 | PKCS7 envelope contains a reference to an incorrect 35 | certificate 36 | v1.2.0 - displays certificate selection dialog on Win XP even if only 37 | one available signing certificate 38 | v1.1.0 - repairs issue with selecting wrong signing cert 39 | 40 | 41 | Certificate Validation 42 | ---------------------- 43 | By default, the tool will check the revocation status of the certificate used to sign the file. 44 | 45 | 46 | Security 47 | -------- 48 | All files will be signed using SHA256. 49 | 50 | 51 | Compatibility 52 | ------------- 53 | This tool was tested and successfully signed files using Windows 8.1 / Windows 7 / Windows XP. 54 | -------------------------------------------------------------------------------- /microsoft/drivers/32-bit/opensc-pkcs11.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/drivers/32-bit/opensc-pkcs11.dll -------------------------------------------------------------------------------- /microsoft/drivers/64-bit/opensc-pkcs11.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/drivers/64-bit/opensc-pkcs11.dll -------------------------------------------------------------------------------- /microsoft/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/icon.ico -------------------------------------------------------------------------------- /microsoft/lib/bcmail-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/lib/bcmail-jdk15on-152.jar -------------------------------------------------------------------------------- /microsoft/lib/bcpg-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/lib/bcpg-jdk15on-152.jar -------------------------------------------------------------------------------- /microsoft/lib/bcpkix-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/lib/bcpkix-jdk15on-152.jar -------------------------------------------------------------------------------- /microsoft/lib/bcprov-ext-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/lib/bcprov-ext-jdk15on-152.jar -------------------------------------------------------------------------------- /microsoft/lib/bcprov-jdk15on-152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/lib/bcprov-jdk15on-152.jar -------------------------------------------------------------------------------- /microsoft/lib/commons-io-2.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/lib/commons-io-2.4.jar -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/app/CheckRevocationStatus.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.net.URI; 7 | import java.net.URL; 8 | import java.security.cert.CertificateFactory; 9 | import java.security.cert.X509Certificate; 10 | import java.util.ArrayList; 11 | import java.util.Date; 12 | import java.util.Iterator; 13 | import java.util.logging.Level; 14 | import org.bouncycastle.asn1.ASN1InputStream; 15 | import org.bouncycastle.asn1.ASN1Primitive; 16 | import org.bouncycastle.asn1.ASN1Sequence; 17 | import org.bouncycastle.asn1.DERIA5String; 18 | import org.bouncycastle.asn1.DEROctetString; 19 | import org.bouncycastle.asn1.x509.AccessDescription; 20 | import org.bouncycastle.asn1.x509.AuthorityInformationAccess; 21 | import org.bouncycastle.asn1.x509.GeneralName; 22 | import static com.gsa.signingtool.app.Gui.dateFormat; 23 | import sun.security.provider.certpath.OCSP; 24 | 25 | public class CheckRevocationStatus { 26 | 27 | public static X509Certificate fetchIssuerCert(X509Certificate cert) { 28 | AuthorityInformationAccess authInfoAcc = null; 29 | AuthorityInformationAccess access = null; 30 | URI responderURI = null; 31 | X509Certificate issuerCert = null; 32 | String serviceAddr = null; 33 | ArrayList issuingCerts = new ArrayList(); 34 | X509Certificate exactIssuerCert = null; 35 | boolean issuerMatch = false; 36 | File issuerChain = null; 37 | 38 | //Get issuer certificate from the path to use for OCSP and 39 | //validating the end entity 40 | try { 41 | Gui.logger.info("Trying to create new file to store " 42 | + "issuer p7c file"); 43 | String issuerChainPath = new File("").getAbsolutePath() 44 | + "\\logs\\issuer.p7b"; 45 | issuerChain = new File(issuerChainPath); 46 | Gui.logger.info("Successfully created issuer file: " 47 | + issuerChain.getAbsolutePath()); 48 | } catch (Exception e) { 49 | Gui.logger.severe("Error creating issuer p7b file"); 50 | Gui.logger.log(Level.FINEST, e.getMessage(), e); 51 | } 52 | 53 | //Get AiA instance from end-entity certificate 54 | try { 55 | Gui.logger.info("Trying to get AiA from end-entity" 56 | + " certificate"); 57 | byte[] extensionValue = 58 | ((X509Certificate)cert).getExtensionValue("1.3.6.1.5.5.7.1.1"); 59 | DEROctetString string = 60 | (DEROctetString) (new ASN1InputStream 61 | (new ByteArrayInputStream(extensionValue)).readObject()); 62 | ASN1Sequence seq = 63 | ASN1Sequence.getInstance(ASN1Primitive.fromByteArray( 64 | DEROctetString.getInstance(string).getOctets())); 65 | access = AuthorityInformationAccess.getInstance(seq); 66 | Gui.logger.info("Successfully retrieved AiA instances"); 67 | } catch (Exception e) { 68 | Gui.logger.severe("Issue getting AiA instances"); 69 | Gui.logger.log(Level.FINEST, e.getMessage(), e); 70 | } 71 | 72 | try { 73 | Gui.logger.info("Setting the accessDescriptions"); 74 | AccessDescription[] accessDescriptions = 75 | access.getAccessDescriptions(); 76 | Gui.logger.info("Looping through the accessDescriptions " 77 | + "to get the different end-points"); 78 | for (AccessDescription accessDescription : accessDescriptions) { 79 | GeneralName gn = 80 | accessDescription.getAccessLocation(); 81 | if(gn.getTagNo() == GeneralName.uniformResourceIdentifier) { 82 | DERIA5String str = 83 | DERIA5String.getInstance(gn.getName()); 84 | String accessLocation = str.getString(); 85 | serviceAddr = accessLocation; 86 | if (serviceAddr.toLowerCase().startsWith("http") 87 | && serviceAddr.toLowerCase().endsWith(".p7c") 88 | || serviceAddr.toLowerCase().endsWith(".p7b")) { 89 | try { 90 | Gui.logger.info("Setting the p7c URL"); 91 | URL url = new URL(serviceAddr); 92 | Gui.logger.info("Downloading the issuer " 93 | + "cert p7c file"); 94 | org.apache.commons.io.FileUtils.copyURLToFile( 95 | url, issuerChain); 96 | Gui.logger.info("Saving the issuer " 97 | + "cert p7c file"); 98 | FileInputStream fis = new FileInputStream(issuerChain); 99 | Gui.logger.info("File location: " 100 | + issuerChain.getAbsolutePath()); 101 | Gui.logger.info("Generating a " 102 | + "new certificate to store issuer cert "); 103 | CertificateFactory cf = 104 | CertificateFactory.getInstance("x.509"); 105 | Iterator iter = 106 | cf.generateCertificates(fis).iterator(); 107 | Gui.logger.info("Iterating through the p7c file"); 108 | while (iter.hasNext()) { 109 | issuerCert = (X509Certificate)iter.next(); 110 | issuingCerts.add(issuerCert); 111 | Gui.logger.info("Verifying if their is a match " 112 | + "between the end-entity issuerDN " 113 | + "and certificates in p7c file subjectDN"); 114 | if (issuerCert.getSubjectDN().equals(cert.getIssuerDN())) { 115 | issuerMatch = true; 116 | Gui.logger.info("Found a match! The " 117 | + "issuer of the end-entity cert's serial " 118 | + "number is: " 119 | + issuerCert.getSerialNumber()); 120 | exactIssuerCert = issuerCert; 121 | } 122 | } 123 | if (issuerMatch = false) { 124 | Gui.logger.severe("Unable to check " 125 | + "revocation status. Issue " 126 | + "finding issuer cert"); 127 | return null; 128 | } 129 | } catch (Exception e) { 130 | Gui.logger.log(Level.FINEST, e.getMessage(), e); 131 | } 132 | } 133 | } 134 | Gui.logger.info("AiA length: " + accessDescriptions.length); 135 | } 136 | } catch (Exception e) { 137 | Gui.logger.severe("Issue with obtaining issuer cert"); 138 | Gui.logger.log(Level.FINEST, e.getMessage(), e); 139 | } 140 | Gui.logger.info("Returning the cert with the following serial #: " 141 | + exactIssuerCert.getSerialNumber()); 142 | return exactIssuerCert; 143 | } 144 | 145 | public static String checkRevocation(X509Certificate end, X509Certificate issuer) { 146 | String revocationStatus = null; 147 | try { 148 | Gui.logger.info("Checking the revocation status"); 149 | revocationStatus = OCSP.check(end, issuer).getCertStatus().toString(); 150 | Gui.logger.info("Revocation Status is: " + revocationStatus); 151 | } catch (Exception ex) { 152 | if (SigningTool.expired == true) { 153 | Gui.status.append(dateFormat.format(new Date()) + " - Unable to " 154 | + "sign. Revocation Status returned an error.\n" 155 | + dateFormat.format(new Date()) 156 | + " - The signing certificate is expired.\n" 157 | + dateFormat.format(new Date()) 158 | + " - Expiration Date: " 159 | + end.getNotAfter().toString() 160 | + "\n"); 161 | System.out.println("Unable to sign. The signing certificate " 162 | + "is expired. Also, unable revocation status " 163 | + "returned an error."); 164 | Gui.logger.log(Level.FINEST, ex.getMessage(), ex); 165 | return null; 166 | } else { 167 | Gui.status.append(dateFormat.format(new Date()) 168 | + " - Unable to get revocation status.\n "); 169 | System.out.println("Unable to sign. The revocation " 170 | + "check for your signing cert failed. If you " 171 | + "believe this is in err, disable revocation " 172 | + "checking in the menu."); 173 | Gui.logger.log(Level.FINEST, ex.getMessage(), ex); 174 | return null; 175 | } 176 | 177 | } 178 | Gui.logger.finest("Returning the following revocation status: " 179 | + revocationStatus); 180 | return revocationStatus; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/app/Gui.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Component; 5 | import java.awt.event.ActionEvent; 6 | import java.awt.event.ActionListener; 7 | import java.awt.event.WindowAdapter; 8 | import java.awt.event.WindowEvent; 9 | import java.util.List; 10 | import java.io.File; 11 | import java.text.DateFormat; 12 | import java.text.SimpleDateFormat; 13 | import java.util.Date; 14 | import java.util.logging.FileHandler; 15 | import java.util.logging.Level; 16 | import java.util.logging.Logger; 17 | import java.util.logging.SimpleFormatter; 18 | import javax.swing.GroupLayout; 19 | import javax.swing.ImageIcon; 20 | import javax.swing.JFileChooser; 21 | import javax.swing.JFrame; 22 | import javax.swing.JOptionPane; 23 | import javax.swing.JPanel; 24 | import javax.swing.JProgressBar; 25 | import javax.swing.SwingUtilities; 26 | import javax.swing.SwingWorker; 27 | 28 | public class Gui { 29 | protected static JFrame frame = 30 | new JFrame("GSA Document Signing Tool 2.0"); 31 | protected static Logger logger = Logger.getAnonymousLogger(); 32 | protected static String revocationStatus = "Not Checked"; 33 | protected static String serialNum = null; 34 | protected static String notAfterDate = null; 35 | protected File file = null; 36 | protected SigningTool pkcs7sign = null; 37 | protected SigningToolVerifier pkcs7unpack = null; 38 | protected static DateFormat dateFormat = 39 | new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 40 | protected static Date date = new Date(); 41 | protected static DateFormat logDate = 42 | new SimpleDateFormat("yyyy-MM-dd"); 43 | protected static int counter = 0; 44 | protected JFileChooser fileChooser = new JFileChooser(); 45 | protected static boolean errors = false; 46 | private volatile boolean done = false; 47 | protected static int progressValue = 0; 48 | protected static SwingWorker worker; 49 | protected static FileHandler fh; 50 | 51 | private javax.swing.JButton browseButton; 52 | private javax.swing.JMenuItem closeApp; 53 | private javax.swing.JLabel fileDestLabel; 54 | private javax.swing.JTextField fileDestination; 55 | private javax.swing.JTextField fileInput; 56 | private javax.swing.JMenu fileMenu; 57 | private javax.swing.JMenu helpMenu; 58 | private javax.swing.JMenuBar menuBar; 59 | private javax.swing.JMenuItem aboutMenu; 60 | private javax.swing.JScrollPane statusScrollPane; 61 | private javax.swing.JMenu menuFile; 62 | private javax.swing.JMenuItem openFile; 63 | private javax.swing.JMenu optionsMenu; 64 | private javax.swing.JPasswordField pin; 65 | private javax.swing.JLabel pinLabel; 66 | protected static javax.swing.JProgressBar progress; 67 | protected static javax.swing.JCheckBoxMenuItem revocationCheckBox; 68 | protected javax.swing.JButton signButton; 69 | protected javax.swing.JButton verifyButton; 70 | protected static javax.swing.JTextArea status; 71 | private javax.swing.JLabel statusLabel; 72 | private GroupLayout layout; 73 | private JPanel pane; 74 | 75 | 76 | public Component createComponents(JFrame frame) { 77 | 78 | menuBar = new javax.swing.JMenuBar(); 79 | fileMenu = new javax.swing.JMenu(); 80 | browseButton = new javax.swing.JButton(); 81 | fileInput = new javax.swing.JTextField(); 82 | fileDestLabel = new javax.swing.JLabel(); 83 | fileDestination = new javax.swing.JTextField(); 84 | signButton = new javax.swing.JButton(); 85 | verifyButton = new javax.swing.JButton(); 86 | statusLabel = new javax.swing.JLabel(); 87 | statusScrollPane = new javax.swing.JScrollPane(); 88 | status = new javax.swing.JTextArea(); 89 | pin = new javax.swing.JPasswordField(); 90 | pinLabel = new javax.swing.JLabel(); 91 | progress = new javax.swing.JProgressBar(); 92 | menuBar = new javax.swing.JMenuBar(); 93 | menuFile = new javax.swing.JMenu(); 94 | openFile = new javax.swing.JMenuItem(); 95 | closeApp = new javax.swing.JMenuItem(); 96 | optionsMenu = new javax.swing.JMenu(); 97 | revocationCheckBox = new javax.swing.JCheckBoxMenuItem(); 98 | helpMenu = new javax.swing.JMenu(); 99 | aboutMenu = new javax.swing.JMenuItem(); 100 | pane = new JPanel(); 101 | layout = new GroupLayout(pane); 102 | 103 | // Settings for progress status bar 104 | progress.setIndeterminate(false); 105 | progress.setStringPainted(true); 106 | 107 | browseButton.setMnemonic('o'); 108 | browseButton.setText("Open"); 109 | browseButton.setToolTipText("Click to select a file to sign"); 110 | browseButton.addActionListener(new java.awt.event.ActionListener() { 111 | public void actionPerformed(java.awt.event.ActionEvent evt) { 112 | browseButtonActionPerformed(evt); 113 | } 114 | }); 115 | 116 | fileInput.setEditable(false); 117 | fileInput.setText("Please select a file to sign or unpack"); 118 | fileInput.setToolTipText("Click the open button to select a file"); 119 | 120 | fileDestLabel.setText("File Destination:"); 121 | fileDestLabel.setToolTipText("File Destination:"); 122 | 123 | fileDestination.setEditable(false); 124 | fileDestination.setText("No file selected"); 125 | fileDestination.setToolTipText("This is the file destination of " 126 | + "the file you would like signed or unpacked."); 127 | 128 | signButton.setMnemonic('s'); 129 | signButton.setText("Sign"); 130 | signButton.setToolTipText("Click to sign file selected"); 131 | signButton.addActionListener(new ActionListener() { 132 | @Override 133 | public void actionPerformed(ActionEvent e) { 134 | progress.setValue(0); 135 | status.setText(dateFormat.format(new Date()) 136 | + " - Applying Signature\n"); 137 | progress.setValue(8); 138 | worker = createWorker(status, progress); 139 | worker.execute(); 140 | } 141 | }); 142 | 143 | verifyButton.setMnemonic('u'); 144 | verifyButton.setText("Unpack"); 145 | verifyButton.setToolTipText("Click to unpack file selected"); 146 | verifyButton.addActionListener(new ActionListener() { 147 | @Override 148 | public void actionPerformed(ActionEvent e) { 149 | progress.setValue(0); 150 | status.setText(dateFormat.format(new Date()) 151 | + " - Unpacking File\n"); 152 | progress.setValue(8); 153 | worker = createVerifyWorker(status, progress); 154 | worker.execute(); 155 | } 156 | }); 157 | 158 | statusLabel.setText("Status:"); 159 | 160 | status.setEditable(false); 161 | status.setColumns(20); 162 | status.setFont(new java.awt.Font("Tahoma", 0, 11)); 163 | status.setRows(5); 164 | status.setAutoscrolls(false); 165 | status.setText(dateFormat.format(date) 166 | + " - Select a file, enter your PIN #, and then Click the Sign button.\n"); 167 | 168 | statusScrollPane.setViewportView(status); 169 | 170 | pin.setToolTipText("Please Enter your card's PIN Number"); 171 | pin.setName("pin"); // NOI18N 172 | 173 | pinLabel.setText("Enter PIN:"); 174 | pinLabel.setToolTipText("Enter PIN Label"); 175 | 176 | menuFile.setMnemonic('f'); 177 | menuFile.setText("File"); 178 | 179 | openFile.setAccelerator(javax.swing.KeyStroke.getKeyStroke( 180 | java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK)); 181 | openFile.setIcon(new javax.swing.ImageIcon(getClass().getResource( 182 | "/com/gsa/signingtool/images/open.png"))); // NOI18N 183 | openFile.setMnemonic('o'); 184 | openFile.setText("Open"); 185 | openFile.setToolTipText("Open a file to sign"); 186 | openFile.setInheritsPopupMenu(true); 187 | openFile.addActionListener(new java.awt.event.ActionListener() { 188 | public void actionPerformed(java.awt.event.ActionEvent evt) { 189 | openFileActionPerformed(evt); 190 | } 191 | }); 192 | menuFile.add(openFile); 193 | 194 | closeApp.setAccelerator(javax.swing.KeyStroke.getKeyStroke( 195 | java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_MASK)); 196 | closeApp.setIcon(new javax.swing.ImageIcon( 197 | getClass().getResource("/com/gsa/signingtool/images/close.png"))); 198 | closeApp.setText("Close"); 199 | closeApp.setToolTipText("Close Application"); 200 | closeApp.addActionListener(new java.awt.event.ActionListener() { 201 | public void actionPerformed(java.awt.event.ActionEvent evt) { 202 | System.exit(0); 203 | } 204 | }); 205 | menuFile.add(closeApp); 206 | closeApp.getAccessibleContext().setAccessibleParent(menuBar); 207 | 208 | optionsMenu.setMnemonic('p'); 209 | optionsMenu.setText("Options"); 210 | optionsMenu.setToolTipText("Options Menu Item"); 211 | revocationCheckBox.setAccelerator(javax.swing.KeyStroke.getKeyStroke( 212 | java.awt.event.KeyEvent.VK_E, java.awt.event.InputEvent.CTRL_MASK)); 213 | revocationCheckBox.setSelected(true); 214 | revocationCheckBox.setText("Enable Revocation Checking"); 215 | revocationCheckBox.setToolTipText("Click to toggle revocation checking"); 216 | optionsMenu.add(revocationCheckBox); 217 | 218 | helpMenu.setMnemonic('h'); 219 | helpMenu.setText("Help"); 220 | helpMenu.setToolTipText("Help Menu Item"); 221 | 222 | aboutMenu.setAccelerator(javax.swing.KeyStroke.getKeyStroke( 223 | java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.CTRL_MASK)); 224 | aboutMenu.setIcon(new javax.swing.ImageIcon( 225 | getClass().getResource("/com/gsa/signingtool/images/info.png"))); // NOI18N 226 | aboutMenu.setText("About"); 227 | aboutMenu.addActionListener(new java.awt.event.ActionListener() { 228 | public void actionPerformed(java.awt.event.ActionEvent evt) { 229 | aboutMenuActionPerformed(evt); 230 | } 231 | }); 232 | helpMenu.add(aboutMenu); 233 | 234 | 235 | // add menuBar items and menuBar to the frame 236 | menuBar.add(menuFile); 237 | menuBar.add(optionsMenu); 238 | menuBar.add(helpMenu); 239 | 240 | frame.setJMenuBar(menuBar); 241 | 242 | browseButton.getAccessibleContext().setAccessibleName("Open Button"); 243 | browseButton.getAccessibleContext().setAccessibleDescription( 244 | "Click button to open a file to sign"); 245 | browseButton.getAccessibleContext().setAccessibleParent(frame); 246 | fileInput.getAccessibleContext().setAccessibleName("File selected"); 247 | fileInput.getAccessibleContext().setAccessibleDescription( 248 | "Please select a file to sign"); 249 | fileInput.getAccessibleContext().setAccessibleParent(frame); 250 | fileDestLabel.getAccessibleContext().setAccessibleParent(frame); 251 | fileDestination.getAccessibleContext().setAccessibleName( 252 | "File Destination"); 253 | signButton.getAccessibleContext().setAccessibleName("Sign Button"); 254 | signButton.getAccessibleContext().setAccessibleDescription( 255 | "Click button to sign a file"); 256 | signButton.getAccessibleContext().setAccessibleParent(frame); 257 | verifyButton.getAccessibleContext().setAccessibleDescription( 258 | "Click button to unpack a file"); 259 | verifyButton.getAccessibleContext().setAccessibleName( 260 | "Unpack Button"); 261 | verifyButton.getAccessibleContext().setAccessibleParent(frame); 262 | pin.getAccessibleContext().setAccessibleName("PIN Number"); 263 | pin.getAccessibleContext().setAccessibleDescription( 264 | "Text field for entering your PIN Number"); 265 | pin.getAccessibleContext().setAccessibleParent(frame); 266 | pinLabel.getAccessibleContext().setAccessibleName("PIN Label"); 267 | pinLabel.getAccessibleContext().setAccessibleParent(frame); 268 | status.getAccessibleContext().setAccessibleName("Status"); 269 | status.getAccessibleContext().setAccessibleParent(frame); 270 | status.getAccessibleContext().setAccessibleDescription( 271 | "Scroll pane that shows the status of the signing tool"); 272 | 273 | // Set application default parameters 274 | frame.getAccessibleContext().setAccessibleDescription( 275 | "GSA Document Signing Tool"); 276 | frame.setIconImage(new ImageIcon(getClass().getResource( 277 | "/com/gsa/signingtool/images/icon.png")).getImage()); 278 | 279 | pane.setLayout(layout); 280 | layout.setHorizontalGroup( 281 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 282 | .addGroup(layout.createSequentialGroup() 283 | .addGap(18, 18, 18) 284 | .addGroup(layout.createParallelGroup( 285 | javax.swing.GroupLayout.Alignment.LEADING, false) 286 | .addComponent(signButton, javax.swing.GroupLayout.DEFAULT_SIZE, 287 | javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 288 | .addComponent(verifyButton, javax.swing.GroupLayout.DEFAULT_SIZE, 289 | javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 290 | .addComponent(fileDestLabel, javax.swing.GroupLayout.Alignment.TRAILING, 291 | javax.swing.GroupLayout.DEFAULT_SIZE, 292 | javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 293 | .addComponent(statusLabel, javax.swing.GroupLayout.Alignment.TRAILING) 294 | .addComponent(pinLabel, javax.swing.GroupLayout.Alignment.TRAILING) 295 | .addComponent(browseButton, javax.swing.GroupLayout.Alignment.TRAILING, 296 | javax.swing.GroupLayout.PREFERRED_SIZE, 77, 297 | javax.swing.GroupLayout.PREFERRED_SIZE)) 298 | .addGap(18, 18, 18) 299 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 300 | .addComponent(progress, javax.swing.GroupLayout.PREFERRED_SIZE, 301 | 450, javax.swing.GroupLayout.PREFERRED_SIZE) 302 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) 303 | .addComponent(pin, javax.swing.GroupLayout.PREFERRED_SIZE, 304 | 100, javax.swing.GroupLayout.PREFERRED_SIZE) 305 | .addComponent(fileInput) 306 | .addComponent(fileDestination, javax.swing.GroupLayout.PREFERRED_SIZE, 307 | 450, javax.swing.GroupLayout.PREFERRED_SIZE)) 308 | .addComponent(statusScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 309 | 450, javax.swing.GroupLayout.PREFERRED_SIZE)) 310 | .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 311 | ); 312 | 313 | layout.setVerticalGroup( 314 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 315 | .addGroup(layout.createSequentialGroup() 316 | .addContainerGap() 317 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 318 | .addComponent(fileInput, javax.swing.GroupLayout.PREFERRED_SIZE, 319 | javax.swing.GroupLayout.DEFAULT_SIZE, 320 | javax.swing.GroupLayout.PREFERRED_SIZE) 321 | .addComponent(browseButton)) 322 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 323 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 324 | .addComponent(fileDestLabel) 325 | .addComponent(fileDestination, javax.swing.GroupLayout.PREFERRED_SIZE, 326 | javax.swing.GroupLayout.DEFAULT_SIZE, 327 | javax.swing.GroupLayout.PREFERRED_SIZE)) 328 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 329 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 330 | .addComponent(pinLabel) 331 | .addComponent(pin, javax.swing.GroupLayout.PREFERRED_SIZE, 332 | javax.swing.GroupLayout.DEFAULT_SIZE, 333 | javax.swing.GroupLayout.PREFERRED_SIZE)) 334 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 335 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 336 | .addComponent(statusLabel) 337 | .addComponent(progress, javax.swing.GroupLayout.PREFERRED_SIZE, 23, 338 | javax.swing.GroupLayout.PREFERRED_SIZE)) 339 | .addGap(18, 18, 18) 340 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 341 | .addGroup(layout.createSequentialGroup() 342 | .addComponent(signButton) 343 | .addGap(18,18,18) 344 | .addComponent(verifyButton) 345 | .addGap(0, 0, Short.MAX_VALUE)) 346 | .addComponent(statusScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 347 | 174, Short.MAX_VALUE)) 348 | .addContainerGap() 349 | )); 350 | frame.pack(); 351 | return pane; 352 | } 353 | 354 | private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) { 355 | int returnVal = fileChooser.showOpenDialog(frame); 356 | if(returnVal == JFileChooser.APPROVE_OPTION) { 357 | file = fileChooser.getSelectedFile(); 358 | fileInput.setText(file.getAbsolutePath()); 359 | fileDestination.setText(file.getAbsolutePath().substring( 360 | 0,file.getAbsolutePath().lastIndexOf(File.separator))); 361 | } 362 | } 363 | 364 | private void openFileActionPerformed(java.awt.event.ActionEvent evt) { 365 | int returnVal = fileChooser.showOpenDialog(frame); 366 | if(returnVal == JFileChooser.APPROVE_OPTION) { 367 | file = fileChooser.getSelectedFile(); 368 | fileInput.setText(file.getAbsolutePath()); 369 | fileDestination.setText(file.getAbsolutePath().substring( 370 | 0,file.getAbsolutePath().lastIndexOf(File.separator))); 371 | } 372 | } 373 | 374 | private void aboutMenuActionPerformed(java.awt.event.ActionEvent evt) { 375 | JOptionPane.showMessageDialog(frame, "The GSA Document Signing Tool " 376 | + "is a free tool provided\n" 377 | + " by the General Services Administration (GSA). The primary\n" 378 | + " use of this tool is intended for users to be able to\n" 379 | + " digitally sign a file using their PIV card and submit\n" 380 | + " this file to the Federal Register.\n\n" 381 | + " Please use the contact us form on idmanagement.gov\n" 382 | + " to submit any questions regarding this tool.\n\n", 383 | "About the PKCS#7 Signing Tool", 1); 384 | 385 | } 386 | 387 | public SwingWorker createVerifyWorker( 388 | final javax.swing.JTextArea status, final JProgressBar progress) { 389 | return new SwingWorker() { 390 | @Override 391 | protected Boolean doInBackground() throws Exception { 392 | if (file == null) { 393 | logger.severe("No file was selected"); 394 | String updateText = (dateFormat.format(new Date()) 395 | + " - No file selected. Please select a file to sign.\n"); 396 | errors=true; 397 | progress.setValue(100); 398 | publish(updateText); 399 | } else { 400 | errors=false; 401 | pkcs7unpack = new SigningToolVerifier(file); 402 | } 403 | return true; 404 | } 405 | 406 | @Override 407 | protected void process(List chunks) { 408 | super.process(chunks); 409 | for (String chunk : chunks) { 410 | status.append(chunk); 411 | progress.setValue(progress.getValue() + 1); 412 | } 413 | } 414 | 415 | @Override 416 | protected void done() { 417 | try { 418 | Boolean ack = get(); 419 | if (Boolean.TRUE.equals(ack)) { 420 | if (errors == false) { 421 | logger.info("File was verified/unpacked successfully" 422 | + " with no errors."); 423 | status.append(dateFormat.format(new Date()) 424 | + " - File has been successfully unpacked."); 425 | } else { 426 | logger.severe("Errors were found while " 427 | + "unpacking action was running"); 428 | } 429 | } 430 | } catch (Exception e) { 431 | e.printStackTrace(); 432 | } 433 | } 434 | }; 435 | } 436 | public SwingWorker createWorker( 437 | final javax.swing.JTextArea status, final JProgressBar progress) { 438 | return new SwingWorker() { 439 | @Override 440 | protected Boolean doInBackground() throws Exception { 441 | revocationStatus = "Not Checked"; 442 | if (pin.getPassword().length ==0) { 443 | logger.severe("PIN is empty"); 444 | String updateText = dateFormat.format(new Date()) 445 | + " - PIN field is empty. Please enter a valid PIN #.\n"; 446 | errors=true; 447 | progress.setValue(100); 448 | publish(updateText); 449 | 450 | } else if(file == null) { 451 | logger.severe("No file was selected"); 452 | String updateText = (dateFormat.format(new Date()) 453 | + " - No file selected. Please select a file to sign.\n"); 454 | errors=true; 455 | progress.setValue(100); 456 | publish(updateText); 457 | 458 | } else { 459 | errors=false; 460 | pkcs7sign = new SigningTool(file, pin.getPassword()); 461 | } 462 | return true; 463 | } 464 | 465 | @Override 466 | protected void process(List chunks) { 467 | super.process(chunks); 468 | for (String chunk : chunks) { 469 | status.append(chunk); 470 | progress.setValue(progress.getValue() + 1); 471 | } 472 | } 473 | 474 | @Override 475 | protected void done() { 476 | try { 477 | Boolean ack = get(); 478 | if (Boolean.TRUE.equals(ack)) { 479 | if (errors == false) { 480 | logger.info("File was signed successfully with no errors."); 481 | 482 | status.append(dateFormat.format(new Date()) 483 | + " - Signing Cert Expiration Date: " 484 | + notAfterDate 485 | + "\n" + dateFormat.format(new Date()) 486 | + " - Signing Cert Revocation Status: " 487 | + revocationStatus 488 | + "\n" 489 | + dateFormat.format(new Date()) 490 | + " - File has been successfully signed."); 491 | } else { 492 | logger.severe("Errors were found when " 493 | + "signing action was completed"); 494 | } 495 | } 496 | } catch (Exception e) { 497 | e.printStackTrace(); 498 | 499 | } 500 | 501 | } 502 | }; 503 | } 504 | public static void main(String args[]) { 505 | 506 | 507 | /* Set the Nimbus look and feel */ 508 | // 509 | /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. 510 | * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 511 | */ 512 | try { 513 | for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { 514 | if ("Nimbus".equals(info.getName())) { 515 | //javax.swing.UIManager.setLookAndFeel(info.getClassName()); 516 | javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 517 | break; 518 | } 519 | } 520 | } catch (ClassNotFoundException ex) { 521 | java.util.logging.Logger.getLogger(Gui.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 522 | } catch (InstantiationException ex) { 523 | java.util.logging.Logger.getLogger(Gui.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 524 | } catch (IllegalAccessException ex) { 525 | java.util.logging.Logger.getLogger(Gui.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 526 | } catch (javax.swing.UnsupportedLookAndFeelException ex) { 527 | java.util.logging.Logger.getLogger(Gui.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 528 | } 529 | // 530 | try { 531 | fh = new FileHandler("logs\\log-" + logDate.format(new Date()) 532 | + ".txt", true); 533 | logger.addHandler(fh); 534 | fh.setFormatter(new SimpleFormatter()); 535 | logger.setLevel(Level.FINEST); 536 | SwingUtilities.invokeLater(new Runnable() { 537 | public void run() { 538 | 539 | Gui gui = new Gui(); 540 | Component content = gui.createComponents(frame); 541 | frame.getContentPane().add(content, BorderLayout.CENTER); 542 | 543 | frame.addWindowListener(new WindowAdapter() { 544 | public void windowClosing(WindowEvent e) { 545 | fh.close(); 546 | System.exit(0); 547 | } 548 | }); 549 | frame.pack(); 550 | frame.setLocationRelativeTo(null); 551 | frame.setVisible(true); 552 | } 553 | }); 554 | } catch(Exception e) { 555 | e.printStackTrace(); 556 | } 557 | logger.info("Launching the GSA Document Signing Tool Application..."); 558 | } 559 | 560 | } 561 | -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/app/SelectSlot.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.Date; 6 | import java.util.List; 7 | import java.util.ListIterator; 8 | import java.util.logging.Level; 9 | import javax.smartcardio.CardException; 10 | import javax.smartcardio.CardTerminal; 11 | import javax.smartcardio.TerminalFactory; 12 | import static com.gsa.signingtool.app.Gui.dateFormat; 13 | import static com.gsa.signingtool.app.Gui.logger; 14 | import sun.security.pkcs11.wrapper.CK_C_INITIALIZE_ARGS; 15 | import sun.security.pkcs11.wrapper.CK_INFO; 16 | import sun.security.pkcs11.wrapper.CK_SLOT_INFO; 17 | import sun.security.pkcs11.wrapper.CK_TOKEN_INFO; 18 | import sun.security.pkcs11.wrapper.PKCS11; 19 | 20 | public class SelectSlot { 21 | private static PKCS11 pkcs11 = null; 22 | private static long[] slotList = null; 23 | private static ArrayList slotReturn = new ArrayList(); 24 | private static TerminalFactory factory = null; 25 | private static List terminals = null; 26 | private static ListIterator terminalsIterator = null; 27 | private static CardTerminal terminal = null; 28 | private static boolean cardPresent = false; 29 | private static ArrayList readers = new ArrayList(); 30 | private static int slotCount = 0; 31 | private static CK_C_INITIALIZE_ARGS initArgs = null; 32 | private static CK_SLOT_INFO slotInfo = null; 33 | private static CK_TOKEN_INFO tokenInfo = null; 34 | private static CK_INFO info = null; 35 | private static String compareReader = null; 36 | 37 | protected static ArrayList selectCardTerminal() { 38 | try { 39 | try { 40 | logger.info("Retrieving the list of readers " 41 | + "available on system."); 42 | factory = TerminalFactory.getDefault(); 43 | terminals = factory.terminals().list(); 44 | } catch (CardException ex) { 45 | logger.severe("No readers found. Please verify your " 46 | + "card reader is connected."); 47 | Gui.status.append(dateFormat.format(new Date()) 48 | + " - No readers found.\n" 49 | + dateFormat.format(new Date()) 50 | + " - Please verify your card reader is connected.\n"); 51 | Gui.errors = true; 52 | logger.log(Level.FINEST, ex.getMessage(), ex); 53 | Gui.progress.setValue(100); 54 | return null; 55 | } 56 | 57 | terminalsIterator = terminals.listIterator(); 58 | logger.info("Checking # of readers on system connected"); 59 | if(terminals.size() == 1) { 60 | logger.info("Found only 1 reader connected on the system"); 61 | while(terminalsIterator.hasNext()) { 62 | terminal = terminalsIterator.next(); 63 | logger.info("Checking to see if a card is " 64 | + "inserted into the reader"); 65 | cardPresent = terminal.isCardPresent(); 66 | Gui.status.append(dateFormat.format(new Date()) 67 | + " - Verifying card is inserted into the reader.\n"); 68 | Gui.progress.setValue(30); 69 | if(cardPresent) { 70 | logger.info("Found a card present in: " 71 | + terminal.getName()); 72 | Gui.status.append(dateFormat.format(new Date()) 73 | + " - Found reader with card present.\n" 74 | + dateFormat.format(new Date()) 75 | + " - " 76 | + terminal.getName() 77 | + "\n"); 78 | readers.add(terminal.getName()); 79 | Gui.progress.setValue(40); 80 | } else { 81 | logger.severe("No card present, please insert card"); 82 | Gui.status.append(dateFormat.format(new Date()) 83 | + " - No card present, please insert card.\n"); 84 | Gui.errors = true; 85 | Gui.progress.setValue(100); 86 | return null; 87 | } 88 | } 89 | } else { 90 | logger.info("More than 1 reader found connected on system"); 91 | int i = 0; 92 | while(terminalsIterator.hasNext()) { 93 | terminal = terminalsIterator.next(); 94 | cardPresent = terminal.isCardPresent(); 95 | logger.info("Detecting if more than 1 reader has a card inserted"); 96 | if (cardPresent) { 97 | readers.add(terminal.getName()); 98 | System.out.println("Inside If = " + i); 99 | logger.info("Found a card present in: " + terminal.getName()); 100 | Gui.status.append(dateFormat.format(new Date()) 101 | + " - Found reader with card present.\n" 102 | + dateFormat.format(new Date()) + " - " 103 | + terminal.getName() 104 | + "\n"); 105 | Gui.progress.setValue(40); 106 | break; 107 | } else { 108 | System.out.println("Outside If = " + i); 109 | logger.info("No card found in the following reader: " 110 | + terminal.getName()); 111 | System.err.println("No card present in this reader" 112 | + terminal.getName()); 113 | } 114 | i++; 115 | } 116 | 117 | } 118 | 119 | if (readers.size() == 1) { 120 | logger.info("Found 1 reader and determining slot id#"); 121 | 122 | // Setting up the items necessary for determining the # of slots 123 | logger.info("initializing reader arguements"); 124 | initArgs = new CK_C_INITIALIZE_ARGS(); 125 | initArgs.flags = 0; 126 | 127 | String libFile = new File("").getAbsolutePath() 128 | + "\\lib\\opensc-pkcs11.dll"; 129 | pkcs11 = PKCS11.getInstance(libFile, "C_GetFunctionList", initArgs, false); 130 | slotList = pkcs11.C_GetSlotList(true); 131 | slotCount = slotList.length; 132 | 133 | //loop through the available slots and return slot id 134 | logger.info("looping through the available slots"); 135 | if (slotCount >= 1) { 136 | for (long slot : slotList) { 137 | slotInfo = pkcs11.C_GetSlotInfo(slot); 138 | tokenInfo = pkcs11.C_GetTokenInfo(slot); 139 | info = pkcs11.C_GetInfo(); 140 | compareReader = new String(slotInfo.slotDescription); 141 | for (String readerMatch : readers) { 142 | long[] temp = null; 143 | readerMatch = readerMatch.replaceAll("\\s+",""); 144 | compareReader =compareReader.replaceAll("\\s",""); 145 | if (readerMatch.equals(compareReader)) { 146 | slotReturn.add(slot); 147 | } 148 | } 149 | } 150 | } else { 151 | logger.severe("Unable to find a slot id"); 152 | Gui.status.append(dateFormat.format(new Date()) 153 | + " - Issue with card reader.\n" 154 | + dateFormat.format(new Date()) 155 | + " - Please check connection or try a new reader.\n"); 156 | Gui.errors = true; 157 | Gui.progress.setValue(100); 158 | return null; 159 | } 160 | } 161 | } catch (Exception e) { 162 | logger.log(Level.FINEST, e.getMessage(), e); 163 | Gui.status.append(dateFormat.format(new Date()) 164 | + " - Error Getting Card Information From Reader.\n" 165 | + dateFormat.format(new Date()) 166 | + " - Please check reader and card connection.\n"); 167 | Gui.errors = true; 168 | Gui.progress.setValue(100); 169 | return null; 170 | } 171 | logger.info("Returning an ArrayList of slot IDs"); 172 | return slotReturn; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/app/SigningTool.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.security.KeyStore; 8 | import java.security.PrivateKey; 9 | import java.security.Provider; 10 | import java.security.Security; 11 | import java.security.cert.Certificate; 12 | import java.security.cert.X509Certificate; 13 | import java.util.ArrayList; 14 | import java.util.Date; 15 | import java.util.Enumeration; 16 | import java.util.logging.Level; 17 | import org.bouncycastle.cert.jcajce.JcaCertStore; 18 | import org.bouncycastle.cms.CMSProcessableByteArray; 19 | import org.bouncycastle.cms.CMSSignedData; 20 | import org.bouncycastle.cms.CMSSignedDataGenerator; 21 | import org.bouncycastle.cms.CMSTypedData; 22 | import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; 23 | import org.bouncycastle.operator.ContentSigner; 24 | import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; 25 | import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; 26 | import org.bouncycastle.util.Store; 27 | import static com.gsa.signingtool.app.Gui.dateFormat; 28 | import static com.gsa.signingtool.app.Gui.logger; 29 | import sun.security.pkcs11.SunPKCS11; 30 | 31 | public class SigningTool { 32 | 33 | protected String errorDesc = null; 34 | protected String filenameDest = null; 35 | protected String readerStatus = null; 36 | protected String cardStatus = null; 37 | protected String fileStatus = null; 38 | protected long slotID = 0; 39 | protected X509Certificate userCert = null; 40 | private PrivateKey privateKey = null; 41 | private Provider sun = null; 42 | private Provider bc = null; 43 | protected ArrayList readers = null; 44 | private KeyStore piv = null; 45 | protected byte[] fileBytes = null; 46 | protected StringBuffer sb = new StringBuffer(); 47 | protected ArrayList signingCerts = new ArrayList(); 48 | protected static boolean expired = false; 49 | 50 | protected SigningTool(File file, char[] pin) { 51 | if (file != null) { 52 | logger.info("Converting selected file to bytes"); 53 | fileBytes = getFileContentBytes(file); 54 | } else { 55 | logger.severe("File selected is empty"); 56 | Gui.status.append(dateFormat.format(new Date()) 57 | + " - File is empty.\n"); 58 | return; 59 | } 60 | try { 61 | if (sun != null) { 62 | logger.info("Sun Provider is not null. Logging out of card"); 63 | ((SunPKCS11) sun).logout(); 64 | } 65 | logger.info("Initiating communication with reader"); 66 | Gui.progress.setValue(15); 67 | Gui.status.append(dateFormat.format(new Date()) 68 | + " - Detecting card reader.\n"); 69 | readers = SelectSlot.selectCardTerminal(); 70 | 71 | logger.info("Selecting the first card reader slot " 72 | + "found in ArrayList"); 73 | if (readers.isEmpty()) { 74 | logger.severe("Issue selecting card reader and verifying " 75 | + "card is inserted."); 76 | Gui.status.append(dateFormat.format(new Date()) 77 | + " - Issue detecting card reader and/or if card " 78 | + "is inserted.\n"); 79 | Gui.errors = true; 80 | Gui.progress.setValue(100); 81 | return; 82 | } else { 83 | slotID = readers.get(0); 84 | } 85 | 86 | String libFile = "\"" + new File("").getAbsolutePath() 87 | + "\\lib\\opensc-pkcs11.dll\""; 88 | libFile = libFile.replace("\\", "/"); 89 | logger.info(libFile); 90 | String configName = "name=" 91 | + "opensc" 92 | + "\n" 93 | + "library=" 94 | + libFile 95 | + "\n" 96 | + "slot=" 97 | + slotID; 98 | logger.info("Output of information needed to connect SunPKCS11" 99 | + " Provider.\n" 100 | + configName); 101 | byte[] pkcs11configBytes = configName.getBytes(); 102 | ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11configBytes); 103 | bc = new org.bouncycastle.jce.provider.BouncyCastleProvider(); 104 | logger.info("Adding a Bouncy Castle provider"); 105 | Security.addProvider(bc); 106 | logger.info("Trying to add SunPKCS11 provider"); 107 | sun = new sun.security.pkcs11.SunPKCS11(confStream); 108 | Security.addProvider(sun); 109 | try { 110 | //KeyStore.PasswordProtection pp = new KeyStore.PasswordProtection(pin); 111 | piv = KeyStore.getInstance("PKCS11", sun); 112 | logger.info("Trying to connect to smart card using SunPKCS11 " 113 | + "and user PIN"); 114 | piv.load(null, pin); 115 | Gui.progress.setValue(60); 116 | Gui.status.append(dateFormat.format(new Date()) 117 | + " - Validating PIN number.\n"); 118 | } catch (Exception ex) { 119 | logger.log(Level.FINEST, ex.getMessage(), ex); 120 | ((SunPKCS11) sun).logout(); 121 | Security.removeProvider(sun.getName()); 122 | Security.removeProvider(bc.getName()); 123 | Gui.status.append(dateFormat.format(new Date()) 124 | + " - Unable to validate PIN. Verify PIN is correct.\n"); 125 | Gui.progress.setValue(100); 126 | Gui.errors = true; 127 | return; 128 | } 129 | 130 | Gui.logger.info("Looping through certificates on card"); 131 | Enumeration aliasesEnum = piv.aliases(); 132 | while (aliasesEnum.hasMoreElements()) { 133 | boolean[] keyUsage = null; 134 | String alias = (String)aliasesEnum.nextElement(); 135 | Certificate[] certificationChain = piv.getCertificateChain(alias); 136 | 137 | for (X509Certificate certificate : (X509Certificate[]) certificationChain) { 138 | Gui.logger.finest(certificate.getSubjectDN().toString()); 139 | } 140 | Certificate cert = piv.getCertificate(alias); 141 | X509Certificate x509 = (X509Certificate)cert; 142 | keyUsage = x509.getKeyUsage(); 143 | if (keyUsage[0] && keyUsage[1]) { 144 | logger.info("Found a signing certificate with Digital" 145 | + " Signature & Non-repudiation!"); 146 | logger.info("Serial Number of Signing Certificate: " 147 | + x509.getSerialNumber()); 148 | privateKey = (PrivateKey) piv.getKey(alias, null); 149 | Gui.notAfterDate = x509.getNotAfter().toString(); 150 | Gui.serialNum = x509.getSerialNumber().toString(); 151 | signingCerts.add(x509); 152 | Gui.progress.setValue(70); 153 | Gui.status.append(dateFormat.format(new Date()) 154 | + " - Found a signing certificate.\n"); 155 | } 156 | } 157 | 158 | if (signingCerts.size()==1) { 159 | logger.info("Found only 1 signing certificate"); 160 | byte[] envelopedBytes = null; 161 | userCert = (X509Certificate)signingCerts.get(0); 162 | X509Certificate issuerCert = null; 163 | String revokeStatus = null; 164 | 165 | try { 166 | logger.info("Checking the expiration date of the " 167 | + "signing certificate"); 168 | userCert.checkValidity(); 169 | Gui.progress.setValue(80); 170 | Gui.status.append(dateFormat.format(new Date()) 171 | + " - Checking expiration date of signing certificate.\n"); 172 | } catch (Exception exc) { 173 | Gui.logger.log(Level.FINEST, exc.getMessage(), exc); 174 | Gui.errors = true; 175 | expired = true; 176 | Gui.status.append(dateFormat.format(new Date()) 177 | + " - Unable to sign. The signing certificate is expired.\n" 178 | + dateFormat.format(new Date()) 179 | + " - Expires: " 180 | + userCert.getNotAfter() 181 | + "\n"); 182 | ((SunPKCS11) sun).logout(); 183 | Security.removeProvider(sun.getName()); 184 | Security.removeProvider(bc.getName()); 185 | Gui.progress.setValue(100); 186 | return; 187 | } 188 | if (Gui.revocationCheckBox.getState()) { 189 | try { 190 | logger.info("Checking Revocation Status of " 191 | + "signing certificate..."); 192 | issuerCert = CheckRevocationStatus.fetchIssuerCert(userCert); 193 | revokeStatus = CheckRevocationStatus.checkRevocation(userCert, issuerCert); 194 | 195 | Gui.revocationStatus = revokeStatus; 196 | if (revokeStatus == "REVOKED") { 197 | Gui.status.append(dateFormat.format(new Date()) 198 | + " - Unable to sign. Signing Certificate " 199 | + "is REVOKED"); 200 | } 201 | } catch (Exception e) { 202 | Gui.status.append(dateFormat.format(new Date()) 203 | + " - Signing Certificate Revocation Status: " 204 | + revokeStatus 205 | + "\n"); 206 | logger.log(Level.FINEST, e.getMessage(), e); 207 | } 208 | } 209 | Store signers = new JcaCertStore(signingCerts); 210 | CMSTypedData msg = new CMSProcessableByteArray(fileBytes); 211 | CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); 212 | logger.info("Trying to create a ContentSigner using SHA256RSA " 213 | + "algorithm, SunPKCS11 Provider, and Signing Cert " 214 | + "Private Key..."); 215 | ContentSigner sha2 = new JcaContentSignerBuilder( 216 | "SHA256withRSA").setProvider("SunPKCS11-opensc").build(privateKey); 217 | logger.info("Trying to add SignerInfo data to CMSSignedDataGenerator..."); 218 | gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder( 219 | new JcaDigestCalculatorProviderBuilder().setProvider( 220 | "BC").build()).build(sha2, userCert)); 221 | Gui.progress.setValue(90); 222 | gen.addCertificates(signers); 223 | logger.info("Trying to generate CMSSignedData object..."); 224 | 225 | CMSSignedData sigData = gen.generate(msg, true); 226 | logger.info("Completed sigData"); 227 | Gui.errors = false; 228 | 229 | envelopedBytes = sigData.getEncoded(); 230 | logger.info("Logging out of card/reader"); 231 | ((SunPKCS11) sun).logout(); 232 | Security.removeProvider(sun.getName()); 233 | Security.removeProvider(bc.getName()); 234 | 235 | if (envelopedBytes != null) { 236 | filenameDest = file.toString() + ".p7m"; 237 | String result = writeBytes(envelopedBytes, filenameDest); 238 | if (result == null) { 239 | System.out.println("Done"); 240 | } else { 241 | System.out.println(result + "\n"); 242 | } 243 | Gui.progress.setValue(100); 244 | } 245 | } else if (signingCerts.size() > 1) { 246 | String tooManySigners = "Unable to sign. More than 1 " 247 | + "signing certificate found."; 248 | Gui.errors = true; 249 | errorDesc = tooManySigners; 250 | Gui.status.append(dateFormat.format(new Date()) 251 | + " - " 252 | + tooManySigners 253 | + "\n"); 254 | logger.severe(tooManySigners); 255 | Gui.progress.setValue(100); 256 | return; 257 | } else { 258 | Gui.errors = true; 259 | errorDesc = "Unable to sign. No signing certificates " 260 | + "found on the card."; 261 | Gui.status.append(dateFormat.format(new Date()) 262 | + " - " 263 | + errorDesc 264 | + "\n"); 265 | logger.severe(errorDesc); 266 | Gui.progress.setValue(100); 267 | return; 268 | } 269 | } catch(Exception e) { 270 | logger.log(Level.FINEST, e.getMessage(), e); 271 | Gui.errors=true; 272 | Gui.progress.setValue(100); 273 | return; 274 | } 275 | } 276 | 277 | public byte[] getFileContentBytes(File file) { 278 | byte[] fileBytes = null; 279 | try { 280 | FileInputStream fis = new FileInputStream(file); 281 | fileBytes = new byte[(int)file.length()]; 282 | fis.read(fileBytes); 283 | fis.close(); 284 | } 285 | catch (Exception x) { 286 | Gui.errors=true; 287 | logger.log(Level.FINEST, x.getMessage(), x); 288 | } 289 | return fileBytes; 290 | } 291 | 292 | public String writeBytes(byte[] dataToSign, String outputFilename) { 293 | try { 294 | FileOutputStream fos = new FileOutputStream(outputFilename); 295 | fos.write(dataToSign); 296 | fos.close(); 297 | return null; 298 | } catch(Exception x) { 299 | Gui.errors=true; 300 | logger.log(Level.FINEST, x.getMessage(), x); 301 | Gui.status.append(dateFormat.format(new Date()) 302 | + " - Error Writing File " 303 | + outputFilename 304 | + ": " 305 | + x.toString() 306 | + "\n"); 307 | return "Error Writing File " 308 | + outputFilename 309 | + ": " 310 | + x.toString(); 311 | } 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/app/SigningToolVerifier.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import static com.gsa.signingtool.app.Gui.logger; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.util.Date; 9 | import org.bouncycastle.cms.CMSProcessable; 10 | import org.bouncycastle.cms.CMSSignedData; 11 | import static com.gsa.signingtool.app.Gui.dateFormat; 12 | import org.apache.commons.io.FilenameUtils; 13 | 14 | public class SigningToolVerifier { 15 | protected SigningToolVerifier(File file) { 16 | byte[] fileBytes = null; 17 | 18 | if (file != null) { 19 | fileBytes = getFileContentBytes(file); 20 | } 21 | System.out.println(fileBytes.length); 22 | System.out.println(unpackP7(fileBytes, file.toString())); 23 | Gui.progress.setValue(100); 24 | } 25 | 26 | public byte[] getFileContentBytes(File file) { 27 | byte[] fileBytes = null; 28 | 29 | try { 30 | FileInputStream fos = new FileInputStream(file); 31 | fileBytes = new byte[(int)file.length()]; 32 | fos.read(fileBytes); 33 | fos.close(); 34 | } catch (Exception x) { 35 | System.out.println("Unable to open " + file); 36 | } 37 | return fileBytes; 38 | } 39 | 40 | public String unpackP7(byte[] bytesToUnpack, String filename) 41 | { 42 | String str = null; 43 | StringBuffer response = new StringBuffer(); 44 | boolean verified = false; 45 | int lastPeriodPos = filename.lastIndexOf('.'); 46 | int flag = 0; 47 | String ext = ""; 48 | try { 49 | ext = FilenameUtils.getExtension(filename); 50 | System.out.println("File Type is: " + ext); 51 | if (ext.equals("p7m")) { 52 | System.out.println("Valid .p7m file."); 53 | CMSSignedData signedData = new CMSSignedData(bytesToUnpack); 54 | CMSProcessable signedContent = signedData.getSignedContent(); 55 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 56 | signedContent.write(baos); 57 | 58 | byte[] fileBytes = baos.toByteArray(); 59 | str = filename.substring(0, lastPeriodPos); 60 | writeBytes(fileBytes, str); 61 | response.append("\n\nUnpacked to " 62 | + str 63 | + "\n"); 64 | Gui.status.append(dateFormat.format(new Date()) 65 | + " - " 66 | + str 67 | + "\n"); 68 | } else { 69 | flag = 1; 70 | throw new Exception(); 71 | } 72 | } catch (Exception e) { 73 | response.append("Unable to unpack " 74 | + filename 75 | + ": " 76 | + e 77 | + "\n"); 78 | if (flag == 1) { 79 | logger.severe("File selected does not have the " 80 | + "appropriate file extension.\n File should " 81 | + "end in a .p7m file extension."); 82 | Gui.status.append(dateFormat.format(new Date()) 83 | + " - File selected does not have the " 84 | + "appropriate file extension (.p7m).\n"); 85 | Gui.errors = true; 86 | Gui.progress.setValue(100); 87 | } else { 88 | logger.severe(e.getMessage()); 89 | Gui.status.append(dateFormat.format(new Date()) 90 | + " - Issue unpacking the signed file. " 91 | + "See log file for more details.\n"); 92 | Gui.errors = true; 93 | Gui.progress.setValue(100); 94 | } 95 | } 96 | return response.toString(); 97 | } 98 | 99 | public Boolean errMessage (String filename) { 100 | int lastPeriodPos = filename.lastIndexOf('.'); 101 | if (!filename.substring(0, lastPeriodPos).equals(".p7m")) { 102 | String errMesg = "Not a valid .p7m file."; 103 | } 104 | return true; 105 | } 106 | public String writeBytes(byte[] bytesToWrite, String paramString) 107 | { 108 | try 109 | { 110 | FileOutputStream fos = new FileOutputStream(paramString); 111 | fos.write(bytesToWrite); 112 | fos.close(); 113 | return null; 114 | } catch (Exception x) { 115 | x.printStackTrace(); 116 | return "Error Writing File " + paramString + ": " + x.toString(); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/app/StatusUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import javax.swing.SwingWorker; 4 | import static com.gsa.signingtool.app.Gui.status; 5 | 6 | public class StatusUpdater extends SwingWorker { 7 | 8 | @Override 9 | protected String doInBackground() throws Exception { 10 | System.out.println(Thread.currentThread().getName()); 11 | String update = "Applying Signature\n"; 12 | status.append(update); 13 | return update; 14 | } 15 | 16 | @Override 17 | public void done() { 18 | try { 19 | System.out.println("DONE"); 20 | } catch (Exception e) { 21 | e.printStackTrace(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/app/SwingWorkerService.java: -------------------------------------------------------------------------------- 1 | package com.gsa.signingtool.app; 2 | 3 | import javax.swing.JCheckBox; 4 | import javax.swing.JFrame; 5 | import javax.swing.JLabel; 6 | import javax.swing.JProgressBar; 7 | import javax.swing.SwingWorker; 8 | import java.awt.BorderLayout; 9 | import java.awt.EventQueue; 10 | import java.lang.reflect.InvocationTargetException; 11 | import java.util.List; 12 | import java.util.concurrent.ExecutionException; 13 | 14 | public class SwingWorkerService { 15 | private static JProgressBar PROGRESS_BAR; 16 | private static JLabel OUTPUT_LABEL; 17 | 18 | private static JFrame createGUI() { 19 | JFrame testFrame = new JFrame( "TestFrame" ); 20 | PROGRESS_BAR = new JProgressBar( ); 21 | PROGRESS_BAR.setMinimum( 0 ); 22 | PROGRESS_BAR.setMaximum( 100 ); 23 | OUTPUT_LABEL = new JLabel( "Processing" ); 24 | 25 | testFrame.getContentPane().add( PROGRESS_BAR, BorderLayout.CENTER ); 26 | testFrame.getContentPane().add( OUTPUT_LABEL, BorderLayout.SOUTH ); 27 | 28 | //add a checkbox as well to proof the UI is still responsive 29 | testFrame.getContentPane().add( new JCheckBox( "Click me to " 30 | + "proof UI is responsive" ), BorderLayout.NORTH ); 31 | testFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 32 | return testFrame; 33 | } 34 | 35 | public static void main( String[] args ) 36 | throws InvocationTargetException, InterruptedException { 37 | EventQueue.invokeAndWait( new Runnable() { 38 | @Override 39 | public void run() { 40 | JFrame frame = createGUI(); 41 | frame.pack(); 42 | frame.setVisible( true ); 43 | } 44 | } 45 | ); 46 | 47 | //start the SwingWorker outside the EDT 48 | MySwingWorker worker = new MySwingWorker( PROGRESS_BAR ); 49 | worker.execute(); 50 | } 51 | private static class MySwingWorker extends SwingWorker { 52 | private final JProgressBar fProgressBar; 53 | private MySwingWorker( JProgressBar aProgressBar ) { 54 | fProgressBar = aProgressBar; 55 | } 56 | 57 | @Override 58 | protected String doInBackground() throws Exception { 59 | int maxNumber = 10; 60 | for( int i = 0; i < maxNumber; i++ ){ 61 | Thread.sleep( 2000 );//simulate long running process 62 | double factor = ((double)(i+1) / maxNumber); 63 | System.out.println("Intermediate results ready"); 64 | publish( factor );//publish the progress 65 | } 66 | return "Finished"; 67 | } 68 | 69 | @Override 70 | protected void process( List aDoubles ) { 71 | //update the percentage of the progress bar that is done 72 | int amount = fProgressBar.getMaximum() - fProgressBar.getMinimum(); 73 | fProgressBar.setValue( ( int ) (fProgressBar.getMinimum() 74 | + ( amount * aDoubles.get( aDoubles.size() - 1 ))) ); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/src/com/gsa/signingtool/images/close.png -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/images/exelogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/src/com/gsa/signingtool/images/exelogo.png -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/src/com/gsa/signingtool/images/icon.png -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/src/com/gsa/signingtool/images/info.png -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/src/com/gsa/signingtool/images/logo.png -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/images/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/src/com/gsa/signingtool/images/open.png -------------------------------------------------------------------------------- /microsoft/src/com/gsa/signingtool/images/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GSA/gsa-doc-digital-signature/147dbc79ca0ca19ae4aa1b84a20488e206adcc61/microsoft/src/com/gsa/signingtool/images/text.png --------------------------------------------------------------------------------