summaryrefslogtreecommitdiffstats
path: root/base/kra
diff options
context:
space:
mode:
Diffstat (limited to 'base/kra')
-rw-r--r--base/kra/CMakeLists.txt66
-rw-r--r--base/kra/LICENSE291
-rw-r--r--base/kra/functional/drmclient.py1014
-rw-r--r--base/kra/functional/drmclient.readme.txt50
-rw-r--r--base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java266
-rw-r--r--base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java503
-rw-r--r--base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java222
-rw-r--r--base/kra/setup/CMakeLists.txt8
-rw-r--r--base/kra/setup/registry_instance63
-rw-r--r--base/kra/shared/conf/CMakeLists.txt12
-rw-r--r--base/kra/shared/conf/CS.cfg.in383
-rw-r--r--base/kra/shared/conf/acl.ldif42
-rw-r--r--base/kra/shared/conf/catalina.policy184
-rw-r--r--base/kra/shared/conf/catalina.properties87
-rw-r--r--base/kra/shared/conf/context.xml40
-rw-r--r--base/kra/shared/conf/database.ldif4
-rw-r--r--base/kra/shared/conf/db.ldif107
-rw-r--r--base/kra/shared/conf/index.ldif198
-rw-r--r--base/kra/shared/conf/jk2.manifest2
-rw-r--r--base/kra/shared/conf/jk2.properties26
-rw-r--r--base/kra/shared/conf/jkconf.ant.xml51
-rw-r--r--base/kra/shared/conf/jkconfig.manifest2
-rw-r--r--base/kra/shared/conf/logging.properties70
-rw-r--r--base/kra/shared/conf/manager.ldif48
-rw-r--r--base/kra/shared/conf/schema.ldif489
-rw-r--r--base/kra/shared/conf/server-minimal.xml25
-rw-r--r--base/kra/shared/conf/server.xml308
-rw-r--r--base/kra/shared/conf/serverCert.profile37
-rw-r--r--base/kra/shared/conf/serverCertNick.conf1
-rw-r--r--base/kra/shared/conf/shm.manifest2
-rw-r--r--base/kra/shared/conf/storageCert.profile37
-rw-r--r--base/kra/shared/conf/subsystemCert.profile37
-rw-r--r--base/kra/shared/conf/tomcat-jk2.manifest7
-rw-r--r--base/kra/shared/conf/tomcat-users.xml45
-rw-r--r--base/kra/shared/conf/tomcat6.conf58
-rw-r--r--base/kra/shared/conf/transportCert.profile37
-rw-r--r--base/kra/shared/conf/uriworkermap.properties13
-rw-r--r--base/kra/shared/conf/vlv.ldif207
-rw-r--r--base/kra/shared/conf/vlvtasks.ldif19
-rw-r--r--base/kra/shared/conf/web.xml989
-rw-r--r--base/kra/shared/conf/workers.properties206
-rw-r--r--base/kra/shared/conf/workers.properties.minimal17
-rw-r--r--base/kra/shared/conf/workers2.properties132
-rw-r--r--base/kra/shared/conf/workers2.properties.minimal55
-rwxr-xr-xbase/kra/shared/etc/init.d/pki-krad87
-rw-r--r--base/kra/shared/lib/systemd/system/pki-krad.target8
-rw-r--r--base/kra/shared/lib/systemd/system/pki-krad@.service13
-rw-r--r--base/kra/shared/webapps/ROOT/WEB-INF/web.xml29
-rw-r--r--base/kra/shared/webapps/ROOT/index.jsp98
-rw-r--r--base/kra/shared/webapps/kra/WEB-INF/auth.properties16
-rw-r--r--base/kra/shared/webapps/kra/WEB-INF/velocity.properties8
-rw-r--r--base/kra/shared/webapps/kra/WEB-INF/web.xml1115
-rw-r--r--base/kra/src/CMakeLists.txt109
-rw-r--r--base/kra/src/com/netscape/kra/ArchiveOptions.java154
-rw-r--r--base/kra/src/com/netscape/kra/EncryptionUnit.java741
-rw-r--r--base/kra/src/com/netscape/kra/EnrollmentService.java872
-rw-r--r--base/kra/src/com/netscape/kra/KRANotify.java50
-rw-r--r--base/kra/src/com/netscape/kra/KRAPolicy.java78
-rw-r--r--base/kra/src/com/netscape/kra/KRAService.java101
-rw-r--r--base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java1785
-rw-r--r--base/kra/src/com/netscape/kra/NetkeyKeygenService.java608
-rw-r--r--base/kra/src/com/netscape/kra/RecoveryService.java710
-rw-r--r--base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java388
-rw-r--r--base/kra/src/com/netscape/kra/SecurityDataService.java171
-rw-r--r--base/kra/src/com/netscape/kra/StorageKeyUnit.java978
-rw-r--r--base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java627
-rw-r--r--base/kra/src/com/netscape/kra/TransportKeyUnit.java195
67 files changed, 15401 insertions, 0 deletions
diff --git a/base/kra/CMakeLists.txt b/base/kra/CMakeLists.txt
new file mode 100644
index 000000000..0e15b2d52
--- /dev/null
+++ b/base/kra/CMakeLists.txt
@@ -0,0 +1,66 @@
+project(kra Java)
+
+add_subdirectory(src)
+add_subdirectory(setup)
+add_subdirectory(shared/conf)
+
+# install systemd scripts
+install(
+ FILES
+ shared/lib/systemd/system/pki-krad.target
+ shared/lib/systemd/system/pki-krad@.service
+ DESTINATION
+ ${SYSTEMD_LIB_INSTALL_DIR}
+ PERMISSIONS
+ OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ GROUP_EXECUTE GROUP_READ
+ WORLD_EXECUTE WORLD_READ
+)
+
+# install init script
+install(
+ FILES
+ shared/etc/init.d/pki-krad
+ DESTINATION
+ ${SYSCONF_INSTALL_DIR}/rc.d/init.d
+ PERMISSIONS
+ OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ GROUP_EXECUTE GROUP_READ
+ WORLD_EXECUTE WORLD_READ
+)
+
+# install directories
+install(
+ DIRECTORY
+ shared/
+ DESTINATION
+ ${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}/${PROJECT_NAME}
+ PATTERN
+ "CMakeLists.txt" EXCLUDE
+ PATTERN
+ "etc/*" EXCLUDE
+ PATTERN
+ "conf/CS.cfg.in" EXCLUDE
+ PATTERN
+ "lib/*" EXCLUDE
+)
+
+# install empty directories
+install(
+ DIRECTORY
+ DESTINATION
+ ${VAR_INSTALL_DIR}/lock/pki/kra
+)
+
+install(
+ DIRECTORY
+ DESTINATION
+ ${VAR_INSTALL_DIR}/run/pki/kra
+)
+
+install(
+ DIRECTORY
+ DESTINATION
+ ${SYSTEMD_ETC_INSTALL_DIR}/pki-krad.target.wants
+)
+
diff --git a/base/kra/LICENSE b/base/kra/LICENSE
new file mode 100644
index 000000000..e281f4362
--- /dev/null
+++ b/base/kra/LICENSE
@@ -0,0 +1,291 @@
+This Program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published
+by the Free Software Foundation; version 2 of the License.
+
+This Program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with this Program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
diff --git a/base/kra/functional/drmclient.py b/base/kra/functional/drmclient.py
new file mode 100644
index 000000000..e9b0ccb49
--- /dev/null
+++ b/base/kra/functional/drmclient.py
@@ -0,0 +1,1014 @@
+# Authors:
+# Ade Lee <alee@redhat.com>
+#
+# Copyright (C) 2012 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+'''
+
+============================================================
+Python Test client for KRA using the new RESTful interface
+============================================================
+
+This is a python client that can be used to retrieve key requests
+and keys from a KRA using the new RESTful interface. Moreover, given
+a PKIArchiveOptions structure containing either a passphrase or a symmetric
+key, this data can be stored in and retrieved from the KRA.
+
+A sample test execution is provided at the end of the file.
+'''
+
+from lxml import etree
+import nss.nss as nss
+import httplib
+from ipapython import nsslib, ipautil
+from nss.error import NSPRError
+from ipalib.errors import NetworkError, CertificateOperationError
+from urllib import urlencode, quote_plus
+from datetime import datetime
+import logging
+import base64
+
+CERT_HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----"
+CERT_FOOTER = "-----END NEW CERTIFICATE REQUEST-----"
+
+def _(string):
+ return string
+
+def parse_key_request_info_xml(doc):
+ '''
+ :param doc: The root node of the xml document to parse
+ :returns: result dict
+ :except ValueError:
+
+ After parsing the results are returned in a result dict. The following
+ table illustrates the mapping from the CMS data item to what may be found in
+ the result dict. If a CMS data item is absent it will also be absent in the
+ result dict.
+
+ +----------------------+----------------+-----------------------+---------------+
+ |cms name |cms type |result name |result type |
+ +======================+================+=======================+===============+
+ |requestType |string |request_type |string |
+ +----------------------+----------------+-----------------------+---------------+
+ |requestStatus |string |request_status |string |
+ +----------------------+----------------+-----------------------+---------------+
+ |requestURL |string |request_id |string |
+ +----------------------+----------------+-----------------------+---------------+
+ |keyURL |string |key_id |string |
+ +----------------------+----------------+-----------------------+---------------+
+ '''
+ response = {}
+
+ request_type = doc.xpath('requestType')
+ if len(request_type) == 1:
+ request_type = etree.tostring(request_type[0], method='text',
+ encoding=unicode).strip()
+ response['request_type'] = request_type
+
+ request_status = doc.xpath('requestStatus')
+ if len(request_status) == 1:
+ request_status = etree.tostring(request_status[0], method='text',
+ encoding=unicode).strip()
+ response['request_status'] = request_status
+
+ request_url = doc.xpath('requestURL')
+ if len(request_url) == 1:
+ request_url = etree.tostring(request_url[0], method='text',
+ encoding=unicode).strip()
+ response['request_id'] = request_url.rsplit('/',1)[1]
+
+ key_url = doc.xpath('keyURL')
+ if len(key_url) == 1:
+ key_url = etree.tostring(key_url[0], method='text',
+ encoding=unicode).strip()
+ response['key_id'] = key_url.rsplit('/',1)[1]
+
+ return response
+
+def parse_key_request_infos_xml(doc):
+ '''
+ :param doc: The root node of the xml document to parse
+ :returns: result dict
+ :except ValueError:
+
+ After parsing the results are returned in a result dict. The following
+ table illustrates the mapping from the CMS data item to what may be found in
+ the result dict. If a CMS data item is absent it will also be absent in the
+ result dict.
+
+ +----------------------+------------------------+-----------------------+---------------+
+ |cms name |cms type |result name |result type |
+ +======================+========================+=======================+===============+
+ |next |Link |next_id |unicode [1] |
+ +----------------------+------------------------+-----------------------+---------------+
+ |prev |Link |prev_id |unicode [1] |
+ +----------------------+------------------------+-----------------------+---------------+
+ |info for each request |SecurityDataRequestInfo |request_id [2] |dict |
+ +----------------------+------------------------+-----------------------+---------------+
+
+ [1] prev_id and next_id are the starting ids for the previous and next pages
+ respectively. They are extracted from the href elements of the Link
+ nodes (if they exist)
+ [2] For each key request info returned, we store a dict containing the key request data.
+ See parse_key_request_info_xml for details. Each dict is referenced by the id
+ of the key request (extracted from the key request URL).
+ '''
+ response = {}
+ next_link = doc.xpath('//Link[@rel="next"]/href')
+ if len(next_link) == 1:
+ next_link = etree.tostring(next_link[0], method='text',
+ encoding=unicode).strip()
+ next_link = next_link.rsplit('/',1)[1]
+ response['next_id'] = next_link
+
+ prev_link = doc.xpath('//Link[@rel="previous"]/href')
+ if len(prev_link) == 1:
+ prev_link = etree.tostring(prev_link[0], method='text',
+ encoding=unicode).strip()
+ prev_link = prev_link.rsplit('/', 1)[1]
+ response['prev_id'] = prev_link
+
+ key_request_infos = doc.xpath('//SecurityDataRequestInfo')
+ for key_request in key_request_infos:
+ node = parse_key_request_info_xml(key_request)
+ response[node['request_id']] = node
+
+ return response
+
+def parse_key_data_info_xml(doc):
+ '''
+ :param doc: The root node of the xml document to parse
+ :returns: result dict
+ :except ValueError:
+
+ After parsing the results are returned in a result dict. The following
+ table illustrates the mapping from the CMS data item to what may be found in
+ the result dict. If a CMS data item is absent it will also be absent in the
+ result dict.
+
+ +----------------------+----------------+-----------------------+---------------+
+ |cms name |cms type |result name |result type |
+ +======================+================+=======================+===============+
+ |clientID |string |client_id |string |
+ +----------------------+----------------+-----------------------+---------------+
+ |keyURL |string |key_url |string |
+ +----------------------+----------------+-----------------------+---------------+
+ '''
+ response = {}
+
+ client_id = doc.xpath('clientID')
+ if len(client_id) == 1:
+ client_id = etree.tostring(client_id[0], method='text',
+ encoding=unicode).strip()
+ response['client_id'] = client_id
+
+ key_url = doc.xpath('keyURL')
+ if len(key_url) == 1:
+ key_url = etree.tostring(key_url[0], method='text',
+ encoding=unicode).strip()
+ response['key_url'] = key_url
+
+ return response
+
+def parse_key_data_infos_xml(doc):
+ '''
+ :param doc: The root node of the xml document to parse
+ :returns: result dict
+ :except ValueError:
+
+ After parsing the results are returned in a result dict. The following
+ table illustrates the mapping from the CMS data item to what may be found in
+ the result dict. If a CMS data item is absent it will also be absent in the
+ result dict.
+
+ +----------------------+-----------------+-----------------------+---------------+
+ |cms name |cms type |result name |result type |
+ +======================+=================+=======================+===============+
+ |next |Link |next_id |unicode [1] |
+ +----------------------+-----------------+-----------------------+---------------+
+ |prev |Link |prev_id |unicode [1] |
+ +----------------------+-----------------+-----------------------+---------------+
+ |info for each key |SecurityDataInfo |key_id [2] |dict |
+ +----------------------+-----------------+-----------------------+---------------+
+
+ [1] prev_id and next_id are the starting ids for the previous and next pages
+ respectively. They are extracted from the href elements of the Link
+ nodes (if they exist)
+ [2] For each key info returned, we store a dict containing the key data.
+ See parse_key_data_info_xml for details. Each dict is referenced by the id
+ of the key (extracted from the key URL).
+ '''
+ response = {}
+
+ next_link = doc.xpath('//Link[@rel="next"]/href')
+ if len(next_link) == 1:
+ next_link = etree.tostring(next_link[0], method='text',
+ encoding=unicode).strip()
+ next_link = next_link.rsplit('/',1)[1]
+ response['next_id'] = next_link
+
+ prev_link = doc.xpath('//Link[@rel="previous"]/href')
+ if len(prev_link) == 1:
+ prev_link = etree.tostring(prev_link[0], method='text',
+ encoding=unicode).strip()
+ prev_link = prev_link.rsplit('/', 1)[1]
+ response['prev_id'] = prev_link
+
+ key_data_infos = doc.xpath('//SecurityDataInfo')
+ for key_data in key_data_infos:
+ node = parse_key_data_info_xml(key_data)
+ response[node['key_url'].rsplit('/',1)[1]] = node
+
+ return response
+
+def parse_key_data_xml(doc):
+ '''
+ :param doc: The root node of the xml document to parse
+ :returns: result dict
+ :except ValueError:
+
+ After parsing the results are returned in a result dict.
+
+ +----------------------+----------------+-----------------------+---------------+
+ |cms name |cms type |result name |result type |
+ +======================+================+=======================+===============+
+ |wrappedPrivateData |string |wrapped_data |unicode |
+ +----------------------+----------------+-----------------------+---------------+
+ |nonceData |string |nonce_data |unicode |
+ +----------------------+----------------+-----------------------+---------------+
+
+ '''
+ response = {}
+
+ wrapped_data = doc.xpath('wrappedPrivateData')
+ if len(wrapped_data) == 1:
+ wrapped_data = etree.tostring(wrapped_data[0], method='text',
+ encoding=unicode).strip()
+ response['wrapped_data'] = wrapped_data
+
+ nonce_data = doc.xpath('nonceData')
+ if len(nonce_data) == 1:
+ nonce_data = etree.tostring(nonce_data[0], method='text',
+ encoding=unicode).strip()
+ response['nonce_data'] = nonce_data
+
+ return response
+
+def parse_certificate_data_xml(doc):
+ '''
+ :param doc: The root node of the xml document to parse
+ :returns: result dict
+ :except ValueError:
+
+ After parsing the results are returned in a result dict.
+
+ +----------------------+----------------+-----------------------+---------------+
+ |cms name |cms type |result name |result type |
+ +======================+================+=======================+===============+
+ |b64 |string [1] |cert |unicode |
+ +----------------------+----------------+-----------------------+---------------+
+
+ [1] Base-64 encoded certificate with header and footer
+ '''
+ response = {}
+
+ b64 = doc.xpath('b64')
+ if len(b64) == 1:
+ b64 = etree.tostring(b64[0], method='text',
+ encoding=unicode).strip()
+ response['cert'] = b64.replace(CERT_HEADER, "").replace(CERT_FOOTER, "")
+
+ return response
+
+def https_request(host, port, url, secdir, password, nickname, operation, args, **kw):
+ """
+ :param url: The URL to post to.
+ :param operation: GET, POST, (PUT and DELETE not yet implemented)
+ :param args: arguments for GET command line, or for POST
+ :param kw: Keyword arguments to encode into POST body.
+ :return: (http_status, http_reason_phrase, http_headers, http_body)
+ as (integer, unicode, dict, str)
+
+ Perform a client authenticated HTTPS request
+ """
+ if isinstance(host, unicode):
+ host = host.encode('utf-8')
+ uri = 'https://%s%s' % (ipautil.format_netloc(host, port), url)
+ logging.info('sslget %r', uri)
+
+ request_headers = {"Content-type": "application/xml",
+ "Accept": "application/xml"}
+ if operation == "POST":
+ if args != None:
+ post = args
+ elif kw != None:
+ post = urlencode(kw)
+ request_headers = {"Content-type": "application/x-www-form-urlencoded",
+ "Accept": "text/plain"}
+ try:
+ conn = nsslib.NSSConnection(host, port, dbdir=secdir)
+ conn.set_debuglevel(0)
+ conn.connect()
+ conn.sock.set_client_auth_data_callback(nsslib.client_auth_data_callback,
+ nickname,
+ password, nss.get_default_certdb())
+ if operation == "GET":
+ url = url + "?" + args
+ conn.request("GET", url)
+ elif operation == "POST":
+ conn.request("POST", url, post, request_headers)
+
+ res = conn.getresponse()
+
+ http_status = res.status
+ http_reason_phrase = unicode(res.reason, 'utf-8')
+ http_headers = res.msg.dict
+ http_body = res.read()
+ conn.close()
+ except Exception, e:
+ raise NetworkError(uri=uri, error=str(e))
+
+ return http_status, http_reason_phrase, http_headers, http_body
+
+def http_request(host, port, url, operation, args):
+ """
+ :param url: The URL to post to.
+ :param operation: GET, POST, (PUT and DELETE not yet implemented)
+ :param args: arguments for GET command line, or for POST
+ :return: (http_status, http_reason_phrase, http_headers, http_body)
+ as (integer, unicode, dict, str)
+
+ Perform an HTTP request.
+ """
+ if isinstance(host, unicode):
+ host = host.encode('utf-8')
+ uri = 'http://%s%s' % (ipautil.format_netloc(host, port), url)
+ logging.info('request %r', uri)
+ request_headers = {"Content-type": "application/xml",
+ "Accept": "application/xml"}
+ if operation == "POST":
+ if args != None:
+ post = args
+ else:
+ post = ""
+ conn = httplib.HTTPConnection(host, port)
+ try:
+ if operation == "GET":
+ if args != None:
+ url = url + "?" + args
+ conn.request("GET", url)
+ elif operation == "POST":
+ conn.request("POST", url, post, request_headers)
+
+ res = conn.getresponse()
+
+ http_status = res.status
+ http_reason_phrase = unicode(res.reason, 'utf-8')
+ http_headers = res.msg.dict
+ http_body = res.read()
+ conn.close()
+ except NSPRError, e:
+ raise NetworkError(uri=uri, error=str(e))
+
+ logging.debug('request status %d', http_status)
+ logging.debug('request reason_phrase %r', http_reason_phrase)
+ logging.debug('request headers %s', http_headers)
+ logging.debug('request body %r', http_body)
+
+ return http_status, http_reason_phrase, http_headers, http_body
+
+class kra:
+ """
+ Key Repository Authority backend plugin.
+ """
+
+ POST = "POST"
+ GET = "GET"
+ transport_cert = "byte array with transport cert"
+ mechanism = nss.CKM_DES_CBC_PAD
+ iv = "e4:bb:3b:d3:c3:71:2e:58"
+ fullname = "kra"
+
+
+ def __init__(self, work_dir, kra_host, kra_port, kra_nickname):
+ #crypto
+ self.sec_dir = work_dir
+ self.pwd_file = work_dir + "/pwdfile.txt"
+ self.transport_cert_nickname = kra_nickname
+ self.mechanism = nss.CKM_DES3_CBC_PAD
+ try:
+ f = open(self.pwd_file, "r")
+ self.password = f.readline().strip()
+ f.close()
+ except IOError:
+ self.password = ''
+
+ #set up key db for crypto functions
+ try:
+ nss.nss_init(self.sec_dir)
+ except Exception, e:
+ raise CertificateOperationError(error=_('Error in initializing certdb (%s)') \
+ + e.strerror)
+ self.transport_cert = nss.find_cert_from_nickname(self.transport_cert_nickname)
+
+ # DRM info
+ self.kra_host = kra_host
+ self.kra_agent_port = kra_port
+ '''super(kra, self).__init__()'''
+
+ def setup_contexts(self, mechanism, sym_key, iv):
+ # Get a PK11 slot based on the cipher
+ slot = nss.get_best_slot(mechanism)
+
+ if sym_key == None:
+ sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism))
+
+ # If initialization vector was supplied use it, otherwise set it to None
+ if iv:
+ iv_data = nss.read_hex(iv)
+ iv_si = nss.SecItem(iv_data)
+ iv_param = nss.param_from_iv(mechanism, iv_si)
+ else:
+ iv_length = nss.get_iv_length(mechanism)
+ if iv_length > 0:
+ iv_data = nss.generate_random(iv_length)
+ iv_si = nss.SecItem(iv_data)
+ iv_param = nss.param_from_iv(mechanism, iv_si)
+ else:
+ iv_param = None
+
+ # Create an encoding context
+ encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT,
+ sym_key, iv_param)
+
+ # Create a decoding context
+ decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT,
+ sym_key, iv_param)
+
+ return encoding_ctx, decoding_ctx
+
+ def debug(self, message, *args):
+ print message % args
+
+ def _request(self, url, port, operation, args):
+ """
+ :param url: The URL to post to.
+ :param port: The port to post to
+ :param operation: GET/POST/PUT/DELETE (as supported by sslget)
+ :param args: A string containing arguments for a GET or POST request
+ :return: (http_status, http_reason_phrase, http_headers, http_body)
+ as (integer, unicode, dict, str)
+
+ Perform an HTTP request.
+ """
+ return http_request(self.kra_host, port, url, operation, args)
+
+ def _sslget(self, url, port, operation, args, **kw):
+ """
+ :param url: The URL to post to.
+ :param port: The port to post to
+ :param operation: GET/POST/PUT/DELETE (as supported by sslget)
+ :param args: A string containing arguments for a GET or POST request
+ :param kw: Alternatively, keyword arguments to be form-encoded into POST body.
+ :return: (http_status, http_reason_phrase, http_headers, http_body)
+ as (integer, unicode, dict, str)
+
+ Perform an HTTPS request
+ """
+ return https_request(self.kra_host, port, url, self.sec_dir, self.password,
+ self.ipa_certificate_nickname, operation, args, **kw)
+
+ def symmetric_wrap(self, data, wrapping_key):
+ """
+ :param data: Data to be wrapped
+ :param wrapping_key Symmetric key to wrap data
+
+ Wrap (encrypt) data using the supplied symmetric key
+ """
+ encoding_ctx, decoding_ctx = self.setup_contexts(self.mechanism, wrapping_key, self.iv)
+ wrapped_data = encoding_ctx.cipher_op(data) + encoding_ctx.digest_final()
+ return wrapped_data
+
+ def asymmetric_wrap(self, data, wrapping_cert):
+ """
+ :param data: Data to be wrapped
+ :param wrapping_cert Public key to wrap data
+
+ Wrap (encrypt) data using the supplied asymmetric key
+ """
+
+ return None
+
+ def symmetric_unwrap(self, data, wrapping_key, iv = None):
+ """
+ :param data: Data to be unwrapped
+ :param wrapping_key Symmetric key to unwrap data
+
+ Unwrap (decrypt) data using the supplied symmetric key
+ """
+ if iv == None:
+ iv = self.iv
+ encoding_ctx, decoding_ctx = self.setup_contexts(self.mechanism, wrapping_key, iv)
+ unwrapped_data = decoding_ctx.cipher_op(data) + decoding_ctx.digest_final()
+ return unwrapped_data
+
+ def get_parse_result_xml(self, xml_text, parse_func):
+ '''
+ :param xml_text: The XML text to parse
+ :param parse_func: The XML parsing function to apply to the parsed DOM tree.
+ :return: parsed result dict
+
+ Utility routine which parses the input text into an XML DOM tree
+ and then invokes the parsing function on the DOM tree in order
+ to get the parsing result as a dict of key/value pairs.
+ '''
+ parser = etree.XMLParser()
+ doc = etree.fromstring(xml_text, parser)
+ result = parse_func(doc)
+ self.debug("%s() xml_text:\n%s\nparse_result:\n%s" % (parse_func.__name__, xml_text, result))
+ return result
+
+ def create_archival_request(self, client_id, security_data, data_type):
+ """
+ :param :param client_id: identifier to be used for this stored key
+ :param security_data: data blob (PKIArchiveOptions) containing passphrase
+ or symmetric key to be archived
+ :param data_type: data type (symmetricKey, pass_phrase, asymmetricKey)
+ :return doc: xml doc with archival request
+ """
+ self.debug('%s.create_archival_request()', self.fullname)
+ root = etree.Element("SecurityDataArchivalRequest")
+ client_id_element = etree.SubElement(root, "clientId")
+ client_id_element.text = client_id
+ wrapped_private_data_element = etree.SubElement(root, "wrappedPrivateData")
+ wrapped_private_data_element.text = security_data
+ data_type_element = etree.SubElement(root, "dataType")
+ data_type_element.text = data_type
+ return etree.ElementTree(root)
+
+ def create_recovery_request(self, key_id, request_id, session_key, passphrase, nonce = None):
+ """
+ :param key_id: identifier of key to be recovered
+ :param request_id: id for the recovery request
+ :param session_key session key wrapped in transport key
+ :param passphrase passphrase wrapped in session key
+ :return doc: xml doc with archival request
+
+ """
+ self.debug('%s.create_recovery_request()', self.fullname)
+ root = etree.Element("SecurityDataRecoveryRequest")
+ if key_id != None:
+ key_id_element = etree.SubElement(root, "keyId")
+ key_id_element.text = key_id
+ if request_id != None:
+ request_id_element = etree.SubElement(root, "requestId")
+ request_id_element.text = request_id
+ if session_key != None:
+ session_key_element = etree.SubElement(root, "transWrappedSessionKey")
+ session_key_element.text = session_key
+ if passphrase != None:
+ passphrase_element = etree.SubElement(root, "sessionWrappedPassphrase")
+ passphrase_element.text = passphrase
+ if nonce != None:
+ nonce_element = etree.SubElement(root, "nonceData")
+ nonce_element.text = nonce
+ return etree.ElementTree(root)
+
+ def archive_security_data(self, client_id, security_data, data_type):
+ """
+ :param client_id: identifier to be used for this stored key
+ :param security_data: data blob (PKIArchiveOptions) containing passphrase
+ or symmetric key to be archived
+ :param data_type: data type (symmetricKey, pass_phrase, asymmetricKey)
+
+ Archives security data packaged in a PKIArchiveOptions blob
+
+ The command returns a dict with key/value pairs as defined in
+ parse_key_request_info_xml(). These include the request_id of the created
+ archival request, the status of the request, and the key_id of the archived
+ key.
+ """
+ self.debug('%s.archive_security_data()', self.fullname)
+
+ # check clientID and security data
+ if ((client_id == None) or (security_data == None)):
+ raise CertificateOperationError(error=_('Bad arguments to archive_security_data'))
+
+ request = self.create_archival_request(client_id, security_data, data_type)
+
+ #Call CMS
+ http_status, http_reason_phrase, http_headers, http_body = \
+ self._request('/kra/pki/keyrequest/archive',
+ self.kra_agent_port,
+ self.POST,
+ etree.tostring(request.getroot(), encoding='UTF-8'))
+
+ # Parse and handle errors
+ if (http_status != 200):
+ raise CertificateOperationError(error=_('Error in archiving request (%s)') % \
+ http_reason_phrase)
+
+ parse_result = self.get_parse_result_xml(http_body, parse_key_request_info_xml)
+ return parse_result
+
+ def get_transport_cert(self, etag=None):
+ """
+ :param etag: etag info for last cert retrieval from DRM
+
+ Gets the transport certificate from the DRM
+
+ The command returns a dict as defined in parse_certificate_data_xml()
+ """
+ self.debug('%s.get_transport_cert()', self.fullname)
+
+ #Call CMS
+ http_status, http_reason_phrase, http_headers, http_body = \
+ self._request('/kra/pki/config/cert/transport',
+ self.kra_agent_port,
+ self.GET,
+ None)
+
+ self.debug("headers: %s" , http_headers)
+ # Parse and handle errors
+ if (http_status != 200):
+ raise CertificateOperationError(error=_('Error in archiving request (%s)') % \
+ http_reason_phrase)
+
+ parse_result = self.get_parse_result_xml(http_body, parse_certificate_data_xml)
+ return parse_result
+
+ def list_security_data(self, client_id, key_state = None, next_id = None):
+ """
+ :param client_id: identifier to be searched for
+ :param key_state: state for key (active, inactive, all)
+ :param next_id: id for starting key on next page (if more than one page)
+
+ List security data matching the specified client id and state
+
+ The command returns a dict as specified in parse_key_data_infos_xml().
+ """
+ self.debug('%s.list_security_data()', self.fullname)
+ if client_id == None:
+ raise CertificateOperationError(error=_('Bad argument to list_security_data'))
+ get_args = "clientID=" + quote_plus(client_id)
+
+ if key_state != None:
+ get_args = get_args + "&status=" + quote_plus(key_state)
+
+ if next_id != None:
+ # currnently not implemented on server
+ get_args = get_args + "&start=" + quote_plus(next_id)
+
+ #Call CMS
+ http_status, http_reason_phrase, http_headers, http_body = \
+ self._request('/kra/pki/keys',
+ self.kra_agent_port,
+ self.GET,
+ get_args)
+
+ # Parse and handle errors
+ if (http_status != 200):
+ raise CertificateOperationError(error=_('Error in listing keys (%s)') % \
+ http_reason_phrase)
+
+ parse_result = self.get_parse_result_xml(http_body, parse_key_data_infos_xml)
+ return parse_result
+
+ def list_key_requests(self, request_state = None, request_type = None, client_id = None,
+ next_id = None):
+ """
+ :param request_state: state of request (pending, complete, cancelled, rejected, approved)
+ :param request_type: request type (enrollment, recovery)
+ :param next_id: id for starting key on next page (if more than one page)
+
+ List security data matching the specified client id and state
+
+ The command returns a dict as specified in parse_key_request_infos_xml().
+ """
+ self.debug('%s.list_key_requests()', self.fullname)
+ get_args = ""
+
+ if request_state != None:
+ get_args = get_args + "&requestState=" + quote_plus(request_state)
+
+ if request_type != None:
+ get_args = get_args + "&requestType=" + quote_plus(request_type)
+
+ if client_id != None:
+ get_args = get_args + "&clientID=" + quote_plus(client_id)
+
+ if next_id != None:
+ # currnently not implemented on server
+ get_args = get_args + "&start=" + quote_plus(next_id)
+
+ #Call CMS
+ http_status, http_reason_phrase, http_headers, http_body = \
+ self._request('/kra/pki/keyrequests',
+ self.kra_agent_port,
+ self.GET,
+ get_args)
+
+ # Parse and handle errors
+ if (http_status != 200):
+ raise CertificateOperationError(error=_('Error in listing key requests (%s)') % \
+ http_reason_phrase)
+
+ parse_result = self.get_parse_result_xml(http_body, parse_key_request_infos_xml)
+ return parse_result
+
+ def submit_recovery_request(self, key_id):
+ """
+ :param key_id: identifier of data to be recovered
+
+ Create a recovery request for a passphrase or symmetric key
+
+ The command returns a dict as described in the comments to
+ parse_key_request_info_xml(). This data includes the request_id
+ of the created recovery request
+ """
+ self.debug('%s.submit_recovery_request()', self.fullname)
+
+ # check clientID and security data
+ if key_id == None:
+ raise CertificateOperationError(error=_('Bad argument to archive_security_data'))
+
+ request = self.create_recovery_request(key_id, None, None, None)
+
+ #Call CMS
+ http_status, http_reason_phrase, http_headers, http_body = \
+ self._request('/kra/pki/keyrequest/recover',
+ self.kra_agent_port,
+ self.POST,
+ etree.tostring(request.getroot(), encoding='UTF-8'))
+
+ # Parse and handle errors
+ if (http_status != 200):
+ raise CertificateOperationError(error=_('Error in archiving request (%s)') % \
+ http_reason_phrase)
+
+ parse_result = self.get_parse_result_xml(http_body, parse_key_request_info_xml)
+ return parse_result
+
+ def check_request_status(self, request_id):
+ """
+ :param recovery_request_id: identifier of key recovery request
+
+ Check recovery request status
+
+ The command returns a dict with these possible key/value pairs.
+ Some key/value pairs may be absent
+
+ +-----------------+---------------+-------------------------------------- +
+ |result name |result type |comments |
+ +=================+===============+=======================================+
+ |request_status |String | status of request (pending, rejected, |
+ | | | approved) |
+ +-----------------+---------------+---------------------------------------|
+ |approvers_needed |int | If pending, number of approvers |
+ | | | needed |
+ +-----------------+---------------+---------------------------------------+
+ |approvers_list |String | list of approvers |
+ +-----------------+---------------+---------------------------------------+
+ """
+ self.debug('%s.check_request_status()', self.fullname)
+
+ def approve_recovery_request(self, request_id):
+ """
+ :param request_id: identifier of key recovery request
+
+ Approve recovery request
+ """
+ self.debug('%s.approve_recovery_request()', self.fullname)
+ if request_id == None:
+ raise CertificateOperationError(error=_('Bad argument to approve_recovery_request'))
+
+ #Call CMS
+ http_status, http_reason_phrase, http_headers, http_body = \
+ self._request('/kra/pki/keyrequest/approve/'+ request_id,
+ self.kra_agent_port,
+ self.POST,
+ None)
+
+ # Parse and handle errors
+ if (http_status > 399):
+ raise CertificateOperationError(error=_('Error in approving request (%s)') % \
+ http_reason_phrase)
+
+ def reject_recovery_request(self, request_id):
+ """
+ :param recovery_request_id: identifier of key recovery request
+
+ Reject recovery request
+ """
+ self.debug('%s.reject_recovery_request()', self.fullname)
+ if request_id == None:
+ raise CertificateOperationError(error=_('Bad argument to reject_recovery_request'))
+
+ #Call CMS
+ http_status, http_reason_phrase, http_headers, http_body = \
+ self._request('/kra/pki/keyrequest/reject/'+ request_id,
+ self.kra_agent_port,
+ self.POST,
+ None)
+
+ # Parse and handle errors
+ if (http_status > 399):
+ raise CertificateOperationError(error=_('Error in rejecting request (%s)') % \
+ http_reason_phrase)
+
+ def cancel_recovery_request(self, request_id):
+ """
+ :param recovery_request_id: identifier of key recovery request
+
+ Cancel recovery request
+ """
+ self.debug('%s.cancel_recovery_request()', self.fullname)
+ if request_id == None:
+ raise CertificateOperationError(error=_('Bad argument to cancel_recovery_request'))
+
+ #Call CMS
+ http_status, http_reason_phrase, http_headers, http_body = \
+ self._request('/kra/pki/keyrequest/cancel/'+ request_id,
+ self.kra_agent_port,
+ self.POST,
+ None)
+
+ # Parse and handle errors
+ if (http_status > 399):
+ raise CertificateOperationError(error=_('Error in cancelling request (%s)') % \
+ http_reason_phrase)
+
+ def retrieve_security_data(self, recovery_request_id, passphrase=None):
+ """
+ :param recovery_request_id: identifier of key recovery request
+ :param passphrase: passphrase to be used to wrap the data
+
+ Recover the passphrase or symmetric key. We require an approved
+ recovery request.
+
+ If a passphrase is provided, the DRM will return a blob that can be decrypted
+ with the passphrase. If not, then a symmetric key will be created to wrap the
+ data for transport to this server. Upon receipt, the data will be unwrapped
+ and returned unencrypted.
+
+ The command returns a dict with the values described in parse_key_data_xml(),
+ as well as the following field
+
+ +-----------------+---------------+-------------------------------------- +
+ |result name |result type |comments |
+ +=================+===============+=======================================+
+ |data |String | Key data (either wrapped using |
+ | | | passphrase or unwrapped) |
+ +-----------------+---------------+---------------------------------------+
+ """
+ self.debug('%s.retrieve_security_data()', self.fullname)
+
+ if recovery_request_id == None:
+ raise CertificateOperationError(error=_('Bad arguments to retrieve_security_data'))
+
+ # generate symmetric key
+ slot = nss.get_best_slot(self.mechanism)
+ session_key = slot.key_gen(self.mechanism, None, slot.get_best_key_length(self.mechanism))
+
+ # wrap this key with the transport cert
+ public_key = self.transport_cert.subject_public_key_info.public_key
+ wrapped_session_key = base64.b64encode(nss.pub_wrap_sym_key(self.mechanism, public_key, session_key))
+ wrapped_passphrase = None
+ if passphrase != None:
+ # wrap passphrase with session key
+ wrapped_session_key = base64.b64encode(self.symmetric_wrap(passphrase, session_key))
+
+ request = self.create_recovery_request(None, recovery_request_id,
+ wrapped_session_key,
+ wrapped_passphrase)
+
+ #Call CMS
+ http_status, http_reason_phrase, http_headers, http_body = \
+ self._request('/kra/pki/key/retrieve',
+ self.kra_agent_port,
+ self.POST,
+ etree.tostring(request.getroot(), encoding='UTF-8'))
+
+ # Parse and handle errors
+ if (http_status != 200):
+ raise CertificateOperationError(error=_('Error in retrieving security data (%s)') % \
+ http_reason_phrase)
+
+ parse_result = self.get_parse_result_xml(http_body, parse_key_data_xml)
+
+ if passphrase == None:
+ iv = nss.data_to_hex(base64.decodestring(parse_result['nonce_data']))
+ parse_result['data'] = self.symmetric_unwrap(base64.decodestring(parse_result['wrapped_data']),
+ session_key, iv)
+
+ return parse_result
+
+ def recover_security_data(self, key_id, passphrase=None):
+ """
+ :param key_id: identifier of key to be recovered
+ :param passphrase: passphrase to wrap key data for delivery outside of this server
+
+ Recover the key data (symmetric key or passphrase) in a one step process.
+ This is the case when only one approver is required to extract a key such that
+ the agent submitting the recovery request is the only approver required.
+
+ In this case, the request is automatically approved, and the KRA just returns the
+ key data.
+
+ This has not yet been implemented on the server
+ """
+ self.debug('%s.recover_security_data()', self.fullname)
+ pass
+
+""" Sample Test execution starts here """
+import argparse
+
+parser = argparse.ArgumentParser(description="Sample Test execution")
+parser.add_argument('-d', default='/tmp/drmtest', dest='work_dir', help='Working directory')
+parser.add_argument('--options', default='options.out', dest='options_file',
+ help='File containing test PKIArchiveOptions to be archived')
+parser.add_argument('--symkey', default='symkey.out', dest='symkey_file',
+ help='File containing test symkey')
+parser.add_argument('--host', default='localhost', dest='kra_host', help='DRM hostname')
+parser.add_argument('-p', default='10080', type=int, dest='kra_port', help='DRM Port')
+parser.add_argument('-n', default='DRM TransportCert Nickname', dest='kra_nickname',
+ help="DRM Nickname")
+
+args = parser.parse_args()
+work_dir = args.work_dir
+kra_host = args.kra_host
+kra_port = args.kra_port
+kra_nickname = args.kra_nickname
+options_file = args.options_file
+symkey_file = args.symkey_file
+
+test_kra = kra(work_dir, kra_host, kra_port, kra_nickname)
+
+# list requests
+requests = test_kra.list_key_requests()
+print requests
+
+# get transport cert
+transport_cert = test_kra.get_transport_cert()
+print transport_cert
+
+#archive symmetric key
+f = open(work_dir + "/" + options_file)
+wrapped_key = f.read()
+client_id = "Python symmetric key " + datetime.now().strftime("%Y-%m-%d %H:%M")
+response = test_kra.archive_security_data(client_id, wrapped_key,"symmetricKey")
+print response
+
+# list keys with client_id
+response = test_kra.list_security_data(client_id, "active")
+print response
+
+#create recovery request
+key_id = response.keys()[0]
+print key_id
+response = test_kra.submit_recovery_request(key_id)
+print response
+
+# approve recovery request
+request_id = response['request_id']
+test_kra.approve_recovery_request(request_id)
+
+# test invalid request
+print "Testing invalid request ID"
+try:
+ response = test_kra.retrieve_security_data("INVALID")
+ print "Failure: No exception thrown"
+except CertificateOperationError, e:
+ if 'Error in retrieving security data (Bad Request)' == e.error:
+ print "Success: " + e.error
+ else:
+ print "Failure: Wrong error message: " + e.error
+
+# retrieve key
+response = test_kra.retrieve_security_data(request_id)
+print response
+print "retrieved data is " + base64.encodestring(response['data'])
+
+#read original symkey from file
+f = open(work_dir + "/" + symkey_file)
+orig_key = f.read()
+print "orig key is " + orig_key
+
+if orig_key.strip() == base64.encodestring(response['data']).strip():
+ print "Success: the keys match"
+else:
+ print "Failure: keys do not match"
diff --git a/base/kra/functional/drmclient.readme.txt b/base/kra/functional/drmclient.readme.txt
new file mode 100644
index 000000000..833c5ce3c
--- /dev/null
+++ b/base/kra/functional/drmclient.readme.txt
@@ -0,0 +1,50 @@
+Running drmclient.py:
+
+The python drmclient currently requires a little setup to be run.
+
+1. Create a working directory - the code uses /tmp/drmtest
+2. In that directory, create an NSS database. In this doc, we will use the
+ password redhat123 as the password for the NSS db.
+
+ certutil -N -d /tmp/drmtest
+
+3. Add a password file /tmp/drmtest/pwdfile.txt. It should contain the password for
+ the NSS database.
+
+4. Put the transport certificate in a file /tmp/drmtest/transport.crt in binary format.
+
+ certutil -L -d /var/lib/pki-kra/alias -n "DRM Transport Certificate" -a > /tmp/drmtest/transport.asc
+ AtoB /tmp/drmtest/transport.asc /tmp/drmtest/transport.crt
+
+5. Import the transport certificate into the certificate databse in /tmp/drmtest.
+ certutil -A -d /tmp/drmtest -n "DRM Transport Certificate" -i /tmp/drmtest/transport.asc
+
+5. Run GeneratePKIArchiveOptions to generate some test data. Specifically we will be
+ using it to generate a symmetric key and its associated PKIArchoveOptions structure
+ to be archived.
+
+ GeneratePKIArchiveOptions -k /tmp/drmtest/symkey.out -w redhat123 -t /tmp/drmtest -o /tmp/drmtest/options.out
+
+6. Run the python code. You will likely need some python modules - python-lxml, python-nss
+ and ipapython.
+
+ The code has the following usage:
+
+usage: drmclient.py [-h] [-d WORK_DIR] [--options OPTIONS_FILE]
+ [--symkey SYMKEY_FILE] [--host KRA_HOST] [-p KRA_PORT]
+ [-n KRA_NICKNAME]
+
+Sample Test execution
+
+optional arguments:
+ -h, --help show this help message and exit
+ -d WORK_DIR Working directory
+ --options OPTIONS_FILE
+ File containing test PKIArchiveOptions to be archived
+ --symkey SYMKEY_FILE File containing test symkey
+ --host KRA_HOST DRM hostname
+ -p KRA_PORT DRM Port
+ -n KRA_NICKNAME DRM Nickname
+
+For example:
+python pki/base/kra/functional/drmclient.py -d /tmp/drmtest -p 10200 -n "DRM Transport Certificate - alee eclipse domain 2"
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
new file mode 100644
index 000000000..651873b20
--- /dev/null
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
@@ -0,0 +1,266 @@
+package com.netscape.cms.servlet.test;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+import org.apache.commons.httpclient.ConnectTimeoutException;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.params.HttpConnectionParams;
+import org.apache.commons.httpclient.protocol.Protocol;
+import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
+import org.jboss.resteasy.client.ClientExecutor;
+import org.jboss.resteasy.client.ClientResponse;
+import org.jboss.resteasy.client.ProxyFactory;
+import com.netscape.certsrv.dbs.keydb.KeyId;
+import com.netscape.certsrv.request.RequestId;
+import org.jboss.resteasy.client.core.executors.ApacheHttpClientExecutor;
+import com.netscape.cms.servlet.admin.SystemCertificateResource;
+import com.netscape.cms.servlet.cert.model.CertificateData;
+import com.netscape.cms.servlet.key.KeyResource;
+import com.netscape.cms.servlet.key.KeysResource;
+import com.netscape.cms.servlet.key.model.KeyData;
+import com.netscape.cms.servlet.key.model.KeyDataInfo;
+import com.netscape.cms.servlet.key.model.KeyDataInfos;
+import com.netscape.cms.servlet.request.KeyRequestResource;
+import com.netscape.cms.servlet.request.KeyRequestsResource;
+import com.netscape.cms.servlet.request.model.ArchivalRequestData;
+import com.netscape.cms.servlet.request.model.KeyRequestInfo;
+import com.netscape.cms.servlet.request.model.KeyRequestInfos;
+import com.netscape.cms.servlet.request.model.RecoveryRequestData;
+import com.netscape.cmsutil.util.Utils;
+
+import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
+import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback;
+import org.mozilla.jss.ssl.SSLSocket;
+
+public class DRMRestClient {
+
+ // Callback to approve or deny returned SSL server certs
+ // Right now, simply approve the cert.
+ // ToDO: Look into taking this JSS http client code and move it into
+ // its own class to be used by possible future clients.
+ private class ServerCertApprovalCB implements SSLCertificateApprovalCallback {
+
+ public boolean approve(org.mozilla.jss.crypto.X509Certificate servercert,
+ SSLCertificateApprovalCallback.ValidityStatus status) {
+
+ //For now lets just accept the server cert. This is a test tool, being
+ // pointed at a well know kra instance.
+
+
+ if (servercert != null) {
+ System.out.println("Peer cert details: " +
+ "\n subject: " + servercert.getSubjectDN().toString() +
+ "\n issuer: " + servercert.getIssuerDN().toString() +
+ "\n serial: " + servercert.getSerialNumber().toString()
+ );
+ }
+
+ SSLCertificateApprovalCallback.ValidityItem item;
+
+ Enumeration<?> errors = status.getReasons();
+ int i = 0;
+ while (errors.hasMoreElements()) {
+ i++;
+ item = (SSLCertificateApprovalCallback.ValidityItem) errors.nextElement();
+ System.out.println("item " + i +
+ " reason=" + item.getReason() +
+ " depth=" + item.getDepth());
+
+ int reason = item.getReason();
+
+ if (reason ==
+ SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER ||
+ reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) {
+
+ //Allow these two since we haven't necessarily installed the CA cert for trust
+ // and we are choosing "localhost" as the host for this client.
+
+ return true;
+
+ }
+ }
+
+ //For other errors return false
+
+ return false;
+ }
+ }
+
+ private class JSSProtocolSocketFactory implements ProtocolSocketFactory {
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+
+ SSLSocket sock = createJSSSocket(host,port, null, 0, null);
+ return (Socket) sock;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException,
+ UnknownHostException {
+
+ SSLSocket sock = createJSSSocket(host,port, clientHost, clientPort, null);
+ return (Socket) sock;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params)
+ throws IOException, UnknownHostException, ConnectTimeoutException {
+
+ SSLSocket sock = createJSSSocket(host, port, localAddress, localPort, null);
+ return (Socket) sock;
+ }
+ }
+
+ private SSLSocket createJSSSocket(String host, int port, InetAddress localAddress,
+ int localPort, SSLClientCertificateSelectionCallback clientCertSelectionCallback)
+ throws IOException, UnknownHostException, ConnectTimeoutException {
+
+ SSLSocket sock = new SSLSocket(InetAddress.getByName(host),
+ port,
+ localAddress,
+ localPort,
+ new ServerCertApprovalCB(),
+ null);
+
+ if(sock != null && clientCertNickname != null) {
+ sock.setClientCertNickname(clientCertNickname);
+ }
+
+ return sock;
+
+ }
+ private KeyResource keyClient;
+ private KeysResource keysClient;
+ private KeyRequestsResource keyRequestsClient;
+ private KeyRequestResource keyRequestClient;
+ private SystemCertificateResource systemCertClient;
+
+ private String clientCertNickname = null;
+
+ public DRMRestClient(String baseUri, String clientCertNick) throws MalformedURLException {
+
+ // For SSL we are assuming the caller has already intialized JSS and has
+ // a valid CryptoManager and CryptoToken
+ // optional clientCertNickname is provided for use if required.
+
+
+ URL url = new URL(baseUri);
+
+ String protocol = url.getProtocol();
+ int port = url.getPort();
+
+ clientCertNickname = null;
+ if(protocol != null && protocol.equals("https")) {
+ if (clientCertNick != null) {
+ clientCertNickname = clientCertNick;
+ }
+
+ Protocol.registerProtocol("https",
+ new Protocol(protocol, new JSSProtocolSocketFactory(), port));
+ }
+
+ HttpClient httpclient = new HttpClient();
+ ClientExecutor executor = new ApacheHttpClientExecutor(httpclient);
+
+ systemCertClient = ProxyFactory.create(SystemCertificateResource.class, baseUri, executor);
+ keyRequestsClient = ProxyFactory.create(KeyRequestsResource.class, baseUri, executor);
+ keyRequestClient = ProxyFactory.create(KeyRequestResource.class, baseUri, executor);
+ keysClient = ProxyFactory.create(KeysResource.class, baseUri, executor);
+ keyClient = ProxyFactory.create(KeyResource.class, baseUri, executor);
+ }
+
+ public String getTransportCert() {
+ @SuppressWarnings("unchecked")
+ ClientResponse<CertificateData> response = (ClientResponse<CertificateData>) systemCertClient.getTransportCert();
+ CertificateData certData = response.getEntity();
+ String transportCert = certData.getB64();
+ return transportCert;
+ }
+
+ public Collection<KeyRequestInfo> listRequests(String requestState, String requestType) {
+ KeyRequestInfos infos = keyRequestsClient.listRequests(
+ requestState, requestType, null, new RequestId(0), 100, 100, 10
+ );
+ Collection<KeyRequestInfo> list = infos.getRequests();
+ return list;
+ }
+
+ public KeyRequestInfo archiveSecurityData(byte[] encoded, String clientId, String dataType) {
+ // create archival request
+ ArchivalRequestData data = new ArchivalRequestData();
+ String req1 = Utils.base64encode(encoded);
+ data.setWrappedPrivateData(req1);
+ data.setClientId(clientId);
+ data.setDataType(dataType);
+
+ KeyRequestInfo info = keyRequestClient.archiveKey(data);
+ return info;
+ }
+
+ public KeyDataInfo getKeyData(String clientId, String status) {
+ KeyDataInfos infos = keysClient.listKeys(clientId, status, 100, 10);
+ Collection<KeyDataInfo> list = infos.getKeyInfos();
+ Iterator<KeyDataInfo> iter = list.iterator();
+
+ while (iter.hasNext()) {
+ KeyDataInfo info = iter.next();
+ if (info != null) {
+ // return the first one
+ return info;
+ }
+ }
+ return null;
+ }
+
+ public KeyRequestInfo requestRecovery(KeyId keyId, byte[] rpwd, byte[] rkey, byte[] nonceData) {
+ // create recovery request
+ RecoveryRequestData data = new RecoveryRequestData();
+ data.setKeyId(keyId);
+ if (rpwd != null) {
+ data.setSessionWrappedPassphrase(Utils.base64encode(rpwd));
+ }
+ if (rkey != null) {
+ data.setTransWrappedSessionKey(Utils.base64encode(rkey));
+ }
+
+ if (nonceData != null) {
+ data.setNonceData(Utils.base64encode(nonceData));
+ }
+
+ KeyRequestInfo info = keyRequestClient.recoverKey(data);
+ return info;
+ }
+
+ public void approveRecovery(RequestId recoveryId) {
+ keyRequestClient.approveRequest(recoveryId);
+ }
+
+ public KeyData retrieveKey(KeyId keyId, RequestId requestId, byte[] rpwd, byte[] rkey, byte[] nonceData) {
+ // create recovery request
+ RecoveryRequestData data = new RecoveryRequestData();
+ data.setKeyId(keyId);
+ data.setRequestId(requestId);
+ if (rkey != null) {
+ data.setTransWrappedSessionKey(Utils.base64encode(rkey));
+ }
+ if (rpwd != null) {
+ data.setSessionWrappedPassphrase(Utils.base64encode(rpwd));
+ }
+
+ if (nonceData != null) {
+ data.setNonceData(Utils.base64encode(nonceData));
+ }
+
+ KeyData key = keyClient.retrieveKey(data);
+ return key;
+ }
+}
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
new file mode 100644
index 000000000..8d83247b8
--- /dev/null
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
@@ -0,0 +1,503 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.test;
+
+import java.net.MalformedURLException;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Random;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.AlreadyInitializedException;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.util.Password;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+
+import com.netscape.certsrv.dbs.keydb.KeyId;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.cms.servlet.base.CMSResourceService;
+import com.netscape.cms.servlet.key.model.KeyData;
+import com.netscape.cms.servlet.key.model.KeyDataInfo;
+import com.netscape.cms.servlet.request.KeyRequestResource;
+import com.netscape.cms.servlet.request.model.KeyRequestInfo;
+import com.netscape.cmsutil.crypto.CryptoUtil;
+import com.netscape.cmsutil.util.Utils;
+
+public class DRMTest {
+
+ public static void usage(Options options) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("DRMTest", options);
+ System.exit(1);
+ }
+
+ public static void main(String args[]) {
+ String host = null;
+ String port = null;
+ String token_pwd = null;
+ String db_dir = "./";
+ String protocol = "http";
+ String clientCertNickname = "KRA Administrator of Instance pki-kra's SjcRedhat Domain ID";
+
+ // parse command line arguments
+ Options options = new Options();
+ options.addOption("h", true, "Hostname of the DRM");
+ options.addOption("p", true, "Port of the DRM");
+ options.addOption("w", true, "Token password");
+ options.addOption("d", true, "Directory for tokendb");
+ options.addOption("s", true, "Attempt Optional Secure SSL connection");
+ options.addOption("c", true, "Optional SSL Client cert Nickname");
+
+ try {
+ CommandLineParser parser = new PosixParser();
+ CommandLine cmd = parser.parse(options, args);
+
+ if (cmd.hasOption("h")) {
+ host = cmd.getOptionValue("h");
+ } else {
+ System.err.println("Error: no hostname provided.");
+ usage(options);
+ }
+
+ if (cmd.hasOption("p")) {
+ port = cmd.getOptionValue("p");
+ } else {
+ System.err.println("Error: no port provided");
+ usage(options);
+ }
+
+ if (cmd.hasOption("w")) {
+ token_pwd = cmd.getOptionValue("w");
+ } else {
+ System.err.println("Error: no token password provided");
+ usage(options);
+ }
+
+ if (cmd.hasOption("d")) {
+ db_dir = cmd.getOptionValue("d");
+ }
+
+ if (cmd.hasOption("s")) {
+ if(cmd.getOptionValue("s") != null && cmd.getOptionValue("s").equals("true")) {
+ protocol = "https";
+ }
+ }
+
+ if (cmd.hasOption("c")) {
+ String nick = cmd.getOptionValue("c");
+
+ if (nick != null && protocol.equals("https")) {
+ clientCertNickname = nick;
+ }
+ }
+
+ } catch (ParseException e) {
+ System.err.println("Error in parsing command line options: " + e.getMessage());
+ usage(options);
+ }
+
+ // used for crypto operations
+ byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ IVParameterSpec ivps = null;
+ IVParameterSpec ivps_server = null;
+
+ try {
+ ivps = genIV(8);
+ } catch (Exception e) {
+ log("Can't generate initialization vector use default: " + e.toString());
+ ivps = new IVParameterSpec(iv);
+ }
+
+ CryptoManager manager = null;
+ CryptoToken token = null;
+
+ // used for wrapping to send data to DRM
+ String transportCert = null;
+
+ // Data to be archived
+ SymmetricKey vek = null;
+ String passphrase = null;
+
+ // Session keys and passphrases for recovery
+ SymmetricKey recoveryKey = null;
+ byte[] wrappedRecoveryKey = null;
+ String recoveryPassphrase = null;
+ byte[] wrappedRecoveryPassphrase = null;
+
+ // retrieved data (should match archived data)
+ String wrappedRecoveredKey = null;
+ String recoveredKey = null;
+
+ // various ids used in recovery/archival operations
+ KeyId keyId = null;
+ String clientId = null;
+ RequestId recoveryRequestId = null;
+
+ // Variables for data structures from calls
+ KeyRequestInfo requestInfo = null;
+ KeyData keyData = null;
+ KeyDataInfo keyInfo = null;
+
+ // Initialize token
+ try {
+ CryptoManager.initialize(db_dir);
+ } catch (AlreadyInitializedException e) {
+ // it is ok if it is already initialized
+ } catch (Exception e) {
+ log("INITIALIZATION ERROR: " + e.toString());
+ System.exit(1);
+ }
+
+ // log into token
+ try {
+ manager = CryptoManager.getInstance();
+ token = manager.getInternalKeyStorageToken();
+ Password password = new Password(token_pwd.toCharArray());
+ try {
+ token.login(password);
+ } catch (Exception e) {
+ log("login Exception: " + e.toString());
+ if (!token.isLoggedIn()) {
+ token.initPassword(password, password);
+ }
+ }
+ } catch (Exception e) {
+ log("Exception in logging into token:" + e.toString());
+ }
+
+ // Set base URI and get client
+
+
+ String baseUri = protocol + "://" + host + ":" + port + "/kra/pki";
+ DRMRestClient client;
+ try {
+ client = new DRMRestClient(baseUri, clientCertNickname);
+ } catch (MalformedURLException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ return;
+ }
+
+ // Test 1: Get transport certificate from DRM
+ transportCert = client.getTransportCert();
+ transportCert = transportCert.substring(CMSResourceService.HEADER.length(),
+ transportCert.indexOf(CMSResourceService.TRAILER));
+
+ log("Transport Cert retrieved from DRM: " + transportCert);
+
+ // Test 2: Get list of completed key archival requests
+ log("\n\nList of completed archival requests");
+ Collection<KeyRequestInfo> list = client.listRequests("complete", "securityDataEnrollment");
+ if (list == null) {
+ log("No requests found");
+ } else {
+ Iterator<KeyRequestInfo> iter = list.iterator();
+ while (iter.hasNext()) {
+ KeyRequestInfo info = iter.next();
+ printRequestInfo(info);
+ }
+ }
+
+ // Test 3: Get list of key recovery requests
+ log("\n\nList of completed recovery requests");
+ Collection<KeyRequestInfo> list2 = client.listRequests("complete", "securityDataRecovery");
+ if (list2 == null) {
+ log("No requests found");
+ } else {
+ Iterator<KeyRequestInfo> iter2 = list2.iterator();
+ while (iter2.hasNext()) {
+ KeyRequestInfo info = iter2.next();
+ printRequestInfo(info);
+ }
+ }
+
+ // Test 4: Generate and archive a symmetric key
+ log("Archiving symmetric key");
+ clientId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime().toString();
+ try {
+ vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
+ KeyGenAlgorithm.DES3, ivps);
+
+ KeyRequestInfo info = client.archiveSecurityData(encoded, clientId, KeyRequestResource.SYMMETRIC_KEY_TYPE);
+ log("Archival Results:");
+ printRequestInfo(info);
+ keyId = info.getKeyId();
+ } catch (Exception e) {
+ log("Exception in archiving symmetric key:" + e.getMessage());
+ e.printStackTrace();
+ }
+
+ //Test 5: Get keyId for active key with client ID
+
+ log("Getting key ID for symmetric key");
+ keyInfo = client.getKeyData(clientId, "active");
+ KeyId keyId2 = keyInfo.getKeyId();
+ if (keyId2 == null) {
+ log("No archived key found");
+ } else {
+ log("Archived Key found: " + keyId);
+ }
+
+ if (!keyId.equals(keyId2)) {
+ log("Error: key ids from search and archival do not match");
+ } else {
+ log("Success: keyids from search and archival match.");
+ }
+
+ // Test 6: Submit a recovery request for the symmetric key using a session key
+ log("Submitting a recovery request for the symmetric key using session key");
+ try {
+ recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+ KeyRequestInfo info = client.requestRecovery(keyId, null, wrappedRecoveryKey, ivps.getIV());
+ recoveryRequestId = info.getRequestId();
+ } catch (Exception e) {
+ log("Exception in recovering symmetric key using session key: " + e.getMessage());
+ }
+
+ // Test 7: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 8: Get key
+ log("Getting key: " + keyId);
+
+ keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+
+ ivps_server = new IVParameterSpec(Utils.base64decode(keyData.getNonceData()));
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
+ Utils.base64decode(wrappedRecoveredKey),
+ recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
+ } catch (Exception e) {
+ log("Exception in unwrapping key: " + e.toString());
+ e.printStackTrace();
+ }
+
+ if (!recoveredKey.equals(Utils.base64encode(vek.getEncoded()))) {
+ log("Error: recovered and archived keys do not match!");
+ } else {
+ log("Success: recoverd and archived keys match!");
+ }
+
+ // Test 9: Submit a recovery request for the symmetric key using a passphrase
+ log("Submitting a recovery request for the symmetric key using a passphrase");
+ recoveryPassphrase = "Gimme me keys please";
+
+ try {
+ recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ wrappedRecoveryPassphrase = CryptoUtil.wrapPassphrase(token, recoveryPassphrase, ivps, recoveryKey,
+ EncryptionAlgorithm.DES3_CBC_PAD);
+ wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+
+ requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ recoveryRequestId = requestInfo.getRequestId();
+ } catch (Exception e) {
+ log("Exception in recovering symmetric key using passphrase" + e.toString());
+ e.printStackTrace();
+ }
+
+ //Test 10: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 11: Get key
+ log("Getting key: " + keyId);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
+ } catch (Exception e) {
+ log("Error: unable to unwrap key using passphrase");
+ e.printStackTrace();
+ }
+
+ if (recoveredKey == null || !recoveredKey.equals(Utils.base64encode(vek.getEncoded()))) {
+ log("Error: recovered and archived keys do not match!");
+ } else {
+ log("Success: recovered and archived keys do match!");
+ }
+
+
+ passphrase = "secret12345";
+ // Test 12: Generate and archive a passphrase
+ clientId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime().toString();
+ try {
+ byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, null, passphrase,
+ KeyGenAlgorithm.DES3, ivps);
+ requestInfo = client.archiveSecurityData(encoded, clientId, KeyRequestResource.PASS_PHRASE_TYPE);
+ log("Archival Results:");
+ printRequestInfo(requestInfo);
+ keyId = requestInfo.getKeyId();
+ } catch (Exception e) {
+ log("Exception in archiving symmetric key:" + e.toString());
+ e.printStackTrace();
+ }
+
+ //Test 13: Get keyId for active passphrase with client ID
+ log("Getting key ID for passphrase");
+ keyInfo = client.getKeyData(clientId, "active");
+ keyId2 = keyInfo.getKeyId();
+ if (keyId2 == null) {
+ log("No archived key found");
+ } else {
+ log("Archived Key found: " + keyId);
+ }
+
+ if (!keyId.equals(keyId2)) {
+ log("Error: key ids from search and archival do not match");
+ } else {
+ log("Success: key ids from search and archival do match!");
+ }
+
+ // Test 14: Submit a recovery request for the passphrase using a session key
+ log("Submitting a recovery request for the passphrase using session key");
+ recoveryKey = null;
+ recoveryRequestId = null;
+ wrappedRecoveryKey = null;
+ try {
+ recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+ wrappedRecoveryPassphrase = CryptoUtil.wrapPassphrase(token, recoveryPassphrase, ivps, recoveryKey,
+ EncryptionAlgorithm.DES3_CBC_PAD);
+ requestInfo = client.requestRecovery(keyId, null, wrappedRecoveryKey, ivps.getIV());
+ recoveryRequestId = requestInfo.getRequestId();
+ } catch (Exception e) {
+ log("Exception in recovering passphrase using session key: " + e.getMessage());
+ }
+
+ // Test 15: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 16: Get key
+ log("Getting passphrase: " + keyId);
+
+ keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+ ivps_server = new IVParameterSpec( Utils.base64decode(keyData.getNonceData()));
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
+ Utils.base64decode(wrappedRecoveredKey),
+ recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
+ recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
+ } catch (Exception e) {
+ log("Exception in unwrapping key: " + e.toString());
+ e.printStackTrace();
+ }
+
+ if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
+ log("Error: recovered and archived passphrases do not match!");
+ } else {
+ log("Success: recovered and archived passphrases do match!");
+ }
+
+ // Test 17: Submit a recovery request for the passphrase using a passphrase
+ log("Submitting a recovery request for the passphrase using a passphrase");
+ requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ recoveryRequestId = requestInfo.getRequestId();
+
+ //Test 18: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 19: Get key
+ log("Getting passphrase: " + keyId);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
+ recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
+ } catch (Exception e) {
+ log("Error: cannot unwrap key using passphrase");
+ e.printStackTrace();
+ }
+
+ if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
+ log("Error: recovered and archived passphrases do not match!");
+ } else {
+ log("Success: recovered and archived passphrases do match!");
+ }
+
+ // Test 20: Submit a recovery request for the passphrase using a passphrase
+ //Wait until retrieving key before sending input data.
+
+ log("Submitting a recovery request for the passphrase using a passphrase, wait till end to provide recovery data.");
+ requestInfo = client.requestRecovery(keyId, null, null, null);
+ recoveryRequestId = requestInfo.getRequestId();
+
+ //Test 21: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 22: Get key
+ log("Getting passphrase: " + keyId);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
+ recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
+ } catch (Exception e) {
+ log("Error: Can't unwrap recovered key using passphrase");
+ e.printStackTrace();
+ }
+
+ if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
+ log("Error: recovered and archived passphrases do not match!");
+ } else {
+ log("Success: recovered and archived passphrases do match!");
+ }
+ }
+
+ private static void log(String string) {
+ // TODO Auto-generated method stub
+ System.out.println(string);
+ }
+
+ private static void printRequestInfo(KeyRequestInfo info) {
+ log("KeyRequestURL: " + info.getRequestURL());
+ log("Key URL: " + info.getKeyURL());
+ log("Status: " + info.getRequestStatus());
+ log("Type: " + info.getRequestType());
+ }
+
+ //Use this when we actually create random initialization vectors
+ private static IVParameterSpec genIV(int blockSize) throws Exception {
+ // generate an IV
+ byte[] iv = new byte[blockSize];
+
+ Random rnd = new Random();
+ rnd.nextBytes(iv);
+
+ return new IVParameterSpec(iv);
+ }
+}
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java b/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java
new file mode 100644
index 000000000..604430b57
--- /dev/null
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java
@@ -0,0 +1,222 @@
+package com.netscape.cms.servlet.test;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.CharConversionException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.crypto.AlreadyInitializedException;
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.SymmetricKey.NotExtractableException;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.crypto.CryptoUtil;
+import com.netscape.cmsutil.util.Utils;
+
+@SuppressWarnings("deprecation")
+public class GeneratePKIArchiveOptions {
+
+ public static void usage(Options options) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("GeneratePKIArchiveOptions", options);
+ System.exit(1);
+ }
+
+ private static void log(String string) {
+ // TODO Auto-generated method stub
+ System.out.println(string);
+ }
+
+ // read in byte array
+ // we must do this somewhere?
+ public static byte[] read(String fname) throws IOException {
+ File file = new File(fname);
+ byte[] result = new byte[(int) file.length()];
+ InputStream input = null;
+ try {
+ int totalBytesRead = 0;
+ input = new BufferedInputStream(new FileInputStream(file));
+ while (totalBytesRead < result.length) {
+ int bytesRemaining = result.length - totalBytesRead;
+ //input.read() returns -1, 0, or more :
+ int bytesRead = input.read(result, totalBytesRead, bytesRemaining);
+ if (bytesRead > 0) {
+ totalBytesRead = totalBytesRead + bytesRead;
+ }
+ }
+ } catch (Exception e) {
+ throw new IOException(e);
+ } finally {
+ if (input != null) {
+ input.close();
+ }
+ }
+
+ return result;
+ }
+
+ public static void write(byte[] aInput, String outFile) throws IOException {
+ OutputStream output = null;
+ try {
+ output = new BufferedOutputStream(new FileOutputStream(outFile));
+ output.write(aInput);
+ } catch (Exception e) {
+ throw new IOException(e);
+ } finally {
+ if (output != null) {
+ output.close();
+ }
+ }
+ }
+
+ private static void write_file(String data, String outFile) throws IOException {
+ FileWriter fstream = new FileWriter(outFile);
+ BufferedWriter out = new BufferedWriter(fstream);
+ out.write(data);
+ //Close the output stream
+ out.close();
+ }
+
+ public static void main(String args[]) throws InvalidKeyException, CertificateEncodingException,
+ CharConversionException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
+ IllegalStateException, TokenException, IOException, IllegalBlockSizeException, BadPaddingException,
+ InvalidBERException, NotExtractableException {
+ String token_pwd = null;
+ String db_dir = "./";
+ String out_file = "./options.out";
+ String transport_file = "./transport.crt";
+ String key_file = "./symkey.out";
+ String passphrase = null;
+ boolean passphraseMode = false;
+
+ // parse command line arguments
+ Options options = new Options();
+ options.addOption("w", true, "Token password (required)");
+ options.addOption("d", true, "Directory for tokendb");
+ options.addOption("p", true, "Passphrase");
+ options.addOption("t", true, "File with transport cert");
+ options.addOption("o", true, "Output file");
+ options.addOption("k", true, "Key file");
+
+ try {
+ CommandLineParser parser = new PosixParser();
+ CommandLine cmd = parser.parse(options, args);
+
+ if (cmd.hasOption("p")) {
+ passphrase = cmd.getOptionValue("p");
+ passphraseMode = true;
+ }
+
+ if (cmd.hasOption("o")) {
+ out_file = cmd.getOptionValue("o");
+ }
+
+ if (cmd.hasOption("k")) {
+ key_file = cmd.getOptionValue("k");
+ }
+
+ if (cmd.hasOption("t")) {
+ transport_file = cmd.getOptionValue("t");
+ }
+
+ if (cmd.hasOption("w")) {
+ token_pwd = cmd.getOptionValue("w");
+ } else {
+ System.err.println("Error: no token password provided");
+ usage(options);
+ }
+
+ if (cmd.hasOption("d")) {
+ db_dir = cmd.getOptionValue("d");
+ }
+
+ } catch (ParseException e) {
+ System.err.println("Error in parsing command line options: " + e.getMessage());
+ usage(options);
+ }
+
+ // used for crypto operations
+ byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ IVParameterSpec ivps = new IVParameterSpec(iv);
+ CryptoManager manager = null;
+ CryptoToken token = null;
+
+ // used for wrapping to send data to DRM
+ byte[] tcert = read(transport_file);
+ String transportCert = Utils.base64encode(tcert);
+
+ // Initialize token
+ try {
+ CryptoManager.initialize(db_dir);
+ } catch (AlreadyInitializedException e) {
+ // it is ok if it is already initialized
+ } catch (Exception e) {
+ log("INITIALIZATION ERROR: " + e.toString());
+ System.exit(1);
+ }
+
+ // log into token
+ try {
+ manager = CryptoManager.getInstance();
+ token = manager.getInternalKeyStorageToken();
+ Password password = new Password(token_pwd.toCharArray());
+ try {
+ token.login(password);
+ } catch (Exception e) {
+ log("login Exception: " + e.toString());
+ if (!token.isLoggedIn()) {
+ token.initPassword(password, password);
+ }
+ }
+ } catch (Exception e) {
+ log("Exception in logging into token:" + e.toString());
+ }
+
+ // Data to be archived
+ SymmetricKey vek = null;
+ if (!passphraseMode) {
+ vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ // store vek in file
+ write_file(Utils.base64encode(vek.getKeyData()), key_file);
+ }
+
+ byte[] encoded = null;
+
+ if (passphraseMode) {
+ encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, null, passphrase,
+ KeyGenAlgorithm.DES3, ivps);
+ } else {
+ encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
+ KeyGenAlgorithm.DES3, ivps);
+ }
+
+ // write encoded to file
+ write_file(Utils.base64encode(encoded), out_file);
+
+ }
+}
diff --git a/base/kra/setup/CMakeLists.txt b/base/kra/setup/CMakeLists.txt
new file mode 100644
index 000000000..f5f069cdb
--- /dev/null
+++ b/base/kra/setup/CMakeLists.txt
@@ -0,0 +1,8 @@
+set(VERSION ${APPLICATION_VERSION})
+
+install(
+ FILES
+ registry_instance
+ DESTINATION
+ ${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}/${PROJECT_NAME}/setup
+)
diff --git a/base/kra/setup/registry_instance b/base/kra/setup/registry_instance
new file mode 100644
index 000000000..3210b9131
--- /dev/null
+++ b/base/kra/setup/registry_instance
@@ -0,0 +1,63 @@
+# Establish PKI Variable "Slot" Substitutions
+
+PKI_FLAVOR=[PKI_FLAVOR]
+export PKI_FLAVOR
+
+PKI_SUBSYSTEM_TYPE=[PKI_SUBSYSTEM_TYPE]
+export PKI_SUBSYSTEM_TYPE
+
+PKI_USER=[PKI_USER]
+export PKI_USER
+
+PKI_GROUP=[PKI_GROUP]
+export PKI_GROUP
+
+PKI_INSTANCE_ID=[PKI_INSTANCE_ID]
+export PKI_INSTANCE_ID
+
+PKI_INSTANCE_PATH=[PKI_INSTANCE_PATH]
+export PKI_INSTANCE_PATH
+
+PKI_INSTANCE_INITSCRIPT=[PKI_INSTANCE_INITSCRIPT]
+export PKI_INSTANCE_INITSCRIPT
+
+PKI_SERVER_XML_CONF=[PKI_SERVER_XML_CONF]
+export PKI_SERVER_XML_CONF
+
+# Use CATALINA_BASE
+
+CATALINA_BASE=$PKI_INSTANCE_PATH
+export CATALINA_BASE
+
+TOMCAT_PROG=$PKI_INSTANCE_ID
+export TOMCAT_PROG
+
+TOMCAT_USER=$PKI_USER
+export TOMCAT_USER
+
+TOMCAT_GROUP=$PKI_GROUP
+export TOMCAT_GROUP
+
+PKI_LOCKDIR="/var/lock/${PKI_FLAVOR}/${PKI_SUBSYSTEM_TYPE}"
+export PKI_LOCKDIR
+
+PKI_LOCKFILE="${PKI_LOCKDIR}/${PKI_INSTANCE_ID}"
+export PKI_LOCKFILE
+
+PKI_PIDDIR="/var/run/${PKI_FLAVOR}/${PKI_SUBSYSTEM_TYPE}"
+export PKI_PIDDIR
+
+PKI_PIDFILE="${PKI_PIDDIR}/${PKI_INSTANCE_ID}.pid"
+export PKI_PIDFILE
+
+TOMCAT_LOCKFILE=/var/lock/subsys/${PKI_INSTANCE_ID}
+export TOMCAT_LOCKFILE
+
+TOMCAT_PIDFILE=[TOMCAT_PIDFILE]
+export TOMCAT_PIDFILE
+
+pki_instance_configuration_file=${PKI_INSTANCE_PATH}/conf/CS.cfg
+export pki_instance_configuration_file
+
+RESTART_SERVER=${PKI_INSTANCE_PATH}/conf/restart_server_after_configuration
+export RESTART_SERVER
diff --git a/base/kra/shared/conf/CMakeLists.txt b/base/kra/shared/conf/CMakeLists.txt
new file mode 100644
index 000000000..e3cef5915
--- /dev/null
+++ b/base/kra/shared/conf/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(VERSION ${APPLICATION_VERSION})
+set(MAJOR_VERSION ${APPLICATION_VERSION_MAJOR})
+set(MINOR_VERSION ${APPLICATION_VERSION_MINOR})
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CS.cfg.in ${CMAKE_CURRENT_BINARY_DIR}/CS.cfg @ONLY)
+
+install(
+ FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/CS.cfg
+ DESTINATION
+ ${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}/${PROJECT_NAME}/conf
+)
diff --git a/base/kra/shared/conf/CS.cfg.in b/base/kra/shared/conf/CS.cfg.in
new file mode 100644
index 000000000..a6d49ceb5
--- /dev/null
+++ b/base/kra/shared/conf/CS.cfg.in
@@ -0,0 +1,383 @@
+_000=##
+_001=## Data Recovery Manager (DRM) Configuration File
+_002=##
+pkicreate.pki_instance_root=[PKI_INSTANCE_ROOT]
+pkicreate.pki_instance_name=[PKI_INSTANCE_ID]
+pkicreate.subsystem_type=[PKI_SUBSYSTEM_TYPE]
+pkicreate.agent_secure_port=[PKI_AGENT_SECURE_PORT]
+pkicreate.ee_secure_port=[PKI_EE_SECURE_PORT]
+pkicreate.admin_secure_port=[PKI_ADMIN_SECURE_PORT]
+pkicreate.secure_port=[PKI_SECURE_PORT]
+pkicreate.unsecure_port=[PKI_UNSECURE_PORT]
+pkicreate.tomcat_server_port=[TOMCAT_SERVER_PORT]
+pkicreate.user=[PKI_USER]
+pkicreate.group=[PKI_GROUP]
+pkicreate.systemd.servicename=[PKI_SYSTEMD_SERVICENAME]
+pkiremove.cert.subsystem.nickname=subsystemCert cert-[PKI_INSTANCE_ID]
+installDate=[INSTALL_TIME]
+preop.wizard.name=DRM Setup Wizard
+preop.product.name=CS
+preop.product.version=@VERSION@
+preop.system.name=DRM
+preop.system.fullname=Data Recovery Manager
+proxy.securePort=[PKI_PROXY_SECURE_PORT]
+proxy.unsecurePort=[PKI_PROXY_UNSECURE_PORT]
+cs.state=0
+cs.type=KRA
+admin.interface.uri=kra/admin/console/config/wizard
+agent.interface.uri=kra/agent/kra
+authType=pwd
+preop.securitydomain.admin_url=https://[PKI_MACHINE_NAME]:9445
+instanceRoot=[PKI_INSTANCE_PATH]
+machineName=[PKI_MACHINE_NAME]
+instanceId=[PKI_INSTANCE_ID]
+pidDir=[PKI_PIDDIR]
+service.machineName=[PKI_MACHINE_NAME]
+service.instanceDir=[PKI_INSTANCE_ROOT]
+service.securePort=[PKI_AGENT_SECURE_PORT]
+service.non_clientauth_securePort=[PKI_EE_SECURE_PORT]
+service.unsecurePort=[PKI_UNSECURE_PORT]
+service.instanceID=[PKI_INSTANCE_ID]
+preop.admin.name=Data Recovery Manager Administrator
+preop.admin.group=Data Recovery Manager Agents
+preop.admincert.profile=caAdminCert
+preop.pin=[PKI_RANDOM_NUMBER]
+kra.cert.list=transport,storage,sslserver,subsystem,audit_signing
+kra.cert.transport.certusage=SSLClient
+kra.cert.storage.certusage=SSLClient
+kra.cert.sslserver.certusage=SSLServer
+kra.cert.subsystem.certusage=SSLClient
+kra.cert.audit_signing.certusage=ObjectSigner
+preop.cert.list=transport,storage,sslserver,subsystem,audit_signing
+preop.cert.rsalist=transport,storage,audit_signing
+preop.cert.transport.enable=true
+preop.cert.storage.enable=true
+preop.cert.sslserver.enable=true
+preop.cert.subsystem.enable=true
+preop.cert.audit_signing.enable=true
+preop.cert.audit_signing.defaultSigningAlgorithm=SHA256withRSA
+preop.cert.audit_signing.dn=CN=DRM Audit Signing Certificate
+preop.cert.audit_signing.keysize.custom_size=2048
+preop.cert.audit_signing.keysize.size=2048
+preop.cert.audit_signing.nickname=auditSigningCert cert-[PKI_INSTANCE_ID]
+preop.cert.audit_signing.profile=caInternalAuthAuditSigningCert
+preop.cert.audit_signing.signing.required=false
+preop.cert.audit_signing.subsystem=kra
+preop.cert.audit_signing.type=remote
+preop.cert.audit_signing.userfriendlyname=DRM Audit Signing Certificate
+preop.cert.audit_signing.cncomponent.override=true
+preop.cert.storage.defaultSigningAlgorithm=SHA256withRSA
+preop.cert.storage.dn=CN=DRM Storage Certificate
+preop.cert.storage.keysize.custom_size=2048
+preop.cert.storage.keysize.size=2048
+preop.cert.storage.nickname=storageCert cert-[PKI_INSTANCE_ID]
+preop.cert.storage.profile=caInternalAuthDRMstorageCert
+preop.cert.storage.signing.required=false
+preop.cert.storage.subsystem=kra
+preop.cert.storage.type=remote
+preop.cert.storage.userfriendlyname=Storage Certificate
+preop.cert.storage.cncomponent.override=true
+preop.cert.transport.defaultSigningAlgorithm=SHA256withRSA
+preop.cert.transport.dn=CN=DRM Transport Certificate
+preop.cert.transport.keysize.custom_size=2048
+preop.cert.transport.keysize.size=2048
+preop.cert.transport.nickname=transportCert cert-[PKI_INSTANCE_ID]
+preop.cert.transport.profile=caInternalAuthTransportCert
+preop.cert.transport.signing.required=true
+preop.cert.transport.subsystem=kra
+preop.cert.transport.type=remote
+preop.cert.transport.userfriendlyname=Transport Certificate
+preop.cert.transport.cncomponent.override=true
+preop.cert.sslserver.defaultSigningAlgorithm=SHA256withRSA
+preop.cert.sslserver.dn=CN=[PKI_MACHINE_NAME]
+preop.cert.sslserver.keysize.custom_size=2048
+preop.cert.sslserver.keysize.size=2048
+preop.cert.sslserver.nickname=Server-Cert cert-[PKI_INSTANCE_ID]
+preop.cert.sslserver.profile=caInternalAuthServerCert
+preop.cert.sslserver.signing.required=false
+preop.cert.sslserver.subsystem=kra
+preop.cert.sslserver.type=remote
+preop.cert.sslserver.userfriendlyname=SSL Server Certificate
+preop.cert.sslserver.cncomponent.override=false
+preop.cert.subsystem.defaultSigningAlgorithm=SHA256withRSA
+preop.cert.subsystem.dn=CN=DRM Subsystem Certificate
+preop.cert.subsystem.keysize.custom_size=2048
+preop.cert.subsystem.keysize.size=2048
+preop.cert.subsystem.nickname=subsystemCert cert-[PKI_INSTANCE_ID]
+preop.cert.subsystem.profile=caInternalAuthSubsystemCert
+preop.cert.subsystem.signing.required=false
+preop.cert.subsystem.subsystem=kra
+preop.cert.subsystem.type=remote
+preop.cert.subsystem.userfriendlyname=Subsystem Certificate
+preop.cert.subsystem.cncomponent.override=true
+preop.hierarchy.profile=caCert.profile
+preop.configModules.module0.userFriendlyName=NSS Internal PKCS #11 Module
+preop.configModules.module0.commonName=NSS Internal PKCS #11 Module
+preop.configModules.module0.imagePath=../img/clearpixel.gif
+preop.configModules.module1.userFriendlyName=nCipher's nFast Token Hardware Module
+preop.configModules.module1.commonName=nfast
+preop.configModules.module1.imagePath=../img/clearpixel.gif
+preop.configModules.module2.userFriendlyName=SafeNet's LunaSA Token Hardware Module
+preop.configModules.module2.commonName=lunasa
+preop.configModules.module2.imagePath=../img/clearpixel.gif
+preop.configModules.count=3
+preop.module.token=Internal Key Storage Token
+passwordFile=[PKI_INSTANCE_PATH]/conf/password.conf
+passwordClass=com.netscape.cmsutil.password.PlainPasswordFile
+multiroles=true
+multiroles.false.groupEnforceList=Administrators,Auditors,Trusted Managers,Certificate Manager Agents,Registration Manager Agents,Data Recovery Manager Agents,Online Certificate Status Manager Agents,Token Key Service Manager Agents,Enterprise CA Administrators,Enterprise KRA Adminstrators,Enterprise OCSP Administrators,Enterprise RA Administrators,Enterprise TKS Administrators,Enterprise TPS Administrators,Security Domain Administrators,Subsystem Group
+CrossCertPair._000=##
+CrossCertPair._001=## CrossCertPair Import
+CrossCertPair._002=##
+CrossCertPair.ldap=internaldb
+accessEvaluator.impl.group.class=com.netscape.cms.evaluators.GroupAccessEvaluator
+accessEvaluator.impl.ipaddress.class=com.netscape.cms.evaluators.IPAddressAccessEvaluator
+accessEvaluator.impl.user.class=com.netscape.cms.evaluators.UserAccessEvaluator
+auths._000=##
+auths._001=## new authentication
+auths._002=##
+auths.impl._000=##
+auths.impl._001=## authentication manager implementations
+auths.impl._002=##
+auths.impl.AgentCertAuth.class=com.netscape.cms.authentication.AgentCertAuthentication
+auths.impl.CMCAuth.class=com.netscape.cms.authentication.CMCAuth
+auths.impl.NISAuth.class=com.netscape.cms.authentication.NISAuth
+auths.impl.PortalEnroll.class=com.netscape.cms.authentication.PortalEnroll
+auths.impl.TokenAuth.class=com.netscape.cms.authentication.TokenAuthentication
+auths.impl.UdnPwdDirAuth.class=com.netscape.cms.authentication.UdnPwdDirAuthentication
+auths.impl.UidPwdDirAuth.class=com.netscape.cms.authentication.UidPwdDirAuthentication
+auths.impl.UidPwdPinDirAuth.class=com.netscape.cms.authentication.UidPwdPinDirAuthentication
+auths.instance.AgentCertAuth.agentGroup=Certificate Manager Agents
+auths.instance.AgentCertAuth.pluginName=AgentCertAuth
+auths.instance.TokenAuth.pluginName=TokenAuth
+auths.revocationChecking.bufferSize=50
+auths.revocationChecking.enabled=false
+auths.revocationChecking.kra=kra
+authz._000=##
+authz._001=## new authorizatioin
+authz._002=##
+authz.evaluateOrder=deny,allow
+authz.sourceType=ldap
+authz.impl._000=##
+authz.impl._001=## authorization manager implementations
+authz.impl._002=##
+authz.impl.BasicAclAuthz.class=com.netscape.cms.authorization.BasicAclAuthz
+authz.impl.DirAclAuthz.class=com.netscape.cms.authorization.DirAclAuthz
+authz.instance.BasicAclAuthz.pluginName=BasicAclAuthz
+authz.instance.DirAclAuthz.ldap=internaldb
+authz.instance.DirAclAuthz.pluginName=DirAclAuthz
+authz.instance.DirAclAuthz.ldap._000=##
+authz.instance.DirAclAuthz.ldap._001=## Internal Database
+authz.instance.DirAclAuthz.ldap._002=##
+cmc.cert.confirmRequired=false
+cmc.lraPopWitness.verify.allow=true
+cmc.revokeCert.verify=true
+cmc.revokeCert.sharedSecret.class=com.netscape.cms.authentication.SharedSecret
+cmc.sharedSecret.class=com.netscape.cms.authentication.SharedSecret
+cms.version=@MAJOR_VERSION@.@MINOR_VERSION@
+dbs.enableSerialManagement=false
+dbs.beginRequestNumber=1
+dbs.endRequestNumber=10000000
+dbs.requestIncrement=10000000
+dbs.requestLowWaterMark=2000000
+dbs.requestCloneTransferNumber=10000
+dbs.requestDN=ou=kra, ou=requests
+dbs.requestRangeDN=ou=requests, ou=ranges
+dbs.beginSerialNumber=1
+dbs.endSerialNumber=10000000
+dbs.serialIncrement=10000000
+dbs.serialLowWaterMark=2000000
+dbs.serialCloneTransferNumber=10000
+dbs.serialDN=ou=keyRepository, ou=kra
+dbs.serialRangeDN=ou=keyRepository, ou=ranges
+dbs.beginReplicaNumber=1
+dbs.endReplicaNumber=100
+dbs.replicaIncrement=100
+dbs.replicaLowWaterMark=20
+dbs.replicaCloneTransferNumber=5
+dbs.replicaDN=ou=replica
+dbs.replicaRangeDN=ou=replica, ou=ranges
+dbs.ldap=internaldb
+dbs.newSchemaEntryAdded=true
+debug.append=true
+debug.enabled=true
+debug.filename=[PKI_INSTANCE_PATH]/logs/debug
+debug.hashkeytypes=
+debug.level=0
+debug.showcaller=false
+keys.ecc.curve.list=nistp256,nistp384,nistp521,sect163k1,nistk163,sect163r1,sect163r2,nistb163,sect193r1,sect193r2,sect233k1,nistk233,sect233r1,nistb233,sect239k1,sect283k1,nistk283,sect283r1,nistb283,sect409k1,nistk409,sect409r1,nistb409,sect571k1,nistk571,sect571r1,nistb571,secp160k1,secp160r1,secp160r2,secp192k1,secp192r1,nistp192,secp224k1,secp224r1,nistp224,secp256k1,secp256r1,secp384r1,secp521r1,prime192v1,prime192v2,prime192v3,prime239v1,prime239v2,prime239v3,c2pnb163v1,c2pnb163v2,c2pnb163v3,c2pnb176v1,c2tnb191v1,c2tnb191v2,c2tnb191v3,c2pnb208w1,c2tnb239v1,c2tnb239v2,c2tnb239v3,c2pnb272w1,c2pnb304w1,c2tnb359w1,c2pnb368w1,c2tnb431r1,secp112r1,secp112r2,secp128r1,secp128r2,sect113r1,sect113r2,sect131r1,sect131r2
+keys.ecc.curve.display.list=nistp256 (secp256r1),nistp384 (secp384r1),nistp521 (secp521r1),nistk163 (sect163k1),sect163r1,nistb163 (sect163r2),sect193r1,sect193r2,nistk233 (sect233k1),nistb233 (sect233r1),sect239k1,nistk283 (sect283k1),nistb283 (sect283r1),nistk409 (sect409k1),nistb409 (sect409r1),nistk571 (sect571k1),nistb571 (sect571r1),secp160k1,secp160r1,secp160r2,secp192k1,nistp192 (secp192r1, prime192v1),secp224k1,nistp224 (secp224r1),secp256k1,prime192v2,prime192v3,prime239v1,prime239v2,prime239v3,c2pnb163v1,c2pnb163v2,c2pnb163v3,c2pnb176v1,c2tnb191v1,c2tnb191v2,c2tnb191v3,c2pnb208w1,c2tnb239v1,c2tnb239v2,c2tnb239v3,c2pnb272w1,c2pnb304w1,c2tnb359w1,c2pnb368w1,c2tnb431r1,secp112r1,secp112r2,secp128r1,secp128r2,sect113r1,sect113r2,sect131r1,sect131r2
+keys.ecc.curve.default=nistp256
+keys.rsa.keysize.default=2048
+internaldb._000=##
+internaldb._001=## Internal Database
+internaldb._002=##
+internaldb.maxConns=15
+internaldb.minConns=3
+internaldb.ldapauth.authtype=BasicAuth
+internaldb.ldapauth.bindDN=cn=Directory Manager
+internaldb.ldapauth.bindPWPrompt=Internal LDAP Database
+internaldb.ldapauth.clientCertNickname=
+internaldb.ldapconn.host=
+internaldb.ldapconn.port=
+internaldb.ldapconn.secureConn=false
+preop.internaldb.schema.ldif=/usr/share/[PKI_FLAVOR]/kra/conf/schema.ldif
+preop.internaldb.ldif=/usr/share/[PKI_FLAVOR]/kra/conf/database.ldif
+preop.internaldb.data_ldif=/usr/share/[PKI_FLAVOR]/kra/conf/db.ldif,/usr/share/[PKI_FLAVOR]/kra/conf/acl.ldif
+preop.internaldb.index_ldif=
+preop.internaldb.manager_ldif=/usr/share/[PKI_FLAVOR]/ca/conf/manager.ldif
+preop.internaldb.post_ldif=/usr/share/[PKI_FLAVOR]/kra/conf/index.ldif,/usr/share/[PKI_FLAVOR]/kra/conf/vlv.ldif,/usr/share/[PKI_FLAVOR]/kra/conf/vlvtasks.ldif
+preop.internaldb.wait_dn=cn=index1160527115, cn=index, cn=tasks, cn=config
+internaldb.multipleSuffix.enable=false
+jobsScheduler._000=##
+jobsScheduler._001=## jobScheduler
+jobsScheduler._002=##
+jobsScheduler.enabled=false
+jobsScheduler.interval=1
+jss._000=##
+jss._001=## JSS
+jss._002=##
+jss.configDir=[PKI_INSTANCE_PATH]/alias/
+jss.enable=true
+jss.secmodName=secmod.db
+jss.ocspcheck.enable=false
+jss.ssl.cipherfortezza=true
+jss.ssl.cipherpref=
+jss.ssl.cipherversion=cipherdomestic
+kra.Policy._000=##
+kra.Policy._001=## Certificate Policy Framework (deprecated)
+kra.Policy._002=##
+kra.Policy._003=## Set 'kra.Policy.enable=true' to allow the following:
+kra.Policy._004=##
+kra.Policy._005=## SERVLET-NAME URL-PATTERN
+kra.Policy._006=## ====================================================
+kra.Policy._007=## krapolicy kra/krapolicy
+kra.Policy._008=##
+kra.Policy.enable=false
+kra.keySplitting=false
+kra.noOfRequiredRecoveryAgents=1
+kra.recoveryAgentGroup=Data Recovery Manager Agents
+kra.reqdbInc=20
+kra.entropy.bitsperkeypair=0
+kra.entropy.blockwarnms=0
+kra.storageUnit.nickName=storageCert cert-[PKI_INSTANCE_ID]
+kra.transportUnit.nickName=transportCert cert-[PKI_INSTANCE_ID]
+log._000=##
+log._001=## Logging
+log._002=##
+log.impl.file.class=com.netscape.cms.logging.RollingLogFile
+log.instance.SignedAudit._000=##
+log.instance.SignedAudit._001=## Signed Audit Logging
+log.instance.SignedAudit._002=##
+log.instance.SignedAudit._003=##
+log.instance.SignedAudit._004=## Available Audit events:
+log.instance.SignedAudit._005=## AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,ROLE_ASSUME,CONFIG_CERT_POLICY,CONFIG_CERT_PROFILE,CONFIG_CRL_PROFILE,CONFIG_OCSP_PROFILE,CONFIG_AUTH,CONFIG_ROLE,CONFIG_ACL,CONFIG_SIGNED_AUDIT,CONFIG_ENCRYPTION,CONFIG_TRUSTED_PUBLIC_KEY,CONFIG_DRM,SELFTESTS_EXECUTION,AUDIT_LOG_DELETE,LOG_PATH_CHANGE,LOG_EXPIRATION_CHANGE,PRIVATE_KEY_ARCHIVE_REQUEST,PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,KEY_RECOVERY_REQUEST,KEY_RECOVERY_REQUEST_ASYNC,KEY_RECOVERY_AGENT_LOGIN,KEY_RECOVERY_REQUEST_PROCESSED,KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,KEY_GEN_ASYMMETRIC,NON_PROFILE_CERT_REQUEST,PROFILE_CERT_REQUEST,CERT_REQUEST_PROCESSED,CERT_STATUS_CHANGE_REQUEST,CERT_STATUS_CHANGE_REQUEST_PROCESSED,AUTHZ_SUCCESS,AUTHZ_FAIL,INTER_BOUNDARY,AUTH_FAIL,AUTH_SUCCESS,CERT_PROFILE_APPROVAL,PROOF_OF_POSSESSION,CRL_RETRIEVAL,CRL_VALIDATION,CMC_SIGNED_REQUEST_SIG_VERIFY,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,SERVER_SIDE_KEYGEN_REQUEST,COMPUTE_SESSION_KEY_REQUEST,COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,DIVERSIFY_KEY_REQUEST,DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS, DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE,ENCRYPT_DATA_REQUEST,ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS,ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE,OCSP_ADD_CA_REQUEST,OCSP_ADD_CA_REQUEST_PROCESSED,OCSP_REMOVE_CA_REQUEST,OCSP_REMOVE_CA_REQUEST_PROCESSED_SUCCESS,OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE,COMPUTE_RANDOM_DATA_REQUEST,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_SUCCESS,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_FAILURE,CIMC_CERT_VERIFICATION,CONFIG_SERIAL_NUMBER
+log.instance.SignedAudit._006=##
+log.instance.SignedAudit.bufferSize=512
+log.instance.SignedAudit.enable=true
+log.instance.SignedAudit.events=AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,ROLE_ASSUME,CONFIG_CERT_POLICY,CONFIG_CERT_PROFILE,CONFIG_CRL_PROFILE,CONFIG_OCSP_PROFILE,CONFIG_AUTH,CONFIG_ROLE,CONFIG_ACL,CONFIG_SIGNED_AUDIT,CONFIG_ENCRYPTION,CONFIG_TRUSTED_PUBLIC_KEY,CONFIG_DRM,SELFTESTS_EXECUTION,AUDIT_LOG_DELETE,LOG_PATH_CHANGE,PRIVATE_KEY_ARCHIVE_REQUEST,PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,KEY_RECOVERY_REQUEST,KEY_RECOVERY_REQUEST_ASYNC,KEY_RECOVERY_AGENT_LOGIN,KEY_RECOVERY_REQUEST_PROCESSED,KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,KEY_GEN_ASYMMETRIC,NON_PROFILE_CERT_REQUEST,PROFILE_CERT_REQUEST,CERT_REQUEST_PROCESSED,CERT_STATUS_CHANGE_REQUEST,CERT_STATUS_CHANGE_REQUEST_PROCESSED,AUTHZ_SUCCESS,AUTHZ_FAIL,INTER_BOUNDARY,AUTH_FAIL,AUTH_SUCCESS,CERT_PROFILE_APPROVAL,PROOF_OF_POSSESSION,CRL_RETRIEVAL,CRL_VALIDATION,CMC_SIGNED_REQUEST_SIG_VERIFY,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,SERVER_SIDE_KEYGEN_REQUEST,COMPUTE_SESSION_KEY_REQUEST,COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,DIVERSIFY_KEY_REQUEST,DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS, DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE,ENCRYPT_DATA_REQUEST,ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS,ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE,OCSP_ADD_CA_REQUEST,OCSP_ADD_CA_REQUEST_PROCESSED,OCSP_REMOVE_CA_REQUEST,OCSP_REMOVE_CA_REQUEST_PROCESSED_SUCCESS,OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE,COMPUTE_RANDOM_DATA_REQUEST,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_SUCCESS,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_FAILURE,CIMC_CERT_VERIFICATION,CONFIG_SERIAL_NUMBER
+log.instance.SignedAudit.expirationTime=0
+log.instance.SignedAudit.fileName=[PKI_INSTANCE_PATH]/logs/signedAudit/kra_cert-kra_audit
+log.instance.SignedAudit.flushInterval=5
+log.instance.SignedAudit.level=1
+log.instance.SignedAudit.logSigning=false
+log.instance.SignedAudit.maxFileSize=2000
+log.instance.SignedAudit.pluginName=file
+log.instance.SignedAudit.rolloverInterval=2592000
+log.instance.SignedAudit.signedAudit:_000=##
+log.instance.SignedAudit.signedAudit:_001=## Fill in the nickname of a trusted signing certificate to allow KRA audit logs to be signed
+log.instance.SignedAudit.signedAudit:_002=##
+log.instance.SignedAudit.signedAuditCertNickname=auditSigningCert cert-[PKI_INSTANCE_ID]
+log.instance.SignedAudit.type=signedAudit
+log.instance.System._000=##
+log.instance.System._001=## System Logging
+log.instance.System._002=##
+log.instance.System.bufferSize=512
+log.instance.System.enable=true
+log.instance.System.expirationTime=0
+log.instance.System.fileName=[PKI_INSTANCE_PATH]/logs/system
+log.instance.System.flushInterval=5
+log.instance.System.level=3
+log.instance.System.maxFileSize=2000
+log.instance.System.pluginName=file
+log.instance.System.rolloverInterval=2592000
+log.instance.System.type=system
+log.instance.Transactions._000=##
+log.instance.Transactions._001=## Transaction Logging
+log.instance.Transactions._002=##
+log.instance.Transactions.bufferSize=512
+log.instance.Transactions.enable=true
+log.instance.Transactions.expirationTime=0
+log.instance.Transactions.fileName=[PKI_INSTANCE_PATH]/logs/transactions
+log.instance.Transactions.flushInterval=5
+log.instance.Transactions.level=1
+log.instance.Transactions.maxFileSize=2000
+log.instance.Transactions.pluginName=file
+log.instance.Transactions.rolloverInterval=2592000
+log.instance.Transactions.type=transaction
+logAudit.fileName=[PKI_INSTANCE_PATH]/logs/access
+logError.fileName=[PKI_INSTANCE_PATH]/logs/error
+oidmap.auth_info_access.class=netscape.security.extensions.AuthInfoAccessExtension
+oidmap.auth_info_access.oid=1.3.6.1.5.5.7.1.1
+oidmap.challenge_password.class=com.netscape.cms.servlet.cert.scep.ChallengePassword
+oidmap.challenge_password.oid=1.2.840.113549.1.9.7
+oidmap.extended_key_usage.class=netscape.security.extensions.ExtendedKeyUsageExtension
+oidmap.extended_key_usage.oid=2.5.29.37
+oidmap.extensions_requested_pkcs9.class=com.netscape.cms.servlet.cert.scep.ExtensionsRequested
+oidmap.extensions_requested_pkcs9.oid=1.2.840.113549.1.9.14
+oidmap.extensions_requested_vsgn.class=com.netscape.cms.servlet.cert.scep.ExtensionsRequested
+oidmap.extensions_requested_vsgn.oid=2.16.840.1.113733.1.9.8
+oidmap.netscape_comment.class=netscape.security.x509.NSCCommentExtension
+oidmap.netscape_comment.oid=2.16.840.1.113730.1.13
+oidmap.ocsp_no_check.class=netscape.security.extensions.OCSPNoCheckExtension
+oidmap.ocsp_no_check.oid=1.3.6.1.5.5.7.48.1.5
+oidmap.pse.class=netscape.security.extensions.PresenceServerExtension
+oidmap.pse.oid=2.16.840.1.113730.1.18
+oidmap.subject_info_access.class=netscape.security.extensions.SubjectInfoAccessExtension
+oidmap.subject_info_access.oid=1.3.6.1.5.5.7.1.11
+os.serverName=cert-[PKI_INSTANCE_ID]
+os.userid=nobody
+registry.file=[PKI_INSTANCE_PATH]/conf/registry.cfg
+selftests._000=##
+selftests._001=## Self Tests
+selftests._002=##
+selftests._003=## The Self-Test plugin SystemCertsVerification uses the
+selftests._004=## following parameters (where certusage is optional):
+selftests._005=## kra.cert.list = <list of cert tag names deliminated by ",">
+selftests._006=## kra.cert.<cert tag name>.nickname
+selftests._007=## kra.cert.<cert tag name>.certusage
+selftests._008=##
+selftests.container.instance.KRAPresence=com.netscape.cms.selftests.kra.KRAPresence
+selftests.container.instance.SystemCertsVerification=com.netscape.cms.selftests.common.SystemCertsVerification
+selftests.container.logger.bufferSize=512
+selftests.container.logger.class=com.netscape.cms.logging.RollingLogFile
+selftests.container.logger.enable=true
+selftests.container.logger.expirationTime=0
+selftests.container.logger.fileName=[PKI_INSTANCE_PATH]/logs/selftests.log
+selftests.container.logger.flushInterval=5
+selftests.container.logger.level=1
+selftests.container.logger.maxFileSize=2000
+selftests.container.logger.register=false
+selftests.container.logger.rolloverInterval=2592000
+selftests.container.logger.type=transaction
+selftests.container.order.onDemand=KRAPresence:critical
+selftests.container.order.startup=SystemCertsVerification:critical
+selftests.plugin.KRAPresence.SubId=kra
+selftests.plugin.SystemCertsVerification.SubId=kra
+smtp.host=localhost
+smtp.port=25
+subsystem.0.class=com.netscape.kra.KeyRecoveryAuthority
+subsystem.0.id=kra
+subsystem.1.class=com.netscape.cmscore.selftests.SelfTestSubsystem
+subsystem.1.id=selftests
+subsystem.2.class=com.netscape.cmscore.util.StatsSubsystem
+subsystem.2.id=stats
+usrgrp._000=##
+usrgrp._001=## User/Group
+usrgrp._002=##
+usrgrp.ldap=internaldb
+multiroles._000=##
+multiroles._001=## multiroles
+multiroles._002=##
+multiroles.enable=true
+multiroles.false.groupEnforceList=Administrators,Auditors,Trusted Managers,Certificate Manager Agents,Registration Manager Agents,Data Recovery Manager Agents,Online Certificate Status Manager Agents,Token Key Service Manager Agents,Enterprise CA Administrators,Enterprise KRA Administrators,Enterprise OCSP Administrators,Enterprise RA Administrators,Enterprise TKS Administrators,Enterprise TPS Administrators,Security Domain Administrators,Subsystem Group,ClonedSubsystems
diff --git a/base/kra/shared/conf/acl.ldif b/base/kra/shared/conf/acl.ldif
new file mode 100644
index 000000000..38a9a088c
--- /dev/null
+++ b/base/kra/shared/conf/acl.ldif
@@ -0,0 +1,42 @@
+dn: cn=aclResources,{rootSuffix}
+objectClass: top
+objectClass: CertACLS
+cn: aclResources
+resourceACLS: certServer.general.configuration:read,modify,delete:allow (read) group="Administrators" || group="Auditors" || group="Data Recovery Manager Agents";allow (modify,delete) group="Administrators":Administrators, auditors, and agents are allowed to read CMS general configuration but only administrators are allowed to modify and delete
+resourceACLS: certServer.acl.configuration:read,modify:allow (read) group="Administrators" || group="Data Recovery Manager Agents" || group="Auditors";allow (modify) group="Administrators":Administrators, agents and auditors are allowed to read ACL configuration but only administrators allowed to modify
+resourceACLS: certServer.log.configuration:read,modify:allow (read) group="Administrators" || group="Auditors" || group="Data Recovery Manager Agents";allow (modify) group="Administrators":Administrators, Agents, and auditors are allowed to read the log configuration but only administrators are allowed to modify
+resourceACLS: certServer.log.configuration.fileName:read,modify:allow (read) group="Administrators" || group="Auditors" || group="Data Recovery Manager Agents";deny (modify) user=anybody:Nobody is allowed to modify a fileName parameter
+#resourceACLS: certServer.log.configuration.signedAudit.expirationTime:read,modify:allow (read) group="Administrators" || group="Auditors" || group="Data Recovery Manager Agents";deny (modify) user=anybody:Nobody is allowed to modify an expirationTime parameter
+resourceACLS: certServer.log.content.signedAudit:read:allow (read) group="Auditors":Only auditor is allowed to read the signed audit log
+resourceACLS: certServer.log.content.system:read:allow (read) group="Administrators" || group="Data Recovery Manager Agents" || group="Auditors":Administrators, auditors, and agents are allowed to read the log content
+resourceACLS: certServer.log.content.transactions:read:allow (read) group="Administrators" || group="Data Recovery Manager Agents" || group="Auditors":Administrators, auditors, and agents are allowed to read the log content
+resourceACLS: certServer.auth.configuration:read,modify:allow (read) group="Administrators" || group="Data Recovery Manager Agents" || group="Auditors";allow (modify) group="Administrators":Administrators, agents, and auditors are allowed to read authentication configuration but only administrators allowed to modify
+resourceACLS: certServer.registry.configuration:read,modify:allow (read) group="Administrators" || group="Data Recovery Manager Agents" || group="Auditors";allow (modify) group="Administrators":this acl is shared by all admin servlets
+resourceACLS: certServer.job.configuration:read,modify:allow (read) group="Administrators" || group="Data Recovery Manager Agents" || group="Auditors";allow (modify) group="Administrators":Administrators, agents, and auditors are allowed to read job configuration but only administrators allowed to modify
+resourceACLS: certServer.kra.configuration:read,modify:allow (read) group="Administrators" || group="Auditors" || group="Data Recovery Manager Agents";allow (modify) group="Administrators":Administrators, auditors, and agents are allowed to read DRM configuration but only administrators allowed to modify
+resourceACLS: certServer.kra.key:read,recover,download:allow (read,recover,download) group="Data Recovery Manager Agents":Only data recovery manager agents retrieve key information
+resourceACLS: certServer.kra.request:read:allow (read) group="Data Recovery Manager Agents":Data Recovery Manager Agents may read request
+resourceACLS: certServer.kra.keys:list:allow (list) group="Data Recovery Manager Agents":Only data recovery manager agents list keys
+resourceACLS: certServer.kra.requests:list:allow (list) group="Data Recovery Manager Agents":Only data recovery manager agents list key archival requests
+resourceACLS: certServer.admin.certificate:import:allow (import) user="anybody":Any user may import a certificate
+resourceACLS: certServer.admin.request.enrollment:submit,read,execute:allow (submit) user="anybody":Anybody may submit an enrollment request
+resourceACLS: certServer.kra.connector:submit:allow (submit) group="Trusted Managers":Only Trusted Managers submit requests
+resourceACLS: certServer.kra.systemstatus:read:allow (read) group="Data Recovery Manager Agents":Data Recovery Manager agents may view statistics
+resourceACLS: certServer.kra.certificate.transport:read:allow (read) user="anybody":Anybody is allowed to read transport certificate
+resourceACLS: certServer.kra.request.status:read:allow (read) group="Data Recovery Manager Agents":Only data recovery manager agents retrieve the remote key recovery approval status
+resourceACLS: certServer.kra.group:read,modify:allow (modify,read) group="Administrators":Only administrators are allowed to read and modify groups
+resourceACLS: certServer.kra.GenerateKeyPair:execute:allow (execute) group="Data Recovery Manager Agents":Only Data Recovery Manager Agents are allowed to execute requests
+resourceACLS: certServer.kra.TokenKeyRecovery:submit:allow (submit) group="Data Recovery Manager Agents":Only Data Recovery Manager Agents are allowed to submit requests
+resourceACLS: certServer.kra.registerUser:read,modify:allow (modify,read) group="Enterprise CA Administrators" || group="Enterprise KRA Administrators" || group="Enterprise OCSP Administrators" || group="Enterprise TKS Administrators" || group="Enterprise TPS Administrators":Only Enterprise Administrators are allowed to register a new agent
+resourceACLS: certServer.kra.getTransportCert:read:allow (read) group="Enterprise CA Administrators" || group="Enterprise KRA Administrators" || group="Enterprise OCSP Administrators" || group="Enterprise TKS Administrators" || group="Enterprise TPS Administrators":Only Enterprise Administrators are allowed to retrieve the transport cert
+resourceACLS: certServer.clone.configuration:read,modify:allow (modify,read) group="Enterprise CA Administrators" || group="Enterprise KRA Administrators" || group="Enterprise OCSP Administrators" || group="Enterprise TKS Administrators":Only Enterprise Administrators are allowed to clone the configuration.
+resourceACLS: certServer.kra.pki.key.retrieve:execute:allow (execute) group="Data Recovery Manager Agents":Data Recovery Manager Agents may retrieve archived key
+resourceACLS: certServer.kra.pki.keyrequests:read:allow (read) group="Data Recovery Manager Agents":Data Recovery Manager Agents may read keyrequests data
+resourceACLS: certServer.kra.pki.keyrequest:read:allow (read) group="Data Recovery Manager Agents":Data Recovery Manager Agents may read keyrequest data
+resourceACLS: certServer.kra.pki.keyrequest.archive:execute:allow (execute) group="Data Recovery Manager Agents":Data Recovery Manager Agents may issue archival request
+resourceACLS: certServer.kra.pki.keyrequest.recover:execute:allow (execute) group="Data Recovery Manager Agents":Data Recovery Manager Agents may issue recovery request
+resourceACLS: certServer.kra.pki.keyrequest.approve:execute:allow (execute) group="Data Recovery Manager Agents":Data Recovery Manager Agents may approve security data request
+resourceACLS: certServer.kra.pki.keyrequest.reject:execute:allow (execute) group="Data Recovery Manager Agents":Data Recovery Manager Agents may reject key security data request
+resourceACLS: certServer.kra.pki.keyrequest.cancel:execute:allow (execute) group="Data Recovery Manager Agents":Data Recovery Manager Agents may cancel security data request
+resourceACLS: certServer.kra.pki.keys:read:allow (read) group="Data Recovery Manager Agents":Data Recovery Manager Agents may read security data
+resourceACLS: certServer.kra.pki.config.cert.transport:read:allow (read) group="Data Recovery Manager Agents":Data Recovery Manager Agents may read transport cert data
diff --git a/base/kra/shared/conf/catalina.policy b/base/kra/shared/conf/catalina.policy
new file mode 100644
index 000000000..cf8302cd0
--- /dev/null
+++ b/base/kra/shared/conf/catalina.policy
@@ -0,0 +1,184 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// Copyright (C) 2006-2010 Red Hat, Inc.
+// All rights reserved.
+// Modifications: configuration parameters
+// --- END COPYRIGHT BLOCK ---
+
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// ============================================================================
+// catalina.corepolicy - Security Policy Permissions for Tomcat 6
+//
+// This file contains a default set of security policies to be enforced (by the
+// JVM) when Catalina is executed with the "-security" option. In addition
+// to the permissions granted here, the following additional permissions are
+// granted to the codebase specific to each web application:
+//
+// * Read access to the document root directory
+//
+// $Id$
+// ============================================================================
+
+
+// ========== SYSTEM CODE PERMISSIONS =========================================
+
+
+// These permissions apply to javac
+grant codeBase "file:${java.home}/lib/-" {
+ permission java.security.AllPermission;
+};
+
+// These permissions apply to all shared system extensions
+grant codeBase "file:${java.home}/jre/lib/ext/-" {
+ permission java.security.AllPermission;
+};
+
+// These permissions apply to javac when ${java.home] points at $JAVA_HOME/jre
+grant codeBase "file:${java.home}/../lib/-" {
+ permission java.security.AllPermission;
+};
+
+// These permissions apply to all shared system extensions when
+// ${java.home} points at $JAVA_HOME/jre
+grant codeBase "file:${java.home}/lib/ext/-" {
+ permission java.security.AllPermission;
+};
+
+
+// ========== CATALINA CODE PERMISSIONS =======================================
+
+
+// These permissions apply to the daemon code
+grant codeBase "file:${catalina.home}/bin/commons-daemon.jar" {
+ permission java.security.AllPermission;
+};
+
+// These permissions apply to the logging API
+grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" {
+ permission java.util.PropertyPermission "java.util.logging.config.class", "read";
+ permission java.util.PropertyPermission "java.util.logging.config.file", "read";
+ permission java.io.FilePermission "${java.home}${file.separator}lib${file.separator}logging.properties", "read";
+ permission java.lang.RuntimePermission "shutdownHooks";
+ permission java.io.FilePermission "${catalina.base}${file.separator}conf${file.separator}logging.properties", "read";
+ permission java.util.PropertyPermission "catalina.base", "read";
+ permission java.util.logging.LoggingPermission "control";
+ permission java.io.FilePermission "${catalina.base}${file.separator}logs", "read, write";
+ permission java.io.FilePermission "${catalina.base}${file.separator}logs${file.separator}*", "read, write";
+ permission java.lang.RuntimePermission "getClassLoader";
+ // To enable per context logging configuration, permit read access to the appropriate file.
+ // Be sure that the logging configuration is secure before enabling such access
+ // eg for the examples web application:
+ // permission java.io.FilePermission "${catalina.base}${file.separator}webapps${file.separator}examples${file.separator}WEB-INF${file.separator}classes${file.separator}logging.properties", "read";
+};
+
+// These permissions apply to the server startup code
+grant codeBase "file:${catalina.home}/bin/bootstrap.jar" {
+ permission java.security.AllPermission;
+};
+
+// These permissions apply to the servlet API classes
+// and those that are shared across all class loaders
+// located in the "lib" directory
+grant codeBase "file:${catalina.home}/lib/-" {
+ permission java.security.AllPermission;
+};
+
+
+// ========== WEB APPLICATION PERMISSIONS =====================================
+
+
+// These permissions are granted by default to all web applications
+// In addition, a web application will be given a read FilePermission
+// and JndiPermission for all files and directories in its document root.
+grant {
+ // Required for JNDI lookup of named JDBC DataSource's and
+ // javamail named MimePart DataSource used to send mail
+ permission java.util.PropertyPermission "java.home", "read";
+ permission java.util.PropertyPermission "java.naming.*", "read";
+ permission java.util.PropertyPermission "javax.sql.*", "read";
+
+ // OS Specific properties to allow read access
+ permission java.util.PropertyPermission "os.name", "read";
+ permission java.util.PropertyPermission "os.version", "read";
+ permission java.util.PropertyPermission "os.arch", "read";
+ permission java.util.PropertyPermission "file.separator", "read";
+ permission java.util.PropertyPermission "path.separator", "read";
+ permission java.util.PropertyPermission "line.separator", "read";
+
+ // JVM properties to allow read access
+ permission java.util.PropertyPermission "java.version", "read";
+ permission java.util.PropertyPermission "java.vendor", "read";
+ permission java.util.PropertyPermission "java.vendor.url", "read";
+ permission java.util.PropertyPermission "java.class.version", "read";
+ permission java.util.PropertyPermission "java.specification.version", "read";
+ permission java.util.PropertyPermission "java.specification.vendor", "read";
+ permission java.util.PropertyPermission "java.specification.name", "read";
+
+ permission java.util.PropertyPermission "java.vm.specification.version", "read";
+ permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
+ permission java.util.PropertyPermission "java.vm.specification.name", "read";
+ permission java.util.PropertyPermission "java.vm.version", "read";
+ permission java.util.PropertyPermission "java.vm.vendor", "read";
+ permission java.util.PropertyPermission "java.vm.name", "read";
+
+ // Required for OpenJMX
+ permission java.lang.RuntimePermission "getAttribute";
+
+ // Allow read of JAXP compliant XML parser debug
+ permission java.util.PropertyPermission "jaxp.debug", "read";
+
+ // Precompiled JSPs need access to this package.
+ permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime";
+ permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime.*";
+
+ // Precompiled JSPs need access to this system property.
+ permission java.util.PropertyPermission "org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "read";
+
+};
+
+
+// You can assign additional permissions to particular web applications by
+// adding additional "grant" entries here, based on the code base for that
+// application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files.
+//
+// Different permissions can be granted to JSP pages, classes loaded from
+// the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/
+// directory, or even to individual jar files in the /WEB-INF/lib/ directory.
+//
+// For instance, assume that the standard "examples" application
+// included a JDBC driver that needed to establish a network connection to the
+// corresponding database and used the scrape taglib to get the weather from
+// the NOAA web server. You might create a "grant" entries like this:
+//
+// The permissions granted to the context root directory apply to JSP pages.
+// grant codeBase "file:${catalina.home}/webapps/examples/-" {
+// permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
+// permission java.net.SocketPermission "*.noaa.gov:80", "connect";
+// };
+//
+// The permissions granted to the context WEB-INF/classes directory
+// grant codeBase "file:${catalina.home}/webapps/examples/WEB-INF/classes/-" {
+// };
+//
+// The permission granted to your JDBC driver
+// grant codeBase "jar:file:${catalina.home}/webapps/examples/WEB-INF/lib/driver.jar!/-" {
+// permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
+// };
+// The permission granted to the scrape taglib
+// grant codeBase "jar:file:${catalina.home}/webapps/examples/WEB-INF/lib/scrape.jar!/-" {
+// permission java.net.SocketPermission "*.noaa.gov:80", "connect";
+// };
+
diff --git a/base/kra/shared/conf/catalina.properties b/base/kra/shared/conf/catalina.properties
new file mode 100644
index 000000000..70cb7c05e
--- /dev/null
+++ b/base/kra/shared/conf/catalina.properties
@@ -0,0 +1,87 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2006-2010 Red Hat, Inc.
+# All rights reserved.
+# Modifications: configuration parameters
+# --- END COPYRIGHT BLOCK ---
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageAccess unless the
+# corresponding RuntimePermission ("accessClassInPackage."+package) has
+# been granted.
+package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans.
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageDefinition unless the
+# corresponding RuntimePermission ("defineClassInPackage."+package) has
+# been granted.
+#
+# by default, no packages are restricted for definition, and none of
+# the class loaders supplied with the JDK call checkPackageDefinition.
+#
+package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.
+
+#
+#
+# List of comma-separated paths defining the contents of the "common"
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
+# If left as blank,the JVM system loader will be used as Catalina's "common"
+# loader.
+# Examples:
+# "foo": Add this folder as a class repository
+# "foo/*.jar": Add all the JARs of the specified folder as class
+# repositories
+# "foo/bar.jar": Add bar.jar as a class repository
+common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar,[TOMCAT_INSTANCE_COMMON_LIB]
+
+#
+# List of comma-separated paths defining the contents of the "server"
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
+# If left as blank, the "common" loader will be used as Catalina's "server"
+# loader.
+# Examples:
+# "foo": Add this folder as a class repository
+# "foo/*.jar": Add all the JARs of the specified folder as class
+# repositories
+# "foo/bar.jar": Add bar.jar as a class repository
+server.loader=
+
+#
+# List of comma-separated paths defining the contents of the "shared"
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,
+# the "common" loader will be used as Catalina's "shared" loader.
+# Examples:
+# "foo": Add this folder as a class repository
+# "foo/*.jar": Add all the JARs of the specified folder as class
+# repositories
+# "foo/bar.jar": Add bar.jar as a class repository
+# Please note that for single jars, e.g. bar.jar, you need the URL form
+# starting with file:.
+shared.loader=
+
+#
+# String cache configuration.
+tomcat.util.buf.StringCache.byte.enabled=true
+#tomcat.util.buf.StringCache.char.enabled=true
+#tomcat.util.buf.StringCache.trainThreshold=500000
+#tomcat.util.buf.StringCache.cacheSize=5000
diff --git a/base/kra/shared/conf/context.xml b/base/kra/shared/conf/context.xml
new file mode 100644
index 000000000..8b6fe4905
--- /dev/null
+++ b/base/kra/shared/conf/context.xml
@@ -0,0 +1,40 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- BEGIN COPYRIGHT BLOCK
+ Copyright (C) 2006-2010 Red Hat, Inc.
+ All rights reserved.
+ Modifications: configuration parameters
+ END COPYRIGHT BLOCK -->
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- The contents of this file will be loaded for each web application -->
+<Context crossContext="true" allowLinking="true">
+
+ <!-- Default set of monitored resources -->
+ <WatchedResource>WEB-INF/web.xml</WatchedResource>
+
+ <!-- Uncomment this to disable session persistence across Tomcat restarts -->
+ <!--
+ <Manager pathname="" />
+ -->
+
+ <!-- Uncomment this to enable Comet connection tacking (provides events
+ on session expiration as well as webapp lifecycle) -->
+ <!--
+ <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
+ -->
+
+</Context>
diff --git a/base/kra/shared/conf/database.ldif b/base/kra/shared/conf/database.ldif
new file mode 100644
index 000000000..4dfdcea69
--- /dev/null
+++ b/base/kra/shared/conf/database.ldif
@@ -0,0 +1,4 @@
+dn: cn=config
+changetype: modify
+replace: nsslapd-maxbersize
+nsslapd-maxbersize: 209715200
diff --git a/base/kra/shared/conf/db.ldif b/base/kra/shared/conf/db.ldif
new file mode 100644
index 000000000..c07e9f1a6
--- /dev/null
+++ b/base/kra/shared/conf/db.ldif
@@ -0,0 +1,107 @@
+dn: ou=people,{rootSuffix}
+objectClass: top
+objectClass: organizationalUnit
+ou: people
+aci: (targetattr!="userPassword")(version 3.0; acl "Enable anonymous access"; allow (read, search, compare)userdn="ldap:///anyone";)
+
+dn: ou=groups,{rootSuffix}
+objectClass: top
+objectClass: organizationalUnit
+ou: groups
+
+dn: cn=Data Recovery Manager Agents,ou=groups,{rootSuffix}
+objectClass: top
+objectClass: groupOfUniqueNames
+cn: Data Recovery Manager Agents
+description: Agents for Data Recovery Manager
+
+dn: cn=Subsystem Group, ou=groups, {rootSuffix}
+objectClass: top
+objectClass: groupOfUniqueNames
+cn: Subsystem Group
+description: Subsystem Group
+
+dn: cn=Trusted Managers,ou=groups,{rootSuffix}
+objectClass: top
+objectClass: groupOfUniqueNames
+cn: Trusted Managers
+description: Managers trusted by this PKI instance
+
+dn: cn=Administrators,ou=groups,{rootSuffix}
+objectClass: top
+objectClass: groupOfUniqueNames
+cn: Administrators
+description: People who manage the Certificate System
+
+dn: cn=Auditors,ou=groups,{rootSuffix}
+objectClass: top
+objectClass: groupOfUniqueNames
+cn: Auditors
+description: People who can read the signed audits
+
+dn: cn=ClonedSubsystems,ou=groups,{rootSuffix}
+objectClass: top
+objectClass: groupOfUniqueNames
+cn: ClonedSubsystems
+description: People who can clone the master subsystem
+
+dn: ou=requests,{rootSuffix}
+objectClass: top
+objectClass: organizationalUnit
+ou: requests
+
+dn: cn=crossCerts,{rootSuffix}
+cn: crossCerts
+sn: crossCerts
+objectClass: top
+objectClass: person
+objectClass: pkiCA
+cACertificate;binary:
+authorityRevocationList;binary:
+certificateRevocationList;binary:
+crossCertificatePair;binary:
+
+dn: ou=kra, {rootSuffix}
+objectclass: top
+objectclass: organizationalUnit
+ou: kra
+
+dn: ou=keyRepository, ou=kra, {rootSuffix}
+objectclass: top
+objectclass: repository
+ou: keyRepository
+serialno: 010
+
+dn: ou=kra, ou=requests, {rootSuffix}
+objectclass: top
+objectclass: repository
+ou: kra
+serialno: 010
+
+dn: ou=replica,{rootSuffix}
+objectClass: top
+objectClass: repository
+ou: replica
+serialno: 010
+nextRange: 1000
+
+dn: ou=ranges,{rootSuffix}
+objectClass: top
+objectClass: organizationalUnit
+ou: ranges
+
+dn: ou=replica, ou=ranges,{rootSuffix}
+objectClass: top
+objectClass: organizationalUnit
+ou: replica
+
+dn: ou=requests, ou=ranges,{rootSuffix}
+objectClass: top
+objectClass: organizationalUnit
+ou: requests
+
+dn: ou=keyRepository, ou=ranges,{rootSuffix}
+objectClass: top
+objectClass: organizationalUnit
+ou: certificateRepository
+
diff --git a/base/kra/shared/conf/index.ldif b/base/kra/shared/conf/index.ldif
new file mode 100644
index 000000000..4bc8aebf9
--- /dev/null
+++ b/base/kra/shared/conf/index.ldif
@@ -0,0 +1,198 @@
+dn: cn=revokedby,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsSystemIndex: false
+cn: revokedby
+
+dn: cn=issuedby,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsSystemIndex: false
+cn: issuedby
+
+dn: cn=publicKeyData,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsSystemIndex: false
+cn: publicKeyData
+
+dn: cn=clientId,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsSystemIndex: false
+cn: clientId
+
+dn: cn=dataType,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsSystemIndex: false
+cn: dataType
+
+dn: cn=status,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsSystemIndex: false
+cn: status
+
+dn: cn=description,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: description
+
+dn: cn=serialno,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: serialno
+
+dn: cn=metaInfo,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: metaInfo
+
+dn: cn=certstatus,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: certstatus
+
+dn: cn=requestid,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: requestid
+
+dn: cn=requesttype,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: requesttype
+
+dn: cn=requeststate,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: requeststate
+
+dn: cn=requestowner,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: requestowner
+
+dn: cn=notbefore,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: notbefore
+
+dn: cn=notafter,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: notafter
+
+dn: cn=duration,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: duration
+
+dn: cn=dateOfCreate,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: dateOfCreate
+
+dn: cn=revokedOn,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: revokedOn
+
+dn: cn=archivedBy,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsSystemIndex: false
+cn: archivedBy
+
+dn: cn=ownername,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsIndexType: sub
+nsSystemIndex: false
+cn: ownername
+
+dn: cn=subjectname,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsIndexType: sub
+nsSystemIndex: false
+cn: subjectname
+
+dn: cn=requestsourceid,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsIndexType: sub
+nsSystemIndex: false
+cn: requestsourceid
+
+dn: cn=revInfo,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsIndexType: sub
+nsSystemIndex: false
+cn: revInfo
+
+dn: cn=extension,cn=index,cn={database},cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: nsIndex
+nsIndexType: eq
+nsIndexType: pres
+nsIndexType: sub
+nsSystemIndex: false
+cn: extension
diff --git a/base/kra/shared/conf/jk2.manifest b/base/kra/shared/conf/jk2.manifest
new file mode 100644
index 000000000..986d7b874
--- /dev/null
+++ b/base/kra/shared/conf/jk2.manifest
@@ -0,0 +1,2 @@
+Main-Class: org.apache.jk.apr.TomcatStarter
+Class-Path: ../lib/tomcat.jar log4j.jar log4j-core.jar ../lib/common/log4j.jar ../lib/common/log4j-core.jar ../lib/common/classes ../lib/common/commons-logging.jar bootstrap.jar ../server/lib/commons-logging.jar ../server/lib/jmx.jar jmx.jar commons-logging-api.jar
diff --git a/base/kra/shared/conf/jk2.properties b/base/kra/shared/conf/jk2.properties
new file mode 100644
index 000000000..093bae802
--- /dev/null
+++ b/base/kra/shared/conf/jk2.properties
@@ -0,0 +1,26 @@
+## THIS FILE MAY BE OVERRIDEN AT RUNTIME. MAKE SURE TOMCAT IS STOPED
+## WHEN YOU EDIT THE FILE.
+
+## COMMENTS WILL BE _LOST_
+
+## DOCUMENTATION OF THE FORMAT IN JkMain javadoc.
+
+# Set the desired handler list
+# handler.list=apr,request,channelJni
+#
+# Override the default port for the socketChannel
+# channelSocket.port=8019
+# Default:
+# channelUnix.file=${jkHome}/work/jk2.socket
+# Just to check if the the config is working
+# shm.file=${jkHome}/work/jk2.shm
+
+# In order to enable jni use any channelJni directive
+# channelJni.disabled = 0
+# And one of the following directives:
+
+# apr.jniModeSo=/opt/apache2/modules/mod_jk2.so
+
+# If set to inprocess the mod_jk2 will Register natives itself
+# This will enable the starting of the Tomcat from mod_jk2
+# apr.jniModeSo=inprocess
diff --git a/base/kra/shared/conf/jkconf.ant.xml b/base/kra/shared/conf/jkconf.ant.xml
new file mode 100644
index 000000000..245cf98e2
--- /dev/null
+++ b/base/kra/shared/conf/jkconf.ant.xml
@@ -0,0 +1,51 @@
+<project name="jkconf" default="main" basedir=".">
+
+ <target name="init-3x" if="33.detect">
+ <taskdef name="jkconf"
+ classname="org.apache.jk.config.WebXml2Jk" >
+ <classpath>
+ <!-- 3.3 support -->
+ <pathelement location="/ws/jtc/jk/build/classes" />
+ <pathelement location="${tomcat.home}/lib/container/tomcat-jk2.jar" />
+ <pathelement location="${tomcat.home}/lib/container/crimson.jar"/>
+ <pathelement location="${tomcat.home}/lib/common/commons-logging.jar"/>
+ </classpath>
+ </taskdef>
+ </target>
+
+ <target name="init-4x" if="4x.detect" >
+ <path id="main.classpath">
+ <!-- 3.3 support -->
+ <fileset dir="${tomcat.home}/lib" includes="*.jar" />
+ <fileset dir="${tomcat.home}/server/lib" includes="*.jar" />
+ <fileset dir="${tomcat.home}/common/lib" includes="*.jar" />
+ </path>
+
+ <taskdef name="jkconf" classpathref="main.classpath"
+ classname="org.apache.jk.config.WebXml2Jk" />
+ </target>
+
+ <target name="detect" >
+ <property file="build.properties"/>
+ <property file="${user.home}/build.properties"/>
+ <property file="${user.home}/.build.properties"/>
+
+ <!-- default locations, overrident by properties.
+ This file must be installed in conf/ -->
+ <property name="tomcat.home" location=".." />
+
+ <available property="33.detect" file="${tomcat.home}/lib/container" />
+ <available property="4x.detect" file="${tomcat.home}/server/lib" />
+ </target>
+
+ <target name="init" depends="detect,init-3x,init-4x" />
+
+ <!-- ==================== Detection and reports ==================== -->
+
+
+ <target name="main" depends="init">
+ <jkconf docBase="${tomcat.home}/webapps/examples"
+ context="/examples" />
+ </target>
+
+</project>
diff --git a/base/kra/shared/conf/jkconfig.manifest b/base/kra/shared/conf/jkconfig.manifest
new file mode 100644
index 000000000..3ba1f2e3e
--- /dev/null
+++ b/base/kra/shared/conf/jkconfig.manifest
@@ -0,0 +1,2 @@
+Main-Class: org.apache.jk.config.WebXml2Jk
+Class-Path: tomcat-jk2.jar commons-logging.jar crimson.jar xercesImpl.jar xmlApis.jar tomcat-util.jar log4j.jar log4j-core.jar
diff --git a/base/kra/shared/conf/logging.properties b/base/kra/shared/conf/logging.properties
new file mode 100644
index 000000000..796cfc071
--- /dev/null
+++ b/base/kra/shared/conf/logging.properties
@@ -0,0 +1,70 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2006-2010 Red Hat, Inc.
+# All rights reserved.
+# Modifications: configuration parameters
+# --- END COPYRIGHT BLOCK ---
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, 3manager.org.apache.juli.FileHandler, 4host-manager.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
+
+.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
+
+1catalina.org.apache.juli.FileHandler.level = FINE
+1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+1catalina.org.apache.juli.FileHandler.prefix = catalina.
+
+2localhost.org.apache.juli.FileHandler.level = FINE
+2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+2localhost.org.apache.juli.FileHandler.prefix = localhost.
+
+3manager.org.apache.juli.FileHandler.level = FINE
+3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+3manager.org.apache.juli.FileHandler.prefix = manager.
+
+4host-manager.org.apache.juli.FileHandler.level = FINE
+4host-manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+4host-manager.org.apache.juli.FileHandler.prefix = host-manager.
+
+java.util.logging.ConsoleHandler.level = FINE
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+
+############################################################
+# Facility specific properties.
+# Provides extra control for each logger.
+############################################################
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.FileHandler
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.FileHandler
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.FileHandler
+
+# For example, set the com.xyz.foo logger to only log SEVERE
+# messages:
+#org.apache.catalina.startup.ContextConfig.level = FINE
+#org.apache.catalina.startup.HostConfig.level = FINE
+#org.apache.catalina.session.ManagerBase.level = FINE
+#org.apache.catalina.core.AprLifecycleListener.level=FINE
diff --git a/base/kra/shared/conf/manager.ldif b/base/kra/shared/conf/manager.ldif
new file mode 100644
index 000000000..52e486987
--- /dev/null
+++ b/base/kra/shared/conf/manager.ldif
@@ -0,0 +1,48 @@
+# acis for cert manager
+
+dn: ou=csusers,cn=config
+objectClass: top
+objectClass: organizationalUnit
+ou: csusers
+
+dn: {rootSuffix}
+changetype: modify
+add: aci
+aci: (targetattr=*)(version 3.0; acl "cert manager access"; allow (all) userdn = "ldap:///{dbuser}";)
+
+dn: cn=ldbm database,cn=plugins,cn=config
+changetype: modify
+add: aci
+aci: (targetattr=*)(version 3.0; acl "Cert Manager access for VLV searches"; allow (read) userdn="ldap:///{dbuser}";)
+
+dn: cn=config
+changetype: modify
+add: aci
+aci: (targetattr != aci)(version 3.0; aci "cert manager read access"; allow (read, search, compare) userdn = "ldap:///{dbuser}";)
+
+dn: ou=csusers,cn=config
+changetype: modify
+add: aci
+aci: (targetattr != aci)(version 3.0; aci "cert manager manage replication users"; allow (all) userdn = "ldap:///{dbuser}";)
+
+dn: cn="{rootSuffix}",cn=mapping tree,cn=config
+changetype: modify
+add: aci
+aci: (targetattr=*)(version 3.0;acl "cert manager: Add Replication Agreements";allow (add) userdn = "ldap:///{dbuser}";)
+
+dn: cn="{rootSuffix}",cn=mapping tree,cn=config
+changetype: modify
+add: aci
+aci: (targetattr=*)(targetfilter="(|(objectclass=nsds5Replica)(objectclass=nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement)(objectClass=nsMappingTree))")(version 3.0; acl "cert manager: Modify Replication Agreements"; allow (read, write, search) userdn = "ldap:///{dbuser}";)
+
+dn: cn="{rootSuffix}",cn=mapping tree,cn=config
+changetype: modify
+add: aci
+aci: (targetattr=*)(targetfilter="(|(objectclass=nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement))")(version 3.0;acl "cert manager: Remove Replication Agreements";allow (delete) userdn = "ldap:///{dbuser}";)
+
+dn: cn=tasks,cn=config
+changetype: modify
+add: aci
+aci: (targetattr=*)(version 3.0; acl "cert manager: Run tasks after replica re-initialization"; allow (add) userdn = "ldap:///{dbuser}";)
+
+
diff --git a/base/kra/shared/conf/schema.ldif b/base/kra/shared/conf/schema.ldif
new file mode 100644
index 000000000..70578e21c
--- /dev/null
+++ b/base/kra/shared/conf/schema.ldif
@@ -0,0 +1,489 @@
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( usertype-oid NAME 'usertype' DESC 'Distinguish whether the user is administrator, agent or subsystem.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( userstate-oid NAME 'userstate' DESC 'Distinguish whether the user is administrator, agent or subsystem.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( cmsuser-oid NAME 'cmsuser' DESC 'CMS User' SUP top STRUCTURAL MUST usertype MAY userstate X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( archivedBy-oid NAME 'archivedBy' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( adminMessages-oid NAME 'adminMessages' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( algorithm-oid NAME 'algorithm' DESC 'CMS defined attribute'SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( algorithmId-oid NAME 'algorithmId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( signingAlgorithmId-oid NAME 'signingAlgorithmId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( autoRenew-oid NAME 'autoRenew' DESC 'CMS defined attribute'SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( certStatus-oid NAME 'certStatus' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( crlName-oid NAME 'crlName' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( crlSize-oid NAME 'crlSize' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( deltaSize-oid NAME 'deltaSize' DESC 'CMS defined attribute'SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( crlNumber-oid NAME 'crlNumber' DESC 'CMS defined attribute'SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( deltaNumber-oid NAME 'deltaNumber' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( firstUnsaved-oid NAME 'firstUnsaved' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( crlCache-oid NAME 'crlCache' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( revokedCerts-oid NAME 'revokedCerts' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( unrevokedCerts-oid NAME 'unrevokedCerts' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( expiredCerts-oid NAME 'expiredCerts' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( crlExtensions-oid NAME 'crlExtensions' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dateOfArchival-oid NAME 'dateOfArchival' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dateOfRecovery-oid NAME 'dateOfRecovery' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dateOfRevocation-oid NAME 'dateOfRevocation' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dateOfCreate-oid NAME 'dateOfCreate' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dateOfModify-oid NAME 'dateOfModify' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( duration-oid NAME 'duration' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( extension-oid NAME 'extension' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( issuedBy-oid NAME 'issuedBy' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( issueInfo-oid NAME 'issueInfo' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( issuerName-oid NAME 'issuerName' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( keySize-oid NAME 'keySize' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( clientId-oid NAME 'clientId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dataType-oid NAME 'dataType' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( status-oid NAME 'status' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( keyState-oid NAME 'keyState' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( metaInfo-oid NAME 'metaInfo' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( nextUpdate-oid NAME 'nextUpdate' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( notAfter-oid NAME 'notAfter' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( notBefore-oid NAME 'notBefore' DESC 'CMS defined attribute'SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( ownerName-oid NAME 'ownerName' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( password-oid NAME 'password' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( p12Expiration-oid NAME 'p12Expiration' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( proofOfArchival-oid NAME 'proofOfArchival' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( publicKeyData-oid NAME 'publicKeyData' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( publicKeyFormat-oid NAME 'publicKeyFormat' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( privateKeyData-oid NAME 'privateKeyData' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestId-oid NAME 'requestId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestInfo-oid NAME 'requestInfo' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestState-oid NAME 'requestState' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestResult-oid NAME 'requestResult' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestOwner-oid NAME 'requestOwner' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestAgentGroup-oid NAME 'requestAgentGroup' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestSourceId-oid NAME 'requestSourceId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestType-oid NAME 'requestType' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestFlag-oid NAME 'requestFlag' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( requestError-oid NAME 'requestError' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( resourceACLS-oid NAME 'resourceACLS' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( revInfo-oid NAME 'revInfo' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( revokedBy-oid NAME 'revokedBy' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( revokedOn-oid NAME 'revokedOn' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( serialno-oid NAME 'serialno' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( nextRange-oid NAME 'nextRange' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( publishingStatus-oid NAME 'publishingStatus' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( beginRange-oid NAME 'beginRange' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( endRange-oid NAME 'endRange' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( subjectName-oid NAME 'subjectName' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( sessionContext-oid NAME 'sessionContext' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( thisUpdate-oid NAME 'thisUpdate' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( transId-oid NAME 'transId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( transStatus-oid NAME 'transStatus' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( transName-oid NAME 'transName' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( transOps-oid NAME 'transOps' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( userDN-oid NAME 'userDN' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( userMessages-oid NAME 'userMessages' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( version-oid NAME 'version' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( Clone-oid NAME 'Clone' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( DomainManager-oid NAME 'DomainManager' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( SecurePort-oid NAME 'SecurePort' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( SecureAgentPort-oid NAME 'SecureAgentPort' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( SecureAdminPort-oid NAME 'SecureAdminPort' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( SecureEEClientAuthPort-oid NAME 'SecureEEClientAuthPort' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( UnSecurePort-oid NAME 'UnSecurePort' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( SubsystemName-oid NAME 'SubsystemName' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( cmsUserGroup-oid NAME 'cmsUserGroup' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( CertACLS-oid NAME 'CertACLS' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY resourceACLS X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( repository-oid NAME 'repository' DESC 'CMS defined class' SUP top STRUCTURAL MUST ou MAY ( serialno $ description $ nextRange $ publishingStatus ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( request-oid NAME 'request' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( requestId $ dateOfCreate $ dateOfModify $ requestState $ requestResult $ requestOwner $ requestAgentGroup $ requestSourceId $ requestType $ requestFlag $ requestError $ userMessages $ adminMessages ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( transaction-oid NAME 'transaction' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( transId $ description $ transName $ transStatus $ transOps ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( crlIssuingPointRecord-oid NAME 'crlIssuingPointRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( dateOfCreate $ dateOfModify $ crlNumber $ crlSize $ thisUpdate $ nextUpdate $ deltaNumber $ deltaSize $ firstUnsaved $ certificateRevocationList $ deltaRevocationList $ crlCache $ revokedCerts $ unrevokedCerts $ expiredCerts $ cACertificate ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( certificateRecord-oid NAME 'certificateRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ certStatus $ autoRenew $ issueInfo $ metaInfo $ revInfo $ version $ duration $ notAfter $ notBefore $ algorithmId $ subjectName $ signingAlgorithmId $ userCertificate $ issuedBy $ revokedBy $ revokedOn $ extension $ publicKeyData $ issuerName ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( userDetails-oid NAME 'userDetails' DESC 'CMS defined class' SUP top STRUCTURAL MUST userDN MAY ( dateOfCreate $ dateOfModify $ password $ p12Expiration ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( keyRecord-oid NAME 'keyRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ keyState $ privateKeyData $ ownerName $ keySize $ metaInfo $ dateOfArchival $ dateOfRecovery $ algorithm $ publicKeyFormat $ publicKeyData $ archivedBy $ clientId $ dataType $ status ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( pkiSecurityDomain-oid NAME 'pkiSecurityDomain' DESC 'CMS defined class' SUP top STRUCTURAL MUST ( ou $ name ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( pkiSecurityGroup-oid NAME 'pkiSecurityGroup' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( pkiSubsystem-oid NAME 'pkiSubsystem' DESC 'CMS defined class' SUP top STRUCTURAL MUST ( cn $ Host $ SecurePort $ SubsystemName $ Clone ) MAY ( DomainManager $ SecureAgentPort $ SecureAdminPort $SecureEEClientAuthPort $ UnSecurePort ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( pkiRange-oid NAME 'pkiRange' DESC 'CMS defined class' SUP top STRUCTURAL MUST ( cn $ beginRange $ endRange $ Host $ SecurePort ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( securityDomainSessionEntry-oid NAME 'securityDomainSessionEntry' DESC 'CMS defined class' SUP top STRUCTURAL MUST ( cn $ host $ uid $ cmsUserGroup $ dateOfCreate ) X-ORIGIN 'user defined' )
diff --git a/base/kra/shared/conf/server-minimal.xml b/base/kra/shared/conf/server-minimal.xml
new file mode 100644
index 000000000..7b542b6cf
--- /dev/null
+++ b/base/kra/shared/conf/server-minimal.xml
@@ -0,0 +1,25 @@
+<Server port="8005" shutdown="SHUTDOWN">
+
+ <GlobalNamingResources>
+ <!-- Used by Manager webapp -->
+ <Resource name="UserDatabase" auth="Container"
+ type="org.apache.catalina.UserDatabase"
+ description="User database that can be updated and saved"
+ factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+ pathname="conf/tomcat-users.xml" />
+ </GlobalNamingResources>
+
+ <Service name="Catalina">
+ <Connector port="8080" />
+
+ <!-- This is here for compatibility only, not required -->
+ <Connector port="8009" protocol="AJP/1.3" />
+
+ <Engine name="Catalina" defaultHost="localhost">
+ <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+ resourceName="UserDatabase" />
+ <Host name="localhost" appBase="webapps" />
+ </Engine>
+
+ </Service>
+</Server>
diff --git a/base/kra/shared/conf/server.xml b/base/kra/shared/conf/server.xml
new file mode 100644
index 000000000..58121d448
--- /dev/null
+++ b/base/kra/shared/conf/server.xml
@@ -0,0 +1,308 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- BEGIN COPYRIGHT BLOCK
+ Copyright (C) 2006-2010 Red Hat, Inc.
+ All rights reserved.
+ Modifications: configuration parameters
+ END COPYRIGHT BLOCK -->
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Note: A "Server" is not itself a "Container", so you may not
+ define subcomponents such as "Valves" at this level.
+ Documentation at /docs/config/server.html
+ -->
+
+<!-- DO NOT REMOVE - Begin PKI Status Definitions -->
+<!--
+Unsecure Port = http://[PKI_MACHINE_NAME]:[PKI_UNSECURE_PORT]/[PKI_SUBSYSTEM_TYPE]/ee/[PKI_SUBSYSTEM_TYPE]
+Secure Agent Port = https://[PKI_MACHINE_NAME]:[PKI_AGENT_SECURE_PORT]/[PKI_SUBSYSTEM_TYPE]/agent/[PKI_SUBSYSTEM_TYPE]
+Secure EE Port = https://[PKI_MACHINE_NAME]:[PKI_EE_SECURE_PORT]/[PKI_SUBSYSTEM_TYPE]/ee/[PKI_SUBSYSTEM_TYPE]
+Secure Admin Port = https://[PKI_MACHINE_NAME]:[PKI_ADMIN_SECURE_PORT]/[PKI_SUBSYSTEM_TYPE]/services
+PKI Console Port = pkiconsole https://[PKI_MACHINE_NAME]:[PKI_ADMIN_SECURE_PORT]/[PKI_SUBSYSTEM_TYPE]
+Tomcat Port = [TOMCAT_SERVER_PORT] (for shutdown)
+-->
+<!-- DO NOT REMOVE - End PKI Status Definitions -->
+
+<Server port="[TOMCAT_SERVER_PORT]" shutdown="SHUTDOWN">
+
+ <!--APR library loader. Documentation at /docs/apr.html -->
+ <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
+ <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
+ <Listener className="org.apache.catalina.core.JasperListener" />
+ <!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->
+ <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
+ <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+
+ <!-- Global JNDI resources
+ Documentation at /docs/jndi-resources-howto.html
+ -->
+ <GlobalNamingResources>
+ <!-- Editable user database that can also be used by
+ UserDatabaseRealm to authenticate users
+ -->
+ <Resource name="UserDatabase" auth="Container"
+ type="org.apache.catalina.UserDatabase"
+ description="User database that can be updated and saved"
+ factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+ pathname="conf/tomcat-users.xml" />
+ </GlobalNamingResources>
+
+ <!-- A "Service" is a collection of one or more "Connectors" that share
+ a single "Container" Note: A "Service" is not itself a "Container",
+ so you may not define subcomponents such as "Valves" at this level.
+ Documentation at /docs/config/service.html
+ -->
+ <Service name="Catalina">
+
+ <!--The connectors can use a shared executor, you can define one or more named thread pools-->
+ <!--
+ <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
+ maxThreads="150" minSpareThreads="4"/>
+ -->
+
+
+ <!-- A "Connector" represents an endpoint by which requests are received
+ and responses are returned. Documentation at :
+ Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
+ Java AJP Connector: /docs/config/ajp.html
+ APR (HTTP/AJP) Connector: /docs/apr.html
+ Define a non-SSL HTTP/1.1 Connector on port 8080
+ -->
+
+ [PKI_UNSECURE_PORT_SERVER_COMMENT]
+ <Connector name="[PKI_UNSECURE_PORT_CONNECTOR_NAME]" port="[PKI_UNSECURE_PORT]" protocol="HTTP/1.1" redirectPort="8443"
+ maxHttpHeaderSize="8192"
+ acceptCount="100" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+ enableLookups="false" connectionTimeout="20000" disableUploadTimeout="true"
+ />
+
+ <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
+ [PKI_SECURE_PORT_SERVER_COMMENT]
+ <!-- DO NOT REMOVE - Begin define PKI secure port
+ NOTE: The OCSP settings take effect globally, so it should only be set once.
+
+ In setup where SSL clientAuth="true", OCSP can be turned on by
+ setting enableOCSP to true like the following:
+ enableOCSP="true"
+ along with changes to related settings, especially:
+ ocspResponderURL=<see example in connector definition below>
+ ocspResponderCertNickname=<see example in connector definition below>
+ Here are the definition to all the OCSP-related settings:
+ enableOCSP - turns on/off the ocsp check
+ ocspResponderURL - sets the url where the ocsp requests are sent
+ ocspResponderCertNickname - sets the nickname of the cert that is
+ either CA's signing certificate or the OCSP server's signing
+ certificate.
+ The CA's signing certificate should already be in the db, in
+ case of the same security domain.
+ In case of an ocsp signing certificate, one must import the cert
+ into the subsystem's nss db and set trust. e.g.:
+ certutil -d . -A -n "ocspSigningCert cert-pki-ca" -t "C,," -a -i ocspCert.b64
+ ocspCacheSize - sets max cache entries
+ ocspMinCacheEntryDuration - sets minimum seconds to next fetch attempt
+ ocspMaxCacheEntryDuration - sets maximum seconds to next fetch attempt
+ ocspTimeout -sets OCSP timeout in seconds
+ -->
+ <Connector name="[PKI_SECURE_PORT_CONNECTOR_NAME]" port="[PKI_SECURE_PORT]" protocol="HTTP/1.1" SSLEnabled="true" sslProtocol="SSL" scheme="https" secure="true"
+ maxHttpHeaderSize="8192"
+ acceptCount="100" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+ enableLookups="false" disableUploadTimeout="true"
+ SSLImplementation="org.apache.tomcat.util.net.jss.JSSImplementation"
+ enableOCSP="false"
+ ocspResponderURL="http://[PKI_MACHINE_NAME]:9080/ca/ocsp"
+ ocspResponderCertNickname="ocspSigningCert cert-pki-ca"
+ ocspCacheSize="1000"
+ ocspMinCacheEntryDuration="60"
+ ocspMaxCacheEntryDuration="120"
+ ocspTimeout="10"
+ strictCiphers="false"
+ clientAuth="[PKI_AGENT_CLIENTAUTH]"
+ sslOptions="[TOMCAT_SSL_OPTIONS]"
+ ssl2Ciphers="[TOMCAT_SSL2_CIPHERS]"
+ ssl3Ciphers="[TOMCAT_SSL3_CIPHERS]"
+ tlsCiphers="[TOMCAT_TLS_CIPHERS]"
+ serverCertNickFile="[PKI_INSTANCE_PATH]/conf/serverCertNick.conf"
+ passwordFile="[PKI_INSTANCE_PATH]/conf/password.conf"
+ passwordClass="org.apache.tomcat.util.net.jss.PlainPasswordFile"
+ certdbDir="[PKI_INSTANCE_PATH]/alias"
+ />
+ <!-- DO NOT REMOVE - End define PKI secure port -->
+
+ [PKI_OPEN_SEPARATE_PORTS_SERVER_COMMENT][PKI_ADMIN_SECURE_PORT_SERVER_COMMENT]
+ <Connector name="[PKI_ADMIN_SECURE_PORT_CONNECTOR_NAME]" port="[PKI_ADMIN_SECURE_PORT]" SSLEnabled="true" sslProtocol="SSL" scheme="https" secure="true"
+ maxHttpHeaderSize="8192"
+ acceptCount="100" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+ enableLookups="false" disableUploadTimeout="true"
+ SSLImplementation="org.apache.tomcat.util.net.jss.JSSImplementation"
+ strictCiphers="false"
+ clientAuth="false"
+ sslOptions="[TOMCAT_SSL_OPTIONS]"
+ ssl2Ciphers="[TOMCAT_SSL2_CIPHERS]"
+ ssl3Ciphers="[TOMCAT_SSL3_CIPHERS]"
+ tlsCiphers="[TOMCAT_TLS_CIPHERS]"
+ serverCertNickFile="[PKI_INSTANCE_PATH]/conf/serverCertNick.conf"
+ passwordFile="[PKI_INSTANCE_PATH]/conf/password.conf"
+ passwordClass="org.apache.tomcat.util.net.jss.PlainPasswordFile"
+ certdbDir="[PKI_INSTANCE_PATH]/alias"/>
+ [PKI_CLOSE_SEPARATE_PORTS_SERVER_COMMENT]
+
+ [PKI_OPEN_SEPARATE_PORTS_SERVER_COMMENT][PKI_EE_SECURE_PORT_SERVER_COMMENT]
+ <Connector name="[PKI_EE_SECURE_PORT_CONNECTOR_NAME]" port="[PKI_EE_SECURE_PORT]" SSLEnabled="true" sslProtocol="SSL" scheme="https" secure="true"
+ maxHttpHeaderSize="8192"
+ acceptCount="100" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+ enableLookups="false" disableUploadTimeout="true"
+ SSLImplementation="org.apache.tomcat.util.net.jss.JSSImplementation"
+ strictCiphers="false"
+ clientAuth="false"
+ sslOptions="[TOMCAT_SSL_OPTIONS]"
+ ssl2Ciphers="[TOMCAT_SSL2_CIPHERS]"
+ ssl3Ciphers="[TOMCAT_SSL3_CIPHERS]"
+ tlsCiphers="[TOMCAT_TLS_CIPHERS]"
+ serverCertNickFile="[PKI_INSTANCE_PATH]/conf/serverCertNick.conf"
+ passwordFile="[PKI_INSTANCE_PATH]/conf/password.conf"
+ passwordClass="org.apache.tomcat.util.net.jss.PlainPasswordFile"
+ certdbDir="[PKI_INSTANCE_PATH]/alias"/>
+ [PKI_CLOSE_SEPARATE_PORTS_SERVER_COMMENT]
+
+ <!-- A "Connector" using the shared thread pool-->
+ <!--
+ <Connector executor="tomcatThreadPool"
+ port="8080" protocol="HTTP/1.1"
+ connectionTimeout="20000"
+ redirectPort="8443" />
+ -->
+ <!-- Define a SSL HTTP/1.1 Connector on port 8443
+ This connector uses the JSSE configuration, when using APR, the
+ connector should be using the OpenSSL style configuration
+ described in the APR documentation -->
+ <!--
+ <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
+ maxThreads="150" scheme="https" secure="true"
+ clientAuth="false" sslProtocol="TLS" />
+ -->
+
+ <!-- Define an AJP 1.3 Connector on port [PKI_AJP_PORT] -->
+[PKI_OPEN_AJP_PORT_COMMENT]
+ <Connector port="[PKI_AJP_PORT]" protocol="AJP/1.3" redirectPort="PKI_AJP_REDIRECT_PORT]" />
+[PKI_CLOSE_AJP_PORT_COMMENT]
+
+
+ <!-- An Engine represents the entry point (within Catalina) that processes
+ every request. The Engine implementation for Tomcat stand alone
+ analyzes the HTTP headers included with the request, and passes them
+ on to the appropriate Host (virtual host).
+ Documentation at /docs/config/engine.html -->
+
+ <!-- You should set jvmRoute to support load-balancing via AJP ie :
+ <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
+ -->
+ <Engine name="Catalina" defaultHost="localhost">
+
+ <!--For clustering, please take a look at documentation at:
+ /docs/cluster-howto.html (simple how to)
+ /docs/config/cluster.html (reference documentation) -->
+ <!--
+ <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
+ -->
+
+ <!-- The request dumper valve dumps useful debugging information about
+ the request and response data received and sent by Tomcat.
+ Documentation at: /docs/config/valve.html -->
+ <!--
+ <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
+ -->
+
+ <!-- This Realm uses the UserDatabase configured in the global JNDI
+ resources under the key "UserDatabase". Any edits
+ that are performed against this UserDatabase are immediately
+ available for use by the Realm. -->
+
+ <!--
+ <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+ resourceName="UserDatabase"/>
+ -->
+
+ <!-- Custom PKIJNDI realm
+
+ Example:
+
+ <Realm className="com.netscape.cmscore.realm.PKIJNDIRealm" : classpath to realm
+ connectionURL="ldap://localhost:389" : standard JNDI connection URL
+ userBase="ou=people,dc=localhost-pki-kra" : standard JNDI userBase property
+ userSearch="(description={0})" : Attribute to search for user of incoming client auth certificate
+ : Use userSearch="(UID={0})" if wanting to search isolate user based on UID
+ : Also set the following: certUIDLabel="UID" or whatever the field containing
+ : the user's UID happens to be. This will cause the incoming's cert dn to be
+ : be searched for <certUIDLabel>=<uid value>
+
+ certAttrName="userCertificate" : Attribute containing user's client auth certificate
+ roleBase="ou=groups,dc=localhost-pki-kra" : Standard JNDI search base for roles or groups
+ roleName="cn" : Standard attribute name containg roles or groups
+ roleSubtree="true" : Standard JNDI roleSubtree property
+ roleSearch="(uniqueMember={0})" : How to search for a user in a specific role or group
+ connectionName="cn=Directory Manager" : Connection name, needs elevated privileges
+ connectionPassword="secret123" : Password for elevated user
+ aclBase ="cn=aclResources,dc=localhost-pki-kra" : Custom base location of PKI ACL's in directory
+ aclAttrName="resourceACLS" : Name of attribute containing PKI ACL's
+ />
+
+ Uncomment and customize below to activate Realm.
+ Also umcomment Security Constraints and login config values
+ in WEB-INF/web.xml as well.
+ -->
+
+ <!--
+ <Realm className="com.netscape.cmscore.realm.PKIJNDIRealm"
+ connectionURL="ldap://localhost:389"
+ userBase="ou=people,dc=localhost-pki-kra"
+ userSearch="(description={0})"
+ certAttrName="userCertificate"
+ roleBase="ou=groups,dc=localhost-pki-kra"
+ roleName="cn"
+ roleSubtree="true"
+ roleSearch="(uniqueMember={0})"
+ connectionName="cn=Directory Manager"
+ connectionPassword="netscape"
+ aclBase ="cn=aclResources,dc=localhost-pki-kra"
+ aclAttrName="resourceACLS"
+ />
+
+ -->
+
+ <!-- Define the default virtual host
+ Note: XML Schema validation will not work with Xerces 2.2.
+ -->
+ <Host name="localhost" appBase="webapps"
+ unpackWARs="true" autoDeploy="false"
+ xmlValidation="false" xmlNamespaceAware="false">
+
+ <!-- SingleSignOn valve, share authentication between web applications
+ Documentation at: /docs/config/valve.html -->
+ <!--
+ <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
+ -->
+
+ <!-- Access log processes all example.
+ Documentation at: /docs/config/valve.html -->
+ <!--
+ <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
+ prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
+ -->
+
+ </Host>
+ </Engine>
+ </Service>
+</Server>
diff --git a/base/kra/shared/conf/serverCert.profile b/base/kra/shared/conf/serverCert.profile
new file mode 100644
index 000000000..adf6ee4ad
--- /dev/null
+++ b/base/kra/shared/conf/serverCert.profile
@@ -0,0 +1,37 @@
+#
+# Server Certificate
+#
+id=serverCert.profile
+name=All Purpose SSL server cert Profile
+description=This profile creates an SSL server certificate that is valid for SSL servers
+list=2,4,5,6,7
+2.default.class=com.netscape.cms.profile.def.ValidityDefault
+2.default.name=Validity Default
+2.default.params.range=720
+2.default.params.startTime=0
+4.default.class=com.netscape.cms.profile.def.AuthorityKeyIdentifierExtDefault
+4.default.name=Authority Key Identifier Default
+5.default.class=com.netscape.cms.profile.def.AuthInfoAccessExtDefault
+5.default.name=AIA Extension Default
+5.default.params.authInfoAccessADEnable_0=true
+5.default.params.authInfoAccessADLocationType_0=URIName
+5.default.params.authInfoAccessADLocation_0=
+5.default.params.authInfoAccessADMethod_0=1.3.6.1.5.5.7.48.1
+5.default.params.authInfoAccessCritical=false
+5.default.params.authInfoAccessNumADs=1
+6.default.class=com.netscape.cms.profile.def.KeyUsageExtDefault
+6.default.name=Key Usage Default
+6.default.params.keyUsageCritical=true
+6.default.params.keyUsageDigitalSignature=true
+6.default.params.keyUsageNonRepudiation=true
+6.default.params.keyUsageDataEncipherment=true
+6.default.params.keyUsageKeyEncipherment=true
+6.default.params.keyUsageKeyAgreement=false
+6.default.params.keyUsageKeyCertSign=false
+6.default.params.keyUsageCrlSign=false
+6.default.params.keyUsageEncipherOnly=false
+6.default.params.keyUsageDecipherOnly=false
+7.default.class=com.netscape.cms.profile.def.ExtendedKeyUsageExtDefault
+7.default.name=Extended Key Usage Extension Default
+7.default.params.exKeyUsageCritical=false
+7.default.params.exKeyUsageOIDs=1.3.6.1.5.5.7.3.1
diff --git a/base/kra/shared/conf/serverCertNick.conf b/base/kra/shared/conf/serverCertNick.conf
new file mode 100644
index 000000000..1b1f4fcad
--- /dev/null
+++ b/base/kra/shared/conf/serverCertNick.conf
@@ -0,0 +1 @@
+Server-Cert cert-[PKI_INSTANCE_ID]
diff --git a/base/kra/shared/conf/shm.manifest b/base/kra/shared/conf/shm.manifest
new file mode 100644
index 000000000..0505c085b
--- /dev/null
+++ b/base/kra/shared/conf/shm.manifest
@@ -0,0 +1,2 @@
+Main-Class: org.apache.jk.common.Shm
+Class-Path: tomcat-jk2.jar commons-logging.jar tomcat-util.jar log4j.jar log4j-core.jar
diff --git a/base/kra/shared/conf/storageCert.profile b/base/kra/shared/conf/storageCert.profile
new file mode 100644
index 000000000..fe46c19c1
--- /dev/null
+++ b/base/kra/shared/conf/storageCert.profile
@@ -0,0 +1,37 @@
+#
+# DRM Storage Certificate
+#
+id=storageCert.profile
+name=DRM Key Storage Cert profile
+description=This profile creates a certificate that is good for DRM to encrypt private key materials in storage
+list=2,4,5,6,7
+2.default.class=com.netscape.cms.profile.def.ValidityDefault
+2.default.name=Validity Default
+2.default.params.range=720
+2.default.params.startTime=0
+4.default.class=com.netscape.cms.profile.def.AuthorityKeyIdentifierExtDefault
+4.default.name=Authority Key Identifier Default
+5.default.class=com.netscape.cms.profile.def.AuthInfoAccessExtDefault
+5.default.name=AIA Extension Default
+5.default.params.authInfoAccessADEnable_0=true
+5.default.params.authInfoAccessADLocationType_0=URIName
+5.default.params.authInfoAccessADLocation_0=
+5.default.params.authInfoAccessADMethod_0=1.3.6.1.5.5.7.48.1
+5.default.params.authInfoAccessCritical=false
+5.default.params.authInfoAccessNumADs=1
+6.default.class=com.netscape.cms.profile.def.KeyUsageExtDefault
+6.default.name=Key Usage Default
+6.default.params.keyUsageCritical=true
+6.default.params.keyUsageDigitalSignature=true
+6.default.params.keyUsageNonRepudiation=true
+6.default.params.keyUsageDataEncipherment=true
+6.default.params.keyUsageKeyEncipherment=true
+6.default.params.keyUsageKeyAgreement=false
+6.default.params.keyUsageKeyCertSign=false
+6.default.params.keyUsageCrlSign=false
+6.default.params.keyUsageEncipherOnly=false
+6.default.params.keyUsageDecipherOnly=false
+7.default.class=com.netscape.cms.profile.def.ExtendedKeyUsageExtDefault
+7.default.name=Extended Key Usage Extension Default
+7.default.params.exKeyUsageCritical=false
+7.default.params.exKeyUsageOIDs=1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2
diff --git a/base/kra/shared/conf/subsystemCert.profile b/base/kra/shared/conf/subsystemCert.profile
new file mode 100644
index 000000000..1fc1a6f71
--- /dev/null
+++ b/base/kra/shared/conf/subsystemCert.profile
@@ -0,0 +1,37 @@
+#
+# Subsystem Certificate
+#
+id=subsystemCert.profile
+name=subsystem cert Profile
+description=This profile creates a subsystem certificate that is valid for a CS subsystem
+list=2,4,5,6,7
+2.default.class=com.netscape.cms.profile.def.ValidityDefault
+2.default.name=Validity Default
+2.default.params.range=720
+2.default.params.startTime=0
+4.default.class=com.netscape.cms.profile.def.AuthorityKeyIdentifierExtDefault
+4.default.name=Authority Key Identifier Default
+5.default.class=com.netscape.cms.profile.def.AuthInfoAccessExtDefault
+5.default.name=AIA Extension Default
+5.default.params.authInfoAccessADEnable_0=true
+5.default.params.authInfoAccessADLocationType_0=URIName
+5.default.params.authInfoAccessADLocation_0=
+5.default.params.authInfoAccessADMethod_0=1.3.6.1.5.5.7.48.1
+5.default.params.authInfoAccessCritical=false
+5.default.params.authInfoAccessNumADs=1
+6.default.class=com.netscape.cms.profile.def.KeyUsageExtDefault
+6.default.name=Key Usage Default
+6.default.params.keyUsageCritical=true
+6.default.params.keyUsageDigitalSignature=true
+6.default.params.keyUsageNonRepudiation=true
+6.default.params.keyUsageDataEncipherment=true
+6.default.params.keyUsageKeyEncipherment=true
+6.default.params.keyUsageKeyAgreement=false
+6.default.params.keyUsageKeyCertSign=false
+6.default.params.keyUsageCrlSign=false
+6.default.params.keyUsageEncipherOnly=false
+6.default.params.keyUsageDecipherOnly=false
+7.default.class=com.netscape.cms.profile.def.ExtendedKeyUsageExtDefault
+7.default.name=Extended Key Usage Extension Default
+7.default.params.exKeyUsageCritical=false
+7.default.params.exKeyUsageOIDs=1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2
diff --git a/base/kra/shared/conf/tomcat-jk2.manifest b/base/kra/shared/conf/tomcat-jk2.manifest
new file mode 100644
index 000000000..acfef4a90
--- /dev/null
+++ b/base/kra/shared/conf/tomcat-jk2.manifest
@@ -0,0 +1,7 @@
+Manifest-version: 1.0
+Extension-Name: org.apache.jk
+Specification-Vendor: Apache Software Foundation
+Specification-Version: 2.0
+Implementation-Vendor-Id: org.apache
+Implementation-Vendor: Apache Software Foundation
+Implementation-Version: 2.1
diff --git a/base/kra/shared/conf/tomcat-users.xml b/base/kra/shared/conf/tomcat-users.xml
new file mode 100644
index 000000000..daa9260cc
--- /dev/null
+++ b/base/kra/shared/conf/tomcat-users.xml
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- BEGIN COPYRIGHT BLOCK
+ Copyright (C) 2006-2010 Red Hat, Inc.
+ All rights reserved.
+ Modifications: configuration parameters
+ END COPYRIGHT BLOCK -->
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+ <role rolename="tomcat"/>
+ <role rolename="role1"/>
+ <user username="tomcat" password="tomcat" roles="tomcat"/>
+ <user username="both" password="tomcat" roles="tomcat,role1"/>
+ <user username="role1" password="tomcat" roles="role1"/>
+-->
+
+<!-- The host manager webapp is restricted to users with role "admin" -->
+<!--<user name="tomcat" password="password" roles="admin" />-->
+<!-- The manager webapp is restricted to users with role "manager" -->
+<!--<user name="tomcat" password="password" roles="manager" />-->
+<tomcat-users>
+ <role rolename="pkiuser"/>
+ <role rolename="tomcat"/>
+ <role rolename="manager"/>
+ <role rolename="admin"/>
+
+ <user username="pkiuser" password="pkiuser" roles="pkiuser"/>
+ <user username="tomcat" password="tomcat" roles="tomcat"/>
+ <user username="admin" password="netscape" roles="admin,manager"/>
+</tomcat-users>
diff --git a/base/kra/shared/conf/tomcat6.conf b/base/kra/shared/conf/tomcat6.conf
new file mode 100644
index 000000000..2d7def5ec
--- /dev/null
+++ b/base/kra/shared/conf/tomcat6.conf
@@ -0,0 +1,58 @@
+# Service-specific configuration file for tomcat6. This will be sourced by
+# the SysV init script after the global configuration file
+# /etc/tomcat6/tomcat6.conf, thus allowing values to be overridden in
+# a per-service manner.
+#
+# NEVER change the init script itself. To change values for all services make
+# your changes in /etc/tomcat6/tomcat6.conf
+#
+# To change values for a specific service make your edits here.
+# To create a new service create a link from /etc/init.d/<your new service> to
+# /etc/init.d/tomcat6 (do not copy the init script) and make a copy of the
+# /etc/sysconfig/tomcat6 file to /etc/sysconfig/<your new service> and change
+# the property values so the two services won't conflict. Register the new
+# service in the system as usual (see chkconfig and similars).
+#
+
+# Where your java installation lives
+#JAVA_HOME="/usr/lib/jvm/java"
+
+# Where your tomcat installation lives
+CATALINA_BASE="[PKI_INSTANCE_PATH]"
+#CATALINA_HOME="/usr/share/tomcat6"
+#JASPER_HOME="/usr/share/tomcat6"
+#CATALINA_TMPDIR="/var/cache/tomcat6/temp"
+
+# You can pass some parameters to java here if you wish to
+#JAVA_OPTS="-Xminf0.1 -Xmaxf0.3"
+
+# Use JAVA_OPTS to set java.library.path for libtcnative.so
+#JAVA_OPTS="-Djava.library.path=/usr/lib64"
+
+# What user should run tomcat
+TOMCAT_USER="[PKI_USER]"
+
+# You can change your tomcat locale here
+#LANG="en_US"
+
+# Run tomcat under the Java Security Manager
+#SECURITY_MANAGER="false"
+
+# Time to wait in seconds, before killing process
+#SHUTDOWN_WAIT="30"
+
+# Whether to annoy the user with "attempting to shut down" messages or not
+#SHUTDOWN_VERBOSE="false"
+
+# Set the TOMCAT_PID location
+CATALINA_PID="[TOMCAT_PIDFILE]"
+
+# Set the tomcat log file
+TOMCAT_LOG="[TOMCAT_LOG_DIR]/tomcat-initd.log"
+
+# Connector port is 8080 for this tomcat6 instance
+#CONNECTOR_PORT="8080"
+
+# If you wish to further customize your tomcat environment,
+# put your own definitions here
+# (i.e. LD_LIBRARY_PATH for some jdbc drivers)
diff --git a/base/kra/shared/conf/transportCert.profile b/base/kra/shared/conf/transportCert.profile
new file mode 100644
index 000000000..aba748bfe
--- /dev/null
+++ b/base/kra/shared/conf/transportCert.profile
@@ -0,0 +1,37 @@
+#
+# DRM Transport Certificate
+#
+id=transportCert.profile
+name=DRM Key Transport Cert profile
+description=This profile creates a certificate that is good for transporting private key materials
+list=2,4,5,6,7
+2.default.class=com.netscape.cms.profile.def.ValidityDefault
+2.default.name=Validity Default
+2.default.params.range=720
+2.default.params.startTime=0
+4.default.class=com.netscape.cms.profile.def.AuthorityKeyIdentifierExtDefault
+4.default.name=Authority Key Identifier Default
+5.default.class=com.netscape.cms.profile.def.AuthInfoAccessExtDefault
+5.default.name=AIA Extension Default
+5.default.params.authInfoAccessADEnable_0=true
+5.default.params.authInfoAccessADLocationType_0=URIName
+5.default.params.authInfoAccessADLocation_0=
+5.default.params.authInfoAccessADMethod_0=1.3.6.1.5.5.7.48.1
+5.default.params.authInfoAccessCritical=false
+5.default.params.authInfoAccessNumADs=1
+6.default.class=com.netscape.cms.profile.def.KeyUsageExtDefault
+6.default.name=Key Usage Default
+6.default.params.keyUsageCritical=true
+6.default.params.keyUsageDigitalSignature=true
+6.default.params.keyUsageNonRepudiation=true
+6.default.params.keyUsageDataEncipherment=true
+6.default.params.keyUsageKeyEncipherment=true
+6.default.params.keyUsageKeyAgreement=false
+6.default.params.keyUsageKeyCertSign=false
+6.default.params.keyUsageCrlSign=false
+6.default.params.keyUsageEncipherOnly=false
+6.default.params.keyUsageDecipherOnly=false
+7.default.class=com.netscape.cms.profile.def.ExtendedKeyUsageExtDefault
+7.default.name=Extended Key Usage Extension Default
+7.default.params.exKeyUsageCritical=false
+7.default.params.exKeyUsageOIDs=1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2
diff --git a/base/kra/shared/conf/uriworkermap.properties b/base/kra/shared/conf/uriworkermap.properties
new file mode 100644
index 000000000..c65445b10
--- /dev/null
+++ b/base/kra/shared/conf/uriworkermap.properties
@@ -0,0 +1,13 @@
+# uriworkermap.properties - IIS
+#
+# This file provides sample mappings for example ajp13w
+# worker defined in workermap.properties.minimal
+# The general sytax for this file is:
+# [URL]=[Worker name]
+
+/servlet-examples/*=ajp13w
+
+# Optionally filter out all .jpeg files inside that context
+# For no mapping the url has to start with exclamation (!)
+
+!/servlet-examples/*.jpeg=ajp13w
diff --git a/base/kra/shared/conf/vlv.ldif b/base/kra/shared/conf/vlv.ldif
new file mode 100644
index 000000000..b619e8657
--- /dev/null
+++ b/base/kra/shared/conf/vlv.ldif
@@ -0,0 +1,207 @@
+dn: cn=allKeys-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: allKeys-{instanceId}
+vlvBase: ou=keyRepository,ou=kra,{rootSuffix}
+vlvScope: 1
+vlvFilter: (&(&(objectClass=top)(objectClass=keyRecord))(serialno=*))
+
+dn: cn=kraAll-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraAll-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (requeststate=*)
+
+dn: cn=kraArchival-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraArchival-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (requesttype=enrollment)
+
+dn: cn=kraRecovery-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraRecovery-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (requesttype=recovery)
+
+dn: cn=kraCanceled-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraCanceled-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (requeststate=canceled)
+
+dn: cn=kraCanceledEnrollment-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraCanceledEnrollment-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (&(requeststate=canceled)(requesttype=enrollment))
+
+dn: cn=kraCanceledRecovery-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraCanceledRecovery-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (&(requeststate=canceled)(requesttype=recovery))
+
+dn: cn=kraRejected-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraRejected-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (requeststate=rejected)
+
+dn: cn=kraRejectedEnrollment-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraRejectedEnrollment-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (&(requeststate=rejected)(requesttype=enrollment))
+
+dn: cn=kraRejectedRecovery-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraRejectedRecovery-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (&(requeststate=rejected)(requesttype=recovery))
+
+dn: cn=kraComplete-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraComplete-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (requeststate=complete)
+
+dn: cn=kraCompleteEnrollment-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraCompleteEnrollment-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (&(requeststate=complete)(requesttype=enrollment))
+
+dn: cn=kraCompleteRecovery-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvSearch
+cn: kraCompleteRecovery-{instanceId}
+vlvBase: ou=kra,ou=requests,{rootSuffix}
+vlvScope: 1
+vlvFilter: (&(requeststate=complete)(requesttype=recovery))
+
+dn: cn=allKeys-{instanceId}Index, cn=allKeys-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: allKeys-{instanceId}Index
+vlvSort: serialno
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraAll-{instanceId}Index, cn=kraAll-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraAll-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraArchival-{instanceId}Index, cn=kraArchival-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraArchival-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraRecovery-{instanceId}Index, cn=kraRecovery-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraRecovery-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraCanceled-{instanceId}Index, cn=kraCanceled-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraCanceled-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraCanceledEnrollment-{instanceId}Index, cn=kraCanceledEnrollment-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraCanceledEnrollment-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraCanceledRecovery-{instanceId}Index, cn=kraCanceledRecovery-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraCanceledRecovery-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraRejected-{instanceId}Index, cn=kraRejected-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraRejected-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraRejectedEnrollment-{instanceId}Index, cn=kraRejectedEnrollment-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraRejectedEnrollment-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraRejectedRecovery-{instanceId}Index, cn=kraRejectedRecovery-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraRejectedRecovery-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraComplete-{instanceId}Index, cn=kraComplete-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraComplete-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraCompleteEnrollment-{instanceId}Index, cn=kraCompleteEnrollment-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraCompleteEnrollment-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
+
+dn: cn=kraCompleteRecovery-{instanceId}Index, cn=kraCompleteRecovery-{instanceId}, cn={database}, cn=ldbm database, cn=plugins, cn=config
+objectClass: top
+objectClass: vlvIndex
+cn: kraCompleteRecovery-{instanceId}Index
+vlvSort: requestId
+vlvEnabled: 0
+vlvUses: 0
diff --git a/base/kra/shared/conf/vlvtasks.ldif b/base/kra/shared/conf/vlvtasks.ldif
new file mode 100644
index 000000000..c8a27f170
--- /dev/null
+++ b/base/kra/shared/conf/vlvtasks.ldif
@@ -0,0 +1,19 @@
+dn: cn=index1160527115, cn=index, cn=tasks, cn=config
+objectclass: top
+objectclass: extensibleObject
+cn: index1160527115
+ttl: 10
+nsInstance: {database}
+nsIndexVLVAttribute: allKeys-{instanceId}Index
+nsIndexVLVAttribute: kraAll-{instanceId}Index
+nsIndexVLVAttribute: kraArchival-{instanceId}Index
+nsIndexVLVAttribute: kraRecovery-{instanceId}Index
+nsIndexVLVAttribute: kraCanceled-{instanceId}Index
+nsIndexVLVAttribute: kraCanceledEnrollment-{instanceId}Index
+nsIndexVLVAttribute: kraCanceledRecovery-{instanceId}Index
+nsIndexVLVAttribute: kraRejected-{instanceId}Index
+nsIndexVLVAttribute: kraRejectedEnrollment-{instanceId}Index
+nsIndexVLVAttribute: kraRejectedRecovery-{instanceId}Index
+nsIndexVLVAttribute: kraComplete-{instanceId}Index
+nsIndexVLVAttribute: kraCompleteEnrollment-{instanceId}Index
+nsIndexVLVAttribute: kraCompleteRecovery-{instanceId}Index
diff --git a/base/kra/shared/conf/web.xml b/base/kra/shared/conf/web.xml
new file mode 100644
index 000000000..fb22468ee
--- /dev/null
+++ b/base/kra/shared/conf/web.xml
@@ -0,0 +1,989 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+ version="2.4">
+
+ <!-- ======================== Introduction ============================== -->
+ <!-- This document defines default values for *all* web applications -->
+ <!-- loaded into this instance of Tomcat. As each application is -->
+ <!-- deployed, this file is processed, followed by the -->
+ <!-- "/WEB-INF/web.xml" deployment descriptor from your own -->
+ <!-- applications. -->
+ <!-- -->
+ <!-- WARNING: Do not configure application-specific resources here! -->
+ <!-- They should go in the "/WEB-INF/web.xml" file in your application. -->
+
+
+ <!-- ================== Built In Servlet Definitions ==================== -->
+
+
+ <!-- The default servlet for all web applications, that serves static -->
+ <!-- resources. It processes all requests that are not mapped to other -->
+ <!-- servlets with servlet mappings (defined either here or in your own -->
+ <!-- web.xml file. This servlet supports the following initialization -->
+ <!-- parameters (default values are in square brackets): -->
+ <!-- -->
+ <!-- debug Debugging detail level for messages logged -->
+ <!-- by this servlet. [0] -->
+ <!-- -->
+ <!-- fileEncoding Encoding to be used to read static resources -->
+ <!-- [platform default] -->
+ <!-- -->
+ <!-- input Input buffer size (in bytes) when reading -->
+ <!-- resources to be served. [2048] -->
+ <!-- -->
+ <!-- listings Should directory listings be produced if there -->
+ <!-- is no welcome file in this directory? [true] -->
+ <!-- -->
+ <!-- output Output buffer size (in bytes) when writing -->
+ <!-- resources to be served. [2048] -->
+ <!-- -->
+ <!-- readonly Is this context "read only", so HTTP -->
+ <!-- commands like PUT and DELETE are -->
+ <!-- rejected? [true] -->
+ <!-- -->
+ <!-- readmeFile File name to display with the directory -->
+ <!-- contents. [null] -->
+ <!-- -->
+ <!-- For directory listing customization. Checks localXsltFile, then -->
+ <!-- globalXsltFile, then defaults to original behavior. -->
+ <!-- -->
+ <!-- localXsltFile Make directory listings an XML doc and -->
+ <!-- pass the result to this style sheet residing -->
+ <!-- in that directory. This overrides -->
+ <!-- globalXsltFile[null] -->
+ <!-- -->
+ <!-- globalXsltFile Site wide configuration version of -->
+ <!-- localXsltFile This argument is expected -->
+ <!-- to be a physical file. [null] -->
+ <!-- -->
+ <!-- -->
+
+ <servlet>
+ <servlet-name>default</servlet-name>
+ <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
+ <init-param>
+ <param-name>debug</param-name>
+ <param-value>0</param-value>
+ </init-param>
+ <init-param>
+ <param-name>listings</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+
+ <!-- The "invoker" servlet, which executes anonymous servlet classes -->
+ <!-- that have not been defined in a web.xml file. Traditionally, this -->
+ <!-- servlet is mapped to the URL pattern "/servlet/*", but you can map -->
+ <!-- it to other patterns as well. The extra path info portion of such a -->
+ <!-- request must be the fully qualified class name of a Java class that -->
+ <!-- implements Servlet (or extends HttpServlet), or the servlet name -->
+ <!-- of an existing servlet definition. This servlet supports the -->
+ <!-- following initialization parameters (default values are in square -->
+ <!-- brackets): -->
+ <!-- -->
+ <!-- debug Debugging detail level for messages logged -->
+ <!-- by this servlet. [0] -->
+
+<!--
+ <servlet>
+ <servlet-name>invoker</servlet-name>
+ <servlet-class>
+ org.apache.catalina.servlets.InvokerServlet
+ </servlet-class>
+ <init-param>
+ <param-name>debug</param-name>
+ <param-value>0</param-value>
+ </init-param>
+ <load-on-startup>2</load-on-startup>
+ </servlet>
+-->
+
+
+ <!-- The JSP page compiler and execution servlet, which is the mechanism -->
+ <!-- used by Tomcat to support JSP pages. Traditionally, this servlet -->
+ <!-- is mapped to the URL pattern "*.jsp". This servlet supports the -->
+ <!-- following initialization parameters (default values are in square -->
+ <!-- brackets): -->
+ <!-- -->
+ <!-- checkInterval If development is false and checkInterval is -->
+ <!-- greater than zero, background compilations are -->
+ <!-- enabled. checkInterval is the time in seconds -->
+ <!-- between checks to see if a JSP page needs to -->
+ <!-- be recompiled. [0] -->
+ <!-- -->
+ <!-- modificationTestInterval -->
+ <!-- Causes a JSP (and its dependent files) to not -->
+ <!-- be checked for modification during the -->
+ <!-- specified time interval (in seconds) from the -->
+ <!-- last time the JSP was checked for -->
+ <!-- modification. A value of 0 will cause the JSP -->
+ <!-- to be checked on every access. -->
+ <!-- Used in development mode only. [4] -->
+ <!-- -->
+ <!-- compiler Which compiler Ant should use to compile JSP -->
+ <!-- pages. See the Ant documentation for more -->
+ <!-- information. [javac] -->
+ <!-- -->
+ <!-- classdebuginfo Should the class file be compiled with -->
+ <!-- debugging information? [true] -->
+ <!-- -->
+ <!-- classpath What class path should I use while compiling -->
+ <!-- generated servlets? [Created dynamically -->
+ <!-- based on the current web application] -->
+ <!-- -->
+ <!-- development Is Jasper used in development mode? If true, -->
+ <!-- the frequency at which JSPs are checked for -->
+ <!-- modification may be specified via the -->
+ <!-- modificationTestInterval parameter. [true] -->
+ <!-- -->
+ <!-- enablePooling Determines whether tag handler pooling is -->
+ <!-- enabled [true] -->
+ <!-- -->
+ <!-- fork Tell Ant to fork compiles of JSP pages so that -->
+ <!-- a separate JVM is used for JSP page compiles -->
+ <!-- from the one Tomcat is running in. [true] -->
+ <!-- -->
+ <!-- ieClassId The class-id value to be sent to Internet -->
+ <!-- Explorer when using <jsp:plugin> tags. -->
+ <!-- [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93] -->
+ <!-- -->
+ <!-- javaEncoding Java file encoding to use for generating java -->
+ <!-- source files. [UTF8] -->
+ <!-- -->
+ <!-- keepgenerated Should we keep the generated Java source code -->
+ <!-- for each page instead of deleting it? [true] -->
+ <!-- -->
+ <!-- mappedfile Should we generate static content with one -->
+ <!-- print statement per input line, to ease -->
+ <!-- debugging? [true] -->
+ <!-- -->
+ <!-- trimSpaces Should white spaces in template text between -->
+ <!-- actions or directives be trimmed? [false] -->
+ <!-- -->
+ <!-- suppressSmap Should the generation of SMAP info for JSR45 -->
+ <!-- debugging be suppressed? [false] -->
+ <!-- -->
+ <!-- dumpSmap Should the SMAP info for JSR45 debugging be -->
+ <!-- dumped to a file? [false] -->
+ <!-- False if suppressSmap is true -->
+ <!-- -->
+ <!-- genStrAsCharArray Should text strings be generated as char -->
+ <!-- arrays, to improve performance in some cases? -->
+ <!-- [false] -->
+ <!-- -->
+ <!-- errorOnUseBeanInvalidClassAttribute -->
+ <!-- Should Jasper issue an error when the value of -->
+ <!-- the class attribute in an useBean action is -->
+ <!-- not a valid bean class? [true] -->
+ <!-- -->
+ <!-- scratchdir What scratch directory should we use when -->
+ <!-- compiling JSP pages? [default work directory -->
+ <!-- for the current web application] -->
+ <!-- -->
+ <!-- xpoweredBy Determines whether X-Powered-By response -->
+ <!-- header is added by generated servlet [false] -->
+ <!-- -->
+ <!-- If you wish to use Jikes to compile JSP pages: -->
+ <!-- Please see the "Using Jikes" section of the Jasper-HowTo -->
+ <!-- page in the Tomcat documentation. -->
+
+ <servlet>
+ <servlet-name>jsp</servlet-name>
+ <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+ <init-param>
+ <param-name>fork</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>xpoweredBy</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <load-on-startup>3</load-on-startup>
+ </servlet>
+
+
+ <!-- Server Side Includes processing servlet, which processes SSI -->
+ <!-- directives in HTML pages consistent with similar support in web -->
+ <!-- servers like Apache. Traditionally, this servlet is mapped to the -->
+ <!-- URL pattern "*.shtml". This servlet supports the following -->
+ <!-- initialization parameters (default values are in square brackets): -->
+ <!-- -->
+ <!-- buffered Should output from this servlet be buffered? -->
+ <!-- (0=false, 1=true) [0] -->
+ <!-- -->
+ <!-- debug Debugging detail level for messages logged -->
+ <!-- by this servlet. [0] -->
+ <!-- -->
+ <!-- expires The number of seconds before a page with SSI -->
+ <!-- directives will expire. [No default] -->
+ <!-- -->
+ <!-- isVirtualWebappRelative -->
+ <!-- Should "virtual" paths be interpreted as -->
+ <!-- relative to the context root, instead of -->
+ <!-- the server root? (0=false, 1=true) [0] -->
+ <!-- -->
+ <!-- -->
+ <!-- IMPORTANT: To use the SSI servlet, you also need to rename the -->
+ <!-- $CATALINA_HOME/server/lib/servlets-ssi.renametojar file -->
+ <!-- to $CATALINA_HOME/server/lib/servlets-ssi.jar -->
+
+<!--
+ <servlet>
+ <servlet-name>ssi</servlet-name>
+ <servlet-class>
+ org.apache.catalina.ssi.SSIServlet
+ </servlet-class>
+ <init-param>
+ <param-name>buffered</param-name>
+ <param-value>1</param-value>
+ </init-param>
+ <init-param>
+ <param-name>debug</param-name>
+ <param-value>0</param-value>
+ </init-param>
+ <init-param>
+ <param-name>expires</param-name>
+ <param-value>666</param-value>
+ </init-param>
+ <init-param>
+ <param-name>isVirtualWebappRelative</param-name>
+ <param-value>0</param-value>
+ </init-param>
+ <load-on-startup>4</load-on-startup>
+ </servlet>
+-->
+
+
+ <!-- Common Gateway Includes (CGI) processing servlet, which supports -->
+ <!-- execution of external applications that conform to the CGI spec -->
+ <!-- requirements. Typically, this servlet is mapped to the URL pattern -->
+ <!-- "/cgi-bin/*", which means that any CGI applications that are -->
+ <!-- executed must be present within the web application. This servlet -->
+ <!-- supports the following initialization parameters (default values -->
+ <!-- are in square brackets): -->
+ <!-- -->
+ <!-- cgiPathPrefix The CGI search path will start at -->
+ <!-- webAppRootDir + File.separator + this prefix. -->
+ <!-- [WEB-INF/cgi] -->
+ <!-- -->
+ <!-- debug Debugging detail level for messages logged -->
+ <!-- by this servlet. [0] -->
+ <!-- -->
+ <!-- executable Name of the exectuable used to run the -->
+ <!-- script. [perl] -->
+ <!-- -->
+ <!-- parameterEncoding Name of parameter encoding to be used with -->
+ <!-- CGI servlet. -->
+ <!-- [System.getProperty("file.encoding","UTF-8")] -->
+ <!-- -->
+ <!-- passShellEnvironment Should the shell environment variables (if -->
+ <!-- any) be passed to the CGI script? [false] -->
+ <!-- -->
+ <!-- IMPORTANT: To use the CGI servlet, you also need to rename the -->
+ <!-- $CATALINA_HOME/server/lib/servlets-cgi.renametojar file -->
+ <!-- to $CATALINA_HOME/server/lib/servlets-cgi.jar -->
+
+<!--
+ <servlet>
+ <servlet-name>cgi</servlet-name>
+ <servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
+ <init-param>
+ <param-name>debug</param-name>
+ <param-value>6</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cgiPathPrefix</param-name>
+ <param-value>WEB-INF/cgi</param-value>
+ </init-param>
+ <load-on-startup>5</load-on-startup>
+ </servlet>
+-->
+
+
+ <!-- ================ Built In Servlet Mappings ========================= -->
+
+
+ <!-- The servlet mappings for the built in servlets defined above. Note -->
+ <!-- that, by default, the CGI and SSI servlets are *not* mapped. You -->
+ <!-- must uncomment these mappings (or add them to your application's own -->
+ <!-- web.xml deployment descriptor) to enable these services -->
+
+ <!-- The mapping for the default servlet -->
+ <servlet-mapping>
+ <servlet-name>default</servlet-name>
+ <url-pattern>/</url-pattern>
+ </servlet-mapping>
+
+ <!-- The mapping for the invoker servlet -->
+<!--
+ <servlet-mapping>
+ <servlet-name>invoker</servlet-name>
+ <url-pattern>/servlet/*</url-pattern>
+ </servlet-mapping>
+-->
+
+ <!-- The mapping for the JSP servlet -->
+ <servlet-mapping>
+ <servlet-name>jsp</servlet-name>
+ <url-pattern>*.jsp</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>jsp</servlet-name>
+ <url-pattern>*.jspx</url-pattern>
+ </servlet-mapping>
+
+ <!-- The mapping for the SSI servlet -->
+<!--
+ <servlet-mapping>
+ <servlet-name>ssi</servlet-name>
+ <url-pattern>*.shtml</url-pattern>
+ </servlet-mapping>
+-->
+
+ <!-- The mapping for the CGI Gateway servlet -->
+
+<!--
+ <servlet-mapping>
+ <servlet-name>cgi</servlet-name>
+ <url-pattern>/cgi-bin/*</url-pattern>
+ </servlet-mapping>
+-->
+
+
+ <!-- ==================== Default Session Configuration ================= -->
+ <!-- You can set the default session timeout (in minutes) for all newly -->
+ <!-- created sessions by modifying the value below. -->
+
+ <session-config>
+ <session-timeout>30</session-timeout>
+ </session-config>
+
+
+ <!-- ===================== Default MIME Type Mappings =================== -->
+ <!-- When serving static resources, Tomcat will automatically generate -->
+ <!-- a "Content-Type" header based on the resource's filename extension, -->
+ <!-- based on these mappings. Additional mappings can be added here (to -->
+ <!-- apply to all web applications), or in your own application's web.xml -->
+ <!-- deployment descriptor. -->
+
+ <mime-mapping>
+ <extension>abs</extension>
+ <mime-type>audio/x-mpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ai</extension>
+ <mime-type>application/postscript</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>aif</extension>
+ <mime-type>audio/x-aiff</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>aifc</extension>
+ <mime-type>audio/x-aiff</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>aiff</extension>
+ <mime-type>audio/x-aiff</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>aim</extension>
+ <mime-type>application/x-aim</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>art</extension>
+ <mime-type>image/x-jg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>asf</extension>
+ <mime-type>video/x-ms-asf</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>asx</extension>
+ <mime-type>video/x-ms-asf</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>au</extension>
+ <mime-type>audio/basic</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>avi</extension>
+ <mime-type>video/x-msvideo</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>avx</extension>
+ <mime-type>video/x-rad-screenplay</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>bcpio</extension>
+ <mime-type>application/x-bcpio</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>bin</extension>
+ <mime-type>application/octet-stream</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>bmp</extension>
+ <mime-type>image/bmp</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>body</extension>
+ <mime-type>text/html</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>cdf</extension>
+ <mime-type>application/x-cdf</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>cer</extension>
+ <mime-type>application/x-x509-ca-cert</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>class</extension>
+ <mime-type>application/java</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>cpio</extension>
+ <mime-type>application/x-cpio</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>csh</extension>
+ <mime-type>application/x-csh</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>css</extension>
+ <mime-type>text/css</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>dib</extension>
+ <mime-type>image/bmp</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>doc</extension>
+ <mime-type>application/msword</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>dtd</extension>
+ <mime-type>application/xml-dtd</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>dv</extension>
+ <mime-type>video/x-dv</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>dvi</extension>
+ <mime-type>application/x-dvi</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>eps</extension>
+ <mime-type>application/postscript</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>etx</extension>
+ <mime-type>text/x-setext</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>exe</extension>
+ <mime-type>application/octet-stream</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>gif</extension>
+ <mime-type>image/gif</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>gtar</extension>
+ <mime-type>application/x-gtar</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>gz</extension>
+ <mime-type>application/x-gzip</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>hdf</extension>
+ <mime-type>application/x-hdf</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>hqx</extension>
+ <mime-type>application/mac-binhex40</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>htc</extension>
+ <mime-type>text/x-component</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>htm</extension>
+ <mime-type>text/html</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>html</extension>
+ <mime-type>text/html</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>hqx</extension>
+ <mime-type>application/mac-binhex40</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ief</extension>
+ <mime-type>image/ief</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>jad</extension>
+ <mime-type>text/vnd.sun.j2me.app-descriptor</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>jar</extension>
+ <mime-type>application/java-archive</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>java</extension>
+ <mime-type>text/plain</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>jnlp</extension>
+ <mime-type>application/x-java-jnlp-file</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>jpe</extension>
+ <mime-type>image/jpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>jpeg</extension>
+ <mime-type>image/jpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>jpg</extension>
+ <mime-type>image/jpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>js</extension>
+ <mime-type>text/javascript</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>jsf</extension>
+ <mime-type>text/plain</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>jspf</extension>
+ <mime-type>text/plain</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>kar</extension>
+ <mime-type>audio/x-midi</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>latex</extension>
+ <mime-type>application/x-latex</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>m3u</extension>
+ <mime-type>audio/x-mpegurl</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mac</extension>
+ <mime-type>image/x-macpaint</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>man</extension>
+ <mime-type>application/x-troff-man</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mathml</extension>
+ <mime-type>application/mathml+xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>me</extension>
+ <mime-type>application/x-troff-me</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mid</extension>
+ <mime-type>audio/x-midi</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>midi</extension>
+ <mime-type>audio/x-midi</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mif</extension>
+ <mime-type>application/x-mif</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mov</extension>
+ <mime-type>video/quicktime</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>movie</extension>
+ <mime-type>video/x-sgi-movie</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mp1</extension>
+ <mime-type>audio/x-mpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mp2</extension>
+ <mime-type>audio/x-mpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mp3</extension>
+ <mime-type>audio/x-mpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mpa</extension>
+ <mime-type>audio/x-mpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mpe</extension>
+ <mime-type>video/mpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mpeg</extension>
+ <mime-type>video/mpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mpega</extension>
+ <mime-type>audio/x-mpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mpg</extension>
+ <mime-type>video/mpeg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>mpv2</extension>
+ <mime-type>video/mpeg2</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ms</extension>
+ <mime-type>application/x-wais-source</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>nc</extension>
+ <mime-type>application/x-netcdf</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>oda</extension>
+ <mime-type>application/oda</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ogg</extension>
+ <mime-type>application/ogg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>pbm</extension>
+ <mime-type>image/x-portable-bitmap</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>pct</extension>
+ <mime-type>image/pict</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>pdf</extension>
+ <mime-type>application/pdf</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>pgm</extension>
+ <mime-type>image/x-portable-graymap</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>pic</extension>
+ <mime-type>image/pict</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>pict</extension>
+ <mime-type>image/pict</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>pls</extension>
+ <mime-type>audio/x-scpls</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>png</extension>
+ <mime-type>image/png</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>pnm</extension>
+ <mime-type>image/x-portable-anymap</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>pnt</extension>
+ <mime-type>image/x-macpaint</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ppm</extension>
+ <mime-type>image/x-portable-pixmap</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ppt</extension>
+ <mime-type>application/powerpoint</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ps</extension>
+ <mime-type>application/postscript</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>psd</extension>
+ <mime-type>image/x-photoshop</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>qt</extension>
+ <mime-type>video/quicktime</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>qti</extension>
+ <mime-type>image/x-quicktime</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>qtif</extension>
+ <mime-type>image/x-quicktime</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ras</extension>
+ <mime-type>image/x-cmu-raster</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>rdf</extension>
+ <mime-type>application/rdf+xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>rgb</extension>
+ <mime-type>image/x-rgb</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>rm</extension>
+ <mime-type>application/vnd.rn-realmedia</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>roff</extension>
+ <mime-type>application/x-troff</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>rtf</extension>
+ <mime-type>application/rtf</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>rtx</extension>
+ <mime-type>text/richtext</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>sh</extension>
+ <mime-type>application/x-sh</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>shar</extension>
+ <mime-type>application/x-shar</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>smf</extension>
+ <mime-type>audio/x-midi</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>sit</extension>
+ <mime-type>application/x-stuffit</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>snd</extension>
+ <mime-type>audio/basic</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>src</extension>
+ <mime-type>application/x-wais-source</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>sv4cpio</extension>
+ <mime-type>application/x-sv4cpio</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>sv4crc</extension>
+ <mime-type>application/x-sv4crc</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>svg</extension>
+ <mime-type>image/svg+xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>swf</extension>
+ <mime-type>application/x-shockwave-flash</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>t</extension>
+ <mime-type>application/x-troff</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>tar</extension>
+ <mime-type>application/x-tar</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>tcl</extension>
+ <mime-type>application/x-tcl</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>tex</extension>
+ <mime-type>application/x-tex</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>texi</extension>
+ <mime-type>application/x-texinfo</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>texinfo</extension>
+ <mime-type>application/x-texinfo</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>tif</extension>
+ <mime-type>image/tiff</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>tiff</extension>
+ <mime-type>image/tiff</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>tr</extension>
+ <mime-type>application/x-troff</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>tsv</extension>
+ <mime-type>text/tab-separated-values</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>txt</extension>
+ <mime-type>text/plain</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ulw</extension>
+ <mime-type>audio/basic</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>ustar</extension>
+ <mime-type>application/x-ustar</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>vxml</extension>
+ <mime-type>application/voicexml+xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>xbm</extension>
+ <mime-type>image/x-xbitmap</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>xht</extension>
+ <mime-type>application/xhtml+xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>xhtml</extension>
+ <mime-type>application/xhtml+xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>xml</extension>
+ <mime-type>application/xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>xpm</extension>
+ <mime-type>image/x-xpixmap</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>xsl</extension>
+ <mime-type>application/xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>xslt</extension>
+ <mime-type>application/xslt+xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>xul</extension>
+ <mime-type>application/vnd.mozilla.xul+xml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>xwd</extension>
+ <mime-type>image/x-xwindowdump</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>wav</extension>
+ <mime-type>audio/x-wav</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>svg</extension>
+ <mime-type>image/svg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>svgz</extension>
+ <mime-type>image/svg</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>vsd</extension>
+ <mime-type>application/x-visio</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <!-- Wireless Bitmap -->
+ <extension>wbmp</extension>
+ <mime-type>image/vnd.wap.wbmp</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <!-- WML Source -->
+ <extension>wml</extension>
+ <mime-type>text/vnd.wap.wml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <!-- Compiled WML -->
+ <extension>wmlc</extension>
+ <mime-type>application/vnd.wap.wmlc</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <!-- WML Script Source -->
+ <extension>wmls</extension>
+ <mime-type>text/vnd.wap.wmlscript</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <!-- Compiled WML Script -->
+ <extension>wmlscriptc</extension>
+ <mime-type>application/vnd.wap.wmlscriptc</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>wrl</extension>
+ <mime-type>x-world/x-vrml</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>Z</extension>
+ <mime-type>application/x-compress</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>z</extension>
+ <mime-type>application/x-compress</mime-type>
+ </mime-mapping>
+ <mime-mapping>
+ <extension>zip</extension>
+ <mime-type>application/zip</mime-type>
+ </mime-mapping>
+
+
+ <!-- ==================== Default Welcome File List ===================== -->
+ <!-- When a request URI refers to a directory, the default servlet looks -->
+ <!-- for a "welcome file" within that directory and, if present, -->
+ <!-- to the corresponding resource URI for display. If no welcome file -->
+ <!-- is present, the default servlet either serves a directory listing, -->
+ <!-- or returns a 404 status, depending on how it is configured. -->
+ <!-- -->
+ <!-- If you define welcome files in your own application's web.xml -->
+ <!-- deployment descriptor, that list *replaces* the list configured -->
+ <!-- here, so be sure that you include any of the default values that -->
+ <!-- you wish to include. -->
+
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ <welcome-file>index.htm</welcome-file>
+ <welcome-file>index.jsp</welcome-file>
+ </welcome-file-list>
+
+ <error-page>
+ <error-code>404</error-code>
+ <location>/404.html</location>
+ </error-page>
+
+ <error-page>
+ <error-code>500</error-code>
+ <location>/500.html</location>
+ </error-page>
+
+</web-app>
diff --git a/base/kra/shared/conf/workers.properties b/base/kra/shared/conf/workers.properties
new file mode 100644
index 000000000..50d88557f
--- /dev/null
+++ b/base/kra/shared/conf/workers.properties
@@ -0,0 +1,206 @@
+# workers.properties -
+#
+# This file provides jk derived plugins with the needed information to
+# connect to the different tomcat workers. Note that the distributed
+# version of this file requires modification before it is usable by a
+# plugin.
+#
+# As a general note, the characters $( and ) are used internally to define
+# macros. Do not use them in your own configuration!!!
+#
+# Whenever you see a set of lines such as:
+# x=value
+# y=$(x)\something
+#
+# the final value for y will be value\something
+#
+# Normaly all you will need to do is un-comment and modify the first three
+# properties, i.e. workers.tomcat_home, workers.java_home and ps.
+# Most of the configuration is derived from these.
+#
+# When you are done updating workers.tomcat_home, workers.java_home and ps
+# you should have 3 workers configured:
+#
+# - An ajp12 worker that connects to localhost:8007
+# - An ajp13 worker that connects to localhost:8009
+# - A jni inprocess worker.
+# - A load balancer worker
+#
+# However by default the plugins will only use the ajp12 worker. To have
+# the plugins use other workers you should modify the worker.list property.
+#
+#
+
+# OPTIONS ( very important for jni mode )
+
+#
+# workers.tomcat_home should point to the location where you
+# installed tomcat. This is where you have your conf, webapps and lib
+# directories.
+#
+workers.tomcat_home=/var/tomcat3
+
+#
+# workers.java_home should point to your Java installation. Normally
+# you should have a bin and lib directories beneath it.
+#
+workers.java_home=/opt/IBMJava2-13
+
+#
+# You should configure your environment slash... ps=\ on NT and / on UNIX
+# and maybe something different elsewhere.
+#
+ps=/
+
+#
+#------ ADVANCED MODE ------------------------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+#------ DEFAULT worket list ------------------------------------------
+#---------------------------------------------------------------------
+#
+#
+# The workers that your plugins should create and work with
+#
+# Add 'inprocess' if you want JNI connector
+worker.list=ajp12, ajp13
+# , inprocess
+
+
+#
+#------ DEFAULT ajp12 WORKER DEFINITION ------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+# Defining a worker named ajp12 and of type ajp12
+# Note that the name and the type do not have to match.
+#
+worker.ajp12.port=8007
+worker.ajp12.host=localhost
+worker.ajp12.type=ajp12
+#
+# Specifies the load balance factor when used with
+# a load balancing worker.
+# Note:
+# ----> lbfactor must be > 0
+# ----> Low lbfactor means less work done by the worker.
+worker.ajp12.lbfactor=1
+
+#
+#------ DEFAULT ajp13 WORKER DEFINITION ------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+# Defining a worker named ajp13 and of type ajp13
+# Note that the name and the type do not have to match.
+#
+worker.ajp13.port=8009
+worker.ajp13.host=localhost
+worker.ajp13.type=ajp13
+#
+# Specifies the load balance factor when used with
+# a load balancing worker.
+# Note:
+# ----> lbfactor must be > 0
+# ----> Low lbfactor means less work done by the worker.
+worker.ajp13.lbfactor=1
+
+#
+# Specify the size of the open connection cache.
+#worker.ajp13.cachesize
+
+#
+#------ DEFAULT LOAD BALANCER WORKER DEFINITION ----------------------
+#---------------------------------------------------------------------
+#
+
+#
+# The loadbalancer (type lb) workers perform wighted round-robin
+# load balancing with sticky sessions.
+# Note:
+# ----> If a worker dies, the load balancer will check its state
+# once in a while. Until then all work is redirected to peer
+# workers.
+worker.loadbalancer.type=lb
+worker.loadbalancer.balanced_workers=ajp12, ajp13
+
+
+#
+#------ DEFAULT JNI WORKER DEFINITION---------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+# Defining a worker named inprocess and of type jni
+# Note that the name and the type do not have to match.
+#
+worker.inprocess.type=jni
+
+#
+#------ CLASSPATH DEFINITION -----------------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+# Additional class path components.
+#
+worker.inprocess.class_path=$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar
+
+#
+# Setting the command line for tomcat.
+# Note: The cmd_line string may not contain spaces.
+#
+worker.inprocess.cmd_line=start
+
+# Not needed, but can be customized.
+#worker.inprocess.cmd_line=-config
+#worker.inprocess.cmd_line=$(workers.tomcat_home)$(ps)conf$(ps)server.xml
+#worker.inprocess.cmd_line=-home
+#worker.inprocess.cmd_line=$(workers.tomcat_home)
+
+#
+# The JVM that we are about to use
+#
+# This is for Java2
+#
+# Windows
+worker.inprocess.jvm_lib=$(workers.java_home)$(ps)jre$(ps)bin$(ps)classic$(ps)jvm.dll
+# IBM JDK1.3
+#worker.inprocess.jvm_lib=$(workers.java_home)$(ps)jre$(ps)bin$(ps)classic$(ps)libjvm.so
+# Unix - Sun VM or blackdown
+#worker.inprocess.jvm_lib=$(workers.java_home)$(ps)jre$(ps)lib$(ps)i386$(ps)classic$(ps)libjvm.so
+
+#
+# And this is for jdk1.1.X
+#
+#worker.inprocess.jvm_lib=$(workers.java_home)$(ps)bin$(ps)javai.dll
+
+
+#
+# Setting the place for the stdout and stderr of tomcat
+#
+worker.inprocess.stdout=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stdout
+worker.inprocess.stderr=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stderr
+
+#
+# Setting the tomcat.home Java property
+#
+#worker.inprocess.sysprops=tomcat.home=$(workers.tomcat_home)
+
+#
+# Java system properties
+#
+# worker.inprocess.sysprops=java.compiler=NONE
+# worker.inprocess.sysprops=myprop=mypropvalue
+
+#
+# Additional path components.
+#
+# worker.inprocess.ld_path=d:$(ps)SQLLIB$(ps)bin
+#
+
+
diff --git a/base/kra/shared/conf/workers.properties.minimal b/base/kra/shared/conf/workers.properties.minimal
new file mode 100644
index 000000000..e3b5942c2
--- /dev/null
+++ b/base/kra/shared/conf/workers.properties.minimal
@@ -0,0 +1,17 @@
+# workers.properties.minimal -
+#
+# This file provides minimal jk configuration properties needed to
+# connect to Tomcat.
+#
+# The workers that jk should create and work with
+#
+worker.list=ajp13w
+
+
+#
+# Defining a worker named ajp13w and of type ajp13
+# Note that the name and the type do not have to match.
+#
+worker.ajp13w.type=ajp13
+worker.ajp13w.host=localhost
+worker.ajp13w.port=8009
diff --git a/base/kra/shared/conf/workers2.properties b/base/kra/shared/conf/workers2.properties
new file mode 100644
index 000000000..778118ff2
--- /dev/null
+++ b/base/kra/shared/conf/workers2.properties
@@ -0,0 +1,132 @@
+[logger]
+level=DEBUG
+
+[config:]
+file=${serverRoot}/conf/workers2.properties
+debug=0
+debugEnv=0
+
+[uriMap:]
+info=Maps the requests. Options: debug
+debug=0
+
+# Alternate file logger
+#[logger.file:0]
+#level=DEBUG
+#file=${serverRoot}/logs/jk2.log
+
+[shm:]
+info=Scoreboard. Required for reconfiguration and status with multiprocess servers
+file=${serverRoot}/logs/jk2.shm
+size=1000000
+debug=0
+disabled=0
+
+[workerEnv:]
+info=Global server options
+timing=1
+debug=0
+# Default Native Logger (apache2 or win32 )
+# can be overriden to a file logger, useful
+# when tracing win32 related issues
+#logger=logger.file:0
+
+[lb:lb]
+info=Default load balancer.
+debug=0
+
+[lb:lb_1]
+info=A second load balancer.
+debug=0
+
+[channel.socket:localhost:8009]
+info=Ajp13 forwarding over socket
+debug=0
+tomcatId=localhost:8009
+
+[channel.socket:localhost:8019]
+info=A second tomcat instance.
+debug=0
+tomcatId=localhost:8019
+lb_factor=1
+#group=lb
+group:lb:lb
+#group=lb_1
+group:lb:lb_1
+disabled=0
+
+[channel.un:/opt/33/work/jk2.socket]
+info=A second channel connecting to localhost:8019 via unix socket
+tomcatId=localhost:8019
+lb_factor=1
+debug=0
+
+[channel.jni:jni]
+info=The jni channel, used if tomcat is started inprocess
+
+[status:]
+info=Status worker, displays runtime informations
+
+[vm:]
+info=Parameters used to load a JVM in the server process
+#JVM=C:\jdk\jre\bin\hotspot\jvm.dll
+classpath=${TOMCAT_HOME}/bin/tomcat-jni.jar
+classpath=${TOMCAT_HOME}/server/lib/commons-logging.jar
+OPT=-Dtomcat.home=${TOMCAT_HOME}
+OPT=-Dcatalina.home=${TOMCAT_HOME}
+OPT=-Xmx128M
+#OPT=-Djava.compiler=NONE
+disabled=1
+
+[worker.jni:onStartup]
+info=Command to be executed by the VM on startup. This one will start tomcat.
+class=org/apache/jk/apr/TomcatStarter
+ARG=start
+# For Tomcat 5 use the 'stard' for startup argument
+# ARG=stard
+disabled=1
+stdout=${serverRoot}/logs/stdout.log
+stderr=${serverRoot}/logs/stderr.log
+
+[worker.jni:onShutdown]
+info=Command to be executed by the VM on shutdown. This one will stop tomcat.
+class=org/apache/jk/apr/TomcatStarter
+ARG=stop
+disabled=1
+
+[uri:/jkstatus/*]
+info=Display status information and checks the config file for changes.
+group=status:
+
+[uri:127.0.0.1:8003]
+info=Example virtual host. Make sure myVirtualHost is in /etc/hosts to test it
+alias=myVirtualHost:8003
+
+[uri:127.0.0.1:8003/ex]
+info=Example webapp in the virtual host. It'll go to lb_1 ( i.e. localhost:8019 )
+context=/ex
+group=lb_1
+
+[uri:/examples]
+info=Example webapp in the default context.
+context=/examples
+debug=0
+
+[uri:/examples1/*]
+info=A second webapp, this time going to the second tomcat only.
+group=lb_1
+debug=0
+
+[uri:/examples/servlet/*]
+info=Prefix mapping
+
+[uri:/examples/*.jsp]
+info=Extension mapping
+
+[uri:/examples/*]
+info=Map the whole webapp
+
+[uri:/examples/servlet/HelloW]
+info=Example with debug enabled.
+debug=10
+
diff --git a/base/kra/shared/conf/workers2.properties.minimal b/base/kra/shared/conf/workers2.properties.minimal
new file mode 100644
index 000000000..41a0ba6c1
--- /dev/null
+++ b/base/kra/shared/conf/workers2.properties.minimal
@@ -0,0 +1,55 @@
+#
+# This is the minimal JK2 connector configuration file.
+#
+
+[logger]
+info=Native logger
+level=ERROR
+
+[config:]
+file=${serverRoot}/conf/workers2.properties
+debug=0
+debugEnv=0
+
+[uriMap:]
+info=Maps the requests.
+debug=0
+
+[shm:]
+info=Scoreboard. Required for reconfiguration and status with multiprocess servers
+file=anonymous
+debug=0
+
+[workerEnv:]
+info=Global server options
+timing=0
+debug=0
+
+[lb:lb]
+info=Default load balancer.
+debug=0
+
+[channel.socket:localhost:8009]
+info=Ajp13 forwarding over socket
+debug=0
+tomcatId=localhost:8009
+
+[uri:/admin]
+info=Tomcat HTML based administration web application.
+debug=0
+
+[uri:/manager]
+info=A scriptable management web application for the Tomcat Web Server.
+debug=0
+
+[uri:/jsp-examples]
+info=JSP 2.0 Examples.
+debug=0
+
+[uri:/servlets-examples]
+info=Servlet 2.4 Examples.
+debug=0
+
+[uri:/*.jsp]
+info=JSP Extension mapping.
+debug=0
diff --git a/base/kra/shared/etc/init.d/pki-krad b/base/kra/shared/etc/init.d/pki-krad
new file mode 100755
index 000000000..fe3f888b1
--- /dev/null
+++ b/base/kra/shared/etc/init.d/pki-krad
@@ -0,0 +1,87 @@
+#!/bin/bash
+#
+# --- BEGIN COPYRIGHT BLOCK ---
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2007-2010 Red Hat, Inc.
+# All rights reserved.
+# --- END COPYRIGHT BLOCK ---
+#
+# pki-krad Startup script pki-kra with tomcat6
+#
+# chkconfig: - 82 18
+# description: Data Recovery Manager (Tomcat 6.0)
+# processname: pki-krad
+# piddir: /var/run/pki/kra
+#
+
+PROG_NAME=`basename $0`
+SERVICE_NAME="pki-krad"
+SERVICE_PROG="/sbin/service"
+PKI_PATH="/usr/share/pki/kra"
+PKI_REGISTRY="/etc/sysconfig/pki/kra"
+PKI_TYPE="pki-kra"
+PKI_TOTAL_PORTS=6
+
+# Avoid using 'systemctl' for now
+SYSTEMCTL_SKIP_REDIRECT=1
+export SYSTEMCTL_SKIP_REDIRECT
+
+# Disallow 'others' the ability to 'write' to new files
+umask 00002
+
+command="$1"
+pki_instance="$2"
+
+# Source function library.
+. /etc/init.d/functions
+
+# Source the PKI function library
+. /usr/share/pki/scripts/functions
+
+# See how we were called.
+case $command in
+ status)
+ registry_status
+ exit $?
+ ;;
+ start)
+ start
+ exit $?
+ ;;
+ restart)
+ restart
+ exit $?
+ ;;
+ stop)
+ stop
+ exit $?
+ ;;
+ condrestart|force-restart|try-restart)
+ [ ! -f ${lockfile} ] || restart
+ exit $?
+ ;;
+ reload)
+ echo "The 'reload' action is an unimplemented feature."
+ exit ${default_error}
+ ;;
+ *)
+ echo "unknown action ($command)"
+ usage
+ echo "where valid instance names include:"
+ list_instances
+ exit ${default_error}
+ ;;
+esac
+
diff --git a/base/kra/shared/lib/systemd/system/pki-krad.target b/base/kra/shared/lib/systemd/system/pki-krad.target
new file mode 100644
index 000000000..b7027fc72
--- /dev/null
+++ b/base/kra/shared/lib/systemd/system/pki-krad.target
@@ -0,0 +1,8 @@
+[Unit]
+Description=PKI Key Recovery Authority Server
+After=syslog.target network.target
+
+[Install]
+WantedBy=multi-user.target
+
+
diff --git a/base/kra/shared/lib/systemd/system/pki-krad@.service b/base/kra/shared/lib/systemd/system/pki-krad@.service
new file mode 100644
index 000000000..3c4f177a9
--- /dev/null
+++ b/base/kra/shared/lib/systemd/system/pki-krad@.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=PKI Key Recovery Authority Server %i
+After=pki-krad.target
+BindTo=pki-krad.target
+
+[Service]
+Type=forking
+ExecStart=/usr/bin/pkicontrol start kra %i
+ExecStop=/usr/bin/pkicontrol stop kra %i
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/base/kra/shared/webapps/ROOT/WEB-INF/web.xml b/base/kra/shared/webapps/ROOT/WEB-INF/web.xml
new file mode 100644
index 000000000..59245836e
--- /dev/null
+++ b/base/kra/shared/webapps/ROOT/WEB-INF/web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Copyright 2004 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+ version="2.4">
+
+ <display-name>Welcome to Tomcat</display-name>
+ <description>
+ Welcome to Tomcat
+ </description>
+
+</web-app>
+
diff --git a/base/kra/shared/webapps/ROOT/index.jsp b/base/kra/shared/webapps/ROOT/index.jsp
new file mode 100644
index 000000000..4b2b3c60a
--- /dev/null
+++ b/base/kra/shared/webapps/ROOT/index.jsp
@@ -0,0 +1,98 @@
+<!-- --- BEGIN COPYRIGHT BLOCK ---
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Copyright (C) 2010 Red Hat, Inc.
+ All rights reserved.
+ --- END COPYRIGHT BLOCK --- -->
+<%
+ // establish acceptable schemes
+ final String HTTP_SCHEME = "http";
+ final String HTTPS_SCHEME = "https";
+
+ // establish known ports
+ final int EE_HTTP_PORT = [PKI_UNSECURE_PORT];
+ final int AGENT_HTTPS_PORT = [PKI_AGENT_SECURE_PORT];
+ final int EE_HTTPS_PORT = [PKI_EE_SECURE_PORT];
+ final int ADMIN_HTTPS_PORT = [PKI_ADMIN_SECURE_PORT];
+
+ // establish known paths
+ final String ADMIN_PATH = "/[PKI_SUBSYSTEM_TYPE]/services";
+ final String AGENT_PATH = "/[PKI_SUBSYSTEM_TYPE]/agent/[PKI_SUBSYSTEM_TYPE]";
+ final String ERROR_PATH = "/[PKI_SUBSYSTEM_TYPE]/404.html";
+
+ // retrieve scheme from request
+ String scheme = request.getScheme();
+
+ // retrieve client hostname on which the request was sent
+ String client_hostname = request.getServerName();
+
+ // retrieve client port number on which the request was sent
+ int client_port = request.getServerPort();
+
+ // retrieve server hostname on which the request was received
+ String server_hostname = request.getLocalName();
+
+ // retrieve server port number on which the request was received
+ int server_port = request.getLocalPort();
+
+ // uncomment the following lines to write to 'catalina.out'
+ //System.out.println( "scheme = '" + scheme + "'" );
+ //System.out.println( "client hostname = '" + client_hostname + "'" );
+ //System.out.println( "client port = '" + client_port + "'" );
+ //System.out.println( "server hostname = '" + server_hostname + "'" );
+ //System.out.println( "server port = '" + server_port + "'" );
+
+ // compose the appropriate URL
+ String URL = "";
+
+ if( scheme.equals( HTTP_SCHEME ) ) {
+ if( server_port == EE_HTTP_PORT ) {
+ // always redirect to secure admin 'services' port
+ scheme = HTTPS_SCHEME;
+ client_port = ADMIN_HTTPS_PORT;
+ URL = scheme + "://" + client_hostname + ":" + client_port + ADMIN_PATH;
+ } else {
+ // unknown HTTP server port: should never get here
+ URL = scheme + "://" + client_hostname + ":" + client_port + ERROR_PATH;
+
+ // uncomment the following line to write to 'catalina.out'
+ //System.out.println( "Unknown HTTP server port: '" + server_port + "'" );
+ }
+ } else if( scheme.equals( HTTPS_SCHEME ) ) {
+ if( server_port == AGENT_HTTPS_PORT ) {
+ URL = scheme + "://" + client_hostname + ":" + client_port + AGENT_PATH;
+ } else if( server_port == EE_HTTPS_PORT ) {
+ // always redirect to secure admin 'services' port
+ client_port = ADMIN_HTTPS_PORT;
+ URL = scheme + "://" + client_hostname + ":" + client_port + ADMIN_PATH;
+ } else if( server_port == ADMIN_HTTPS_PORT ) {
+ URL = scheme + "://" + client_hostname + ":" + client_port + ADMIN_PATH;
+ } else {
+ // unknown HTTPS server port: should never get here
+ URL = scheme + "://" + client_hostname + ":" + client_port + ERROR_PATH;
+
+ // uncomment the following line to write to 'catalina.out'
+ //System.out.println( "Unknown HTTPS server port: '" + server_port + "'" );
+ }
+ } else {
+ // unacceptable scheme: should never get here
+ URL = scheme + "://" + client_hostname + ":" + client_port + ERROR_PATH;
+
+ // uncomment the following line to write to 'catalina.out'
+ //System.out.println( "Unacceptable scheme: '" + scheme + "'" );
+ }
+
+ // respond (back to browser) with the appropriate redirected URL
+ response.sendRedirect( URL );
+%>
diff --git a/base/kra/shared/webapps/kra/WEB-INF/auth.properties b/base/kra/shared/webapps/kra/WEB-INF/auth.properties
new file mode 100644
index 000000000..a206aa9e4
--- /dev/null
+++ b/base/kra/shared/webapps/kra/WEB-INF/auth.properties
@@ -0,0 +1,16 @@
+# Restful API auth/authz mapping info
+#
+# Format:
+# <Rest API URL> = <ACL Resource ID>,<ACL resource operation>
+# ex: /kra/pki/key/retrieve = certServer.kra.pki.key.retrieve,execute
+
+/kra/pki/key/retrieve = certServer.kra.pki.key.retrieve,execute
+/kra/pki/keyrequests = certServer.kra.pki.keyrequests,read
+/kra/pki/keyrequest = certServer.kra.pki.keyrequest,read
+/kra/pki/keyrequest/archive = certServer.kra.pki.keyrequest.archive,execute
+/kra/pki/keyrequest/recover = certServer.kra.pki.keyrequest.recover,execute
+/kra/pki/keyrequest/approve = certServer.kra.pki.keyrequest.approve,execute
+/kra/pki/keyrequest/reject = certServer.kra.pki.keyrequest.reject,execute
+/kra/pki/keyrequest/cancel = certServer.kra.pki.keyrequest.cancel,execute
+/kra/pki/keys = certServer.kra.pki.keys,read
+/kra/pki/config/cert/transport = certServer.kra.pki.config.cert.transport,read
diff --git a/base/kra/shared/webapps/kra/WEB-INF/velocity.properties b/base/kra/shared/webapps/kra/WEB-INF/velocity.properties
new file mode 100644
index 000000000..2dfae4bca
--- /dev/null
+++ b/base/kra/shared/webapps/kra/WEB-INF/velocity.properties
@@ -0,0 +1,8 @@
+resource.loader = file
+file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
+file.resource.loader.path = [PKI_INSTANCE_PATH]/[PKI_WEBAPPS_NAME]/[PKI_SUBSYSTEM_TYPE]
+file.resource.loader.cache = true
+file.resource.loader.modificationCheckInterval = 2
+input.encoding=UTF-8
+output.encoding=UTF-8
+runtime.log.logsystem.class=org.apache.velocity.runtime.log.NullLogSystem
diff --git a/base/kra/shared/webapps/kra/WEB-INF/web.xml b/base/kra/shared/webapps/kra/WEB-INF/web.xml
new file mode 100644
index 000000000..c6e9934eb
--- /dev/null
+++ b/base/kra/shared/webapps/kra/WEB-INF/web.xml
@@ -0,0 +1,1115 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE web-app
+ PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "file:///usr/share/pki/setup/web-app_2_3.dtd">
+<web-app>
+
+ <filter>
+ <filter-name>AgentRequestFilter</filter-name>
+ <filter-class>com.netscape.cms.servlet.filter.AgentRequestFilter</filter-class>
+ <init-param>
+ <param-name>https_port</param-name>
+ <param-value>[PKI_AGENT_SECURE_PORT]</param-value>
+ </init-param>
+[PKI_OPEN_ENABLE_PROXY_COMMENT]
+ <init-param>
+ <param-name>proxy_port</param-name>
+ <param-value>[PKI_PROXY_SECURE_PORT]</param-value>
+ </init-param>
+[PKI_CLOSE_ENABLE_PROXY_COMMENT]
+ <init-param>
+ <param-name>active</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ </filter>
+
+ <filter>
+ <filter-name>AdminRequestFilter</filter-name>
+ <filter-class>com.netscape.cms.servlet.filter.AdminRequestFilter</filter-class>
+ <init-param>
+ <param-name>https_port</param-name>
+ <param-value>[PKI_ADMIN_SECURE_PORT]</param-value>
+ </init-param>
+[PKI_OPEN_ENABLE_PROXY_COMMENT]
+ <init-param>
+ <param-name>proxy_port</param-name>
+ <param-value>[PKI_PROXY_SECURE_PORT]</param-value>
+ </init-param>
+[PKI_CLOSE_ENABLE_PROXY_COMMENT]
+ <init-param>
+ <param-name>active</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ </filter>
+
+ <filter>
+ <filter-name>EERequestFilter</filter-name>
+ <filter-class>com.netscape.cms.servlet.filter.EERequestFilter</filter-class>
+ <init-param>
+ <param-name>http_port</param-name>
+ <param-value>[PKI_UNSECURE_PORT]</param-value>
+ </init-param>
+ <init-param>
+ <param-name>https_port</param-name>
+ <param-value>[PKI_EE_SECURE_PORT]</param-value>
+ </init-param>
+[PKI_OPEN_ENABLE_PROXY_COMMENT]
+ <init-param>
+ <param-name>proxy_port</param-name>
+ <param-value>[PKI_PROXY_SECURE_PORT]</param-value>
+ </init-param>
+ <init-param>
+ <param-name>proxy_http_port</param-name>
+ <param-value>[PKI_PROXY_UNSECURE_PORT]</param-value>
+ </init-param>
+[PKI_CLOSE_ENABLE_PROXY_COMMENT]
+ <init-param>
+ <param-name>active</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ </filter>
+
+ <servlet>
+ <servlet-name>csadmin-wizard</servlet-name>
+ <servlet-class>com.netscape.cms.servlet.wizard.WizardServlet</servlet-class>
+ <init-param>
+ <param-name>properties</param-name>
+ <param-value>/WEB-INF/velocity.properties</param-value>
+ </init-param>
+ <init-param>
+ <param-name>name</param-name>
+ <param-value>DRM Setup Wizard</param-value>
+ </init-param>
+ <init-param>
+ <param-name>panels</param-name>
+ <param-value>welcome=com.netscape.cms.servlet.csadmin.WelcomePanel,module=com.netscape.cms.servlet.csadmin.ModulePanel,confighsmlogin=com.netscape.cms.servlet.csadmin.ConfigHSMLoginPanel,securitydomain=com.netscape.cms.servlet.csadmin.SecurityDomainPanel,securitydomain=com.netscape.cms.servlet.csadmin.DisplayCertChainPanel,subsystem=com.netscape.cms.servlet.csadmin.CreateSubsystemPanel,restorekeys=com.netscape.cms.servlet.csadmin.RestoreKeyCertPanel,databasepanel=com.netscape.cms.servlet.csadmin.DatabasePanel,sizepanel=com.netscape.cms.servlet.csadmin.SizePanel,namepanel=com.netscape.cms.servlet.csadmin.NamePanel,certrequestpanel=com.netscape.cms.servlet.csadmin.CertRequestPanel,backupkeys=com.netscape.cms.servlet.csadmin.BackupKeyCertPanel,savepk12=com.netscape.cms.servlet.csadmin.SavePKCS12Panel,adminpanel=com.netscape.cms.servlet.csadmin.AdminPanel,importadmincertpanel=com.netscape.cms.servlet.csadmin.ImportAdminCertPanel,donepanel=com.netscape.cms.servlet.csadmin.DonePanel</param-value>
+ </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name>csadmin-login</servlet-name>
+ <servlet-class>com.netscape.cms.servlet.csadmin.LoginServlet</servlet-class>
+ <init-param>
+ <param-name>properties</param-name>
+ <param-value>/WEB-INF/velocity.properties</param-value>
+ </init-param>
+ </servlet>
+
+
+ <servlet>
+ <servlet-name> kraKRADisplayBySerialForRecovery </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.DisplayBySerialForRecovery </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/displayBySerialForRecovery.template </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRADisplayBySerialForRecovery </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraGetConfigEntries </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.csadmin.GetConfigEntries </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> false </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraGetConfigEntries </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> TokenAuth </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.clone.configuration.GetConfigEntries </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRAGrantRecovery </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.GrantRecovery </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/grantRecovery.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRAGrantRecovery </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRAGrantAsyncRecovery </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.GrantAsyncRecovery </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/grantAsyncRecovery.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRAGrantAsyncRecovery </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraports </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.base.PortsServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraports </param-value> </init-param>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> false </param-value> </init-param>
+ <init-param><param-name> interface </param-name>
+ <param-value> ee </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRADisplayTransport </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.DisplayTransport </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRADisplayTransport </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.certificate.transport </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraRegisterUser </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.csadmin.RegisterUser </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> false </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraRegisterUser </param-value> </init-param>
+ <init-param><param-name> GroupName </param-name>
+ <param-value> Data Recovery Manager Agents </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> TokenAuth </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.registerUser </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraGetTransportCert </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.csadmin.GetTransportCert </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> false </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraGetTransportCert </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> TokenAuth </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.getTransportCert </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRARecoverBySerial </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.RecoverBySerial </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/recoverBySerial.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRARecoverBySerial </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraDynamicVariables </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.base.DynamicVariablesServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraDynamicVariables </param-value> </init-param>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> false </param-value> </init-param>
+ <init-param><param-name> dynamicVariables </param-name>
+ <param-value> serverdate=serverdate(),subsystemname=subsystemname(),http=http(),authmgrs=authmgrs(),clacrlurl=clacrlurl() </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraheader </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.base.IndexServlet </servlet-class>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/header.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraheader </param-value> </init-param>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> template </param-name>
+ <param-value> /agent/header.template </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraTokenKeyRecovery </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.connector.TokenKeyRecoveryServlet </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraTokenKeyRecovery </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.TokenKeyRecovery </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraSrchRecoverKey </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.base.DisplayHtmlServlet </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> htmlPath </param-name>
+ <param-value> /agent/kra/SrchRecoverKey.html </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> interface </param-name>
+ <param-value> agent </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/srchKeyForRecovery.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraSrchRecoverKey </param-value> </init-param>
+ <init-param><param-name> unauthorizedTemplate </param-name>
+ <param-value> /agent/kra/GenUnauthorized.template </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraConnector </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.connector.ConnectorServlet </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraConnector </param-value> </init-param>
+ <init-param><param-name> RequestEncoder </param-name>
+ <param-value> com.netscape.cmscore.connector.HttpRequestEncoder </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.connector </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraSrchKey </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.base.DisplayHtmlServlet </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> htmlPath </param-name>
+ <param-value> /agent/kra/SrchKey.html </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> interface </param-name>
+ <param-value> agent </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/srchKey.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraSrchKey </param-value> </init-param>
+ <init-param><param-name> unauthorizedTemplate </param-name>
+ <param-value> /agent/kra/GenUnauthorized.template </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraListRequests </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.base.DisplayHtmlServlet </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> htmlPath </param-name>
+ <param-value> /agent/kra/ListRequests.html </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> interface </param-name>
+ <param-value> agent </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/ListRequests.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraListRequests </param-value> </init-param>
+ <init-param><param-name> unauthorizedTemplate </param-name>
+ <param-value> /agent/kra/GenUnauthorized.template </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraGenerateKeyPair </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.connector.GenerateKeyPairServlet </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraGenerateKeyPair </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.GenerateKeyPair </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraindex </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.base.IndexServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraindex </param-value> </init-param>
+ <init-param><param-name> template </param-name>
+ <param-value> index.template </param-value> </init-param>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRAGetApprovalStatus </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.GetApprovalStatus </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/getApprovalStatus.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRAGetApprovalStatus </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.request.status </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRAProcessReq </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.request.ProcessReq </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> parser </param-name>
+ <param-value> KeyReqParser.PARSER </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/processReq.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRAProcessReq </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.request </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRAExamineRecovery </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.ExamineRecovery </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> interface </param-name>
+ <param-value> agent </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/examineRecovery.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRAExamineRecovery </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRASrchKey </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.SrchKey </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/srchKey.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRASrchKey </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.keys </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRAGetPk12 </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.GetPk12 </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRAGetPk12 </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRAGetAsyncPk12 </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.GetAsyncPk12 </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRAGetAsyncPk12 </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraGrantRecovery </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.base.DisplayHtmlServlet </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> htmlPath </param-name>
+ <param-value> /agent/kra/GrantRecovery.html </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> interface </param-name>
+ <param-value> agent </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/grantRecovery.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraGrantRecovery </param-value> </init-param>
+ <init-param><param-name> unauthorizedTemplate </param-name>
+ <param-value> /agent/kra/GenUnauthorized.template </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRASrchKeyForRecovery </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.SrchKeyForRecovery </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/srchKeyForRecovery.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRASrchKeyForRecovery </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.keys </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> krakraqueryReq </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.request.QueryReq </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> parser </param-name>
+ <param-value> CertReqParser.NODETAIL_PARSER </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/queryReq.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> krakraqueryReq </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.requests </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraKRADisplayBySerial </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.DisplayBySerial </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/displayBySerial.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRADisplayBySerial </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> krapolicy </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.admin.PolicyAdminServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> krapolicy </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ </servlet>
+
+<!--
+ <servlet>
+ <servlet-name> krajobsScheduler </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.admin.JobsAdminServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> krajobsScheduler </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ </servlet>
+-->
+
+ <servlet>
+ <servlet-name> kraauths </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.admin.AuthAdminServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraauths </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> krastart </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.base.CMSStartServlet </servlet-class>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> cfgPath </param-name>
+ <param-value> [PKI_INSTANCE_PATH]/conf/CS.cfg </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> krastart </param-value> </init-param>
+ <load-on-startup> 1 </load-on-startup>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraacl </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.admin.ACLAdminServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraacl </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraug </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.admin.UsrGrpAdminServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraug </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ </servlet>
+
+
+ <servlet>
+ <servlet-name> kraserver </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.admin.CMSAdminServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraserver </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> krakra </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.admin.KRAAdminServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> krakra </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kralog </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.admin.LogAdminServlet </servlet-class>
+ <init-param><param-name> ID </param-name>
+ <param-value> kralog </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> services </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.csadmin.MainPageServlet </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> false </param-value> </init-param>
+ <init-param><param-name> authorityId </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> services </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /services.template </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraUpdateNumberRange </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.csadmin.UpdateNumberRange </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> false </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraUpdateNumberRange </param-value> </init-param>
+ <init-param><param-name> interface </param-name>
+ <param-value> ee </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> TokenAuth </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.clone.configuration.UpdateNumberRange </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraDownloadPKCS12 </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.csadmin.DownloadPKCS12 </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> false </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraDownloadPKCS12 </param-value> </init-param>
+ <init-param><param-name> interface </param-name>
+ <param-value> ee </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> TokenAuth </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.clone.configuration </param-value> </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name> kraGetTokenInfo </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.csadmin.GetTokenInfo </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> false </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraGetTokenInfo </param-value> </init-param>
+ <init-param><param-name> interface </param-name>
+ <param-value> ee </param-value> </init-param>
+ </servlet>
+
+ <context-param>
+ <param-name>resteasy.scan</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>resteasy.servlet.mapping.prefix</param-name>
+ <param-value>/pki</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>resteasy.resource.method-interceptors</param-name>
+ <param-value>
+ org.jboss.resteasy.core.ResourceMethodSecurityInterceptor
+ </param-value>
+ </context-param>
+
+ <servlet>
+ <servlet-name>Resteasy</servlet-name>
+ <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
+ </servlet>
+
+[PKI_OPEN_SEPARATE_PORTS_WEB_COMMENT]
+ <filter-mapping>
+ <filter-name> AgentRequestFilter </filter-name>
+ <url-pattern> /agent/* </url-pattern>
+ </filter-mapping>
+
+ <filter-mapping>
+ <filter-name> AdminRequestFilter </filter-name>
+ <url-pattern> /admin/* </url-pattern>
+ <url-pattern> /auths </url-pattern>
+ <url-pattern> /server </url-pattern>
+ <url-pattern> /log </url-pattern>
+ <url-pattern> /ug </url-pattern>
+ <url-pattern> /acl </url-pattern>
+ <url-pattern> /kra </url-pattern>
+ </filter-mapping>
+
+ <filter-mapping>
+ <filter-name> EERequestFilter </filter-name>
+ <url-pattern> /ee/* </url-pattern>
+ </filter-mapping>
+[PKI_CLOSE_SEPARATE_PORTS_WEB_COMMENT]
+
+ <servlet-mapping>
+ <servlet-name>Resteasy</servlet-name>
+ <url-pattern>/pki/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraserver </servlet-name>
+ <url-pattern> /server </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> krakra </servlet-name>
+ <url-pattern> /kra </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kralog </servlet-name>
+ <url-pattern> /log </url-pattern>
+ </servlet-mapping>
+
+
+ <servlet-mapping>
+ <servlet-name> kraug </servlet-name>
+ <url-pattern> /ug </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> krastart </servlet-name>
+ <url-pattern> /start </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraacl </servlet-name>
+ <url-pattern> /acl </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraauths </servlet-name>
+ <url-pattern> /auths </url-pattern>
+ </servlet-mapping>
+
+<!--
+ <servlet-mapping>
+ <servlet-name> krajobsScheduler </servlet-name>
+ <url-pattern> /jobsScheduler </url-pattern>
+ </servlet-mapping>
+-->
+
+ <servlet-mapping>
+ <servlet-name> krapolicy </servlet-name>
+ <url-pattern> /krapolicy </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRADisplayBySerialForRecovery </servlet-name>
+ <url-pattern> /agent/kra/displayBySerialForRecovery </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRAGrantRecovery </servlet-name>
+ <url-pattern> /agent/kra/grantRecovery </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRAGrantAsyncRecovery </servlet-name>
+ <url-pattern> /agent/kra/grantAsyncRecovery </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraports </servlet-name>
+ <url-pattern> /ee/kra/ports </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRADisplayTransport </servlet-name>
+ <url-pattern> /agent/kra/displayTransportCert </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRARecoverBySerial </servlet-name>
+ <url-pattern> /agent/kra/recoverBySerial </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraDynamicVariables </servlet-name>
+ <url-pattern> /dynamicVars.js </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraheader </servlet-name>
+ <url-pattern> /agent/header </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraTokenKeyRecovery </servlet-name>
+ <url-pattern> /agent/kra/TokenKeyRecovery </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraSrchRecoverKey </servlet-name>
+ <url-pattern> /agent/kra/srchRecoverKey.html </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraConnector </servlet-name>
+ <url-pattern> /agent/kra/connector </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraSrchKey </servlet-name>
+ <url-pattern> /agent/kra/srchKey.html </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraListRequests </servlet-name>
+ <url-pattern> /agent/kra/listRequests.html </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraGenerateKeyPair </servlet-name>
+ <url-pattern> /agent/kra/GenerateKeyPair </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraindex </servlet-name>
+ <url-pattern> /index </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRAGetApprovalStatus </servlet-name>
+ <url-pattern> /agent/kra/getApprovalStatus </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRAProcessReq </servlet-name>
+ <url-pattern> /agent/kra/processReq </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRAExamineRecovery </servlet-name>
+ <url-pattern> /agent/kra/examineRecovery </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRASrchKey </servlet-name>
+ <url-pattern> /agent/kra/srchKey </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRAGetPk12 </servlet-name>
+ <url-pattern> /agent/kra/getPk12 </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRAGetAsyncPk12 </servlet-name>
+ <url-pattern> /agent/kra/getAsyncPk12 </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraGrantRecovery </servlet-name>
+ <url-pattern> /agent/kra/grantRecovery.html </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRASrchKeyForRecovery </servlet-name>
+ <url-pattern> /agent/kra/srchKeyForRecovery </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> krakraqueryReq </servlet-name>
+ <url-pattern> /agent/kra/queryReq </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraKRADisplayBySerial </servlet-name>
+ <url-pattern> /agent/kra/displayBySerial </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>csadmin-login</servlet-name>
+ <url-pattern>/admin/console/config/login</url-pattern>
+ </servlet-mapping>
+
+
+ <servlet-mapping>
+ <servlet-name> kraRegisterUser </servlet-name>
+ <url-pattern> /admin/kra/registerUser </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraGetTransportCert </servlet-name>
+ <url-pattern> /admin/kra/getTransportCert </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>csadmin-wizard</servlet-name>
+ <url-pattern>/admin/console/config/wizard</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraGetConfigEntries </servlet-name>
+ <url-pattern> /admin/kra/getConfigEntries </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> services </servlet-name>
+ <url-pattern> /services </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraUpdateNumberRange </servlet-name>
+ <url-pattern> /ee/kra/updateNumberRange </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraDownloadPKCS12 </servlet-name>
+ <url-pattern> /admin/console/config/savepkcs12 </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name> kraGetTokenInfo </servlet-name>
+ <url-pattern> /ee/kra/getTokenInfo </url-pattern>
+ </servlet-mapping>
+
+ <!-- ==================== Default Session Configuration =============== -->
+ <!-- You can set the default session timeout (in minutes) for all newly -->
+ <!-- created sessions by modifying the value below. -->
+ <!-- -->
+ <!-- To disable session timeouts for this instance, set a value of -1. -->
+
+ <session-config>
+ <session-timeout>30</session-timeout>
+ </session-config>
+
+<!-- Default login configuration uses form-based authentication -->
+<!-- Security Constraint for agent access to the Security Data Rest Interface -->
+
+<!-- Uncomment to activate PKIJNDI realm as in conf/server.xml -->
+<!--
+<security-constraint>
+ <display-name>KRA Top Level Constraint</display-name>
+ <web-resource-collection>
+ <web-resource-name>KRA Protected Area</web-resource-name>
+ <url-pattern>/pki/*
+ </url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+ </user-data-constraint>
+ <auth-constraint>
+ <role-name>*</role-name>
+ </auth-constraint>
+</security-constraint>
+-->
+
+<!-- Security Constraint to deny certain http methods for key/retrieve -->
+<!-- Uncomment to activate PKIJNDI realm as in conf/server.xml -->
+<!--
+<security-constraint>
+<display-name>Key forbidden</display-name>
+<web-resource-collection>
+ <web-resource-name>Key forbidden</web-resource-name>
+ <url-pattern>/pki/key/retrieve</url-pattern>
+ <http-method>GET</http-method>
+ <http-method>PUT</http-method>
+ <http-method>DELETE</http-method>
+</web-resource-collection>
+<auth-constraint/>
+</security-constraint>
+-->
+
+<!-- Security Constraint to deny certain http methods for keyrequest/* -->
+<!-- Uncomment to activate PKIJNDI realm as in conf/server.xml -->
+
+<!--
+<security-constraint>
+<display-name>KeyRequest forbidden</display-name>
+<web-resource-collection>
+ <web-resource-name>KeyRequest forbidden</web-resource-name>
+ <url-pattern>/pki/keyrequest/archive</url-pattern>
+ <url-pattern>/pki/keyrequest/recover</url-pattern>
+ <url-pattern>/pki/keyrequest/approve/*</url-pattern>
+ <url-pattern>/pki/keyrequest/reject/*</url-pattern>
+ <url-pattern>/pki/keyrequest/cancel/*</url-pattern>
+ <http-method>GET</http-method>
+ <http-method>PUT</http-method>
+ <http-method>DELETE</http-method>
+</web-resource-collection>
+<auth-constraint/>
+</security-constraint>
+-->
+
+
+<!-- Customized SSL Client auth login config
+ uncomment to activate PKIJNDI realm as in conf/server.xml
+-->
+
+<!--
+
+<login-config>
+ <realm-name>PKIJNDIRealm</realm-name>
+ <auth-method>CLIENT-CERT</auth-method>
+ <realm-name>Client Cert Protected Area</realm-name>
+</login-config>
+
+<security-role>
+ <role-name>*</role-name>
+</security-role>
+
+-->
+
+</web-app>
diff --git a/base/kra/src/CMakeLists.txt b/base/kra/src/CMakeLists.txt
new file mode 100644
index 000000000..df7e1929b
--- /dev/null
+++ b/base/kra/src/CMakeLists.txt
@@ -0,0 +1,109 @@
+project(pki-kra_java Java)
+
+# '/usr/share/java/pki' jars
+find_file(PKI_CERTSRV_JAR
+ NAMES
+ pki-certsrv.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_CMS_JAR
+ NAMES
+ pki-cms.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_CMSCORE_JAR
+ NAMES
+ pki-cmscore.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_CMSUTIL_JAR
+ NAMES
+ pki-cmsutil.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_NSUTIL_JAR
+ NAMES
+ pki-nsutil.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+ /usr/share/java/pki
+)
+
+
+# '/usr/share/java' jars
+find_file(LDAPJDK_JAR
+ NAMES
+ ldapjdk.jar
+ PATHS
+ /usr/share/java
+)
+
+
+# '${JAVA_LIB_INSTALL_DIR}' jars
+find_file(JSS_JAR
+ NAMES
+ jss4.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+)
+
+find_file(COMMONS_CODEC_JAR
+ NAMES
+ commons-codec.jar
+ PATHS
+ /usr/share/java
+)
+
+find_file(SYMKEY_JAR
+ NAMES
+ symkey.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+)
+
+
+# identify java sources
+set(pki-kra_java_SRCS
+ com/netscape/kra/KeyRecoveryAuthority.java
+ com/netscape/kra/EnrollmentService.java
+ com/netscape/kra/RecoveryService.java
+ com/netscape/kra/SecurityDataRecoveryService.java
+ com/netscape/kra/TokenKeyRecoveryService.java
+ com/netscape/kra/EncryptionUnit.java
+ com/netscape/kra/KRAService.java
+ com/netscape/kra/NetkeyKeygenService.java
+ com/netscape/kra/SecurityDataService.java
+ com/netscape/kra/KRANotify.java
+ com/netscape/kra/KRAPolicy.java
+ com/netscape/kra/TransportKeyUnit.java
+ com/netscape/kra/StorageKeyUnit.java
+ com/netscape/kra/ArchiveOptions.java
+)
+
+
+# set classpath
+set(CMAKE_JAVA_INCLUDE_PATH
+ ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR}
+ ${PKI_CMSUTIL_JAR} ${PKI_NSUTIL_JAR}
+ ${LDAPJDK_JAR}
+ ${JSS_JAR} ${COMMONS_CODEC_JAR} ${SYMKEY_JAR})
+
+
+# set version
+set(CMAKE_JAVA_TARGET_VERSION ${APPLICATION_VERSION})
+
+
+# build pki-kra.jar
+add_jar(pki-kra ${pki-kra_java_SRCS})
+add_dependencies(pki-kra symkey pki-nsutil pki-cmsutil pki-certsrv pki-cms pki-cmscore)
+install_jar(pki-kra ${JAVA_JAR_INSTALL_DIR}/pki)
+set(PKI_KRA_JAR ${pki-kra_JAR_FILE} CACHE INTERNAL "pki-kra jar file")
+
diff --git a/base/kra/src/com/netscape/kra/ArchiveOptions.java b/base/kra/src/com/netscape/kra/ArchiveOptions.java
new file mode 100644
index 000000000..c4650f17e
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/ArchiveOptions.java
@@ -0,0 +1,154 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.pkix.cms.EncryptedContentInfo;
+import org.mozilla.jss.pkix.cms.EnvelopedData;
+import org.mozilla.jss.pkix.cms.RecipientInfo;
+import org.mozilla.jss.pkix.crmf.EncryptedKey;
+import org.mozilla.jss.pkix.crmf.EncryptedValue;
+import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+
+class ArchiveOptions {
+ private String mSymmAlgOID = null;
+ private byte mSymmAlgParams[] = null;
+ private byte mEncSymmKey[] = null;
+ private byte mEncValue[] = null;
+
+ public ArchiveOptions(PKIArchiveOptions opts) throws EBaseException {
+ try {
+ EncryptedKey key = opts.getEncryptedKey();
+ ANY enveloped_val = null;
+ EncryptedValue val = null;
+ AlgorithmIdentifier symmAlg = null;
+
+ if (key.getType() == org.mozilla.jss.pkix.crmf.EncryptedKey.ENVELOPED_DATA) {
+ CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENVELOPED_DATA");
+ // this is the new RFC4211 EncryptedKey that should
+ // have EnvelopedData to replace the deprecated EncryptedValue
+ enveloped_val = key.getEnvelopedData();
+ byte[] env_b = enveloped_val.getEncoded();
+ EnvelopedData.Template env_template = new EnvelopedData.Template();
+ EnvelopedData env_data =
+ (EnvelopedData) env_template.decode(new ByteArrayInputStream(env_b));
+ EncryptedContentInfo eCI = env_data.getEncryptedContentInfo();
+ symmAlg = eCI.getContentEncryptionAlgorithm();
+ mSymmAlgOID = symmAlg.getOID().toString();
+ mSymmAlgParams =
+ ((OCTET_STRING) ((ANY) symmAlg.getParameters()).decodeWith(OCTET_STRING.getTemplate()))
+ .toByteArray();
+
+ SET recipients = env_data.getRecipientInfos();
+ if (recipients.size() <= 0) {
+ CMS.debug("EnrollService: ArchiveOptions() - missing recipient information ");
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
+ "[PKIArchiveOptions] missing recipient information "));
+ }
+ //check recpient - later
+ //we only handle one recipient here anyways. so, either the key
+ //can be decrypted or it can't. No risk here.
+ RecipientInfo ri = (RecipientInfo) recipients.elementAt(0);
+ OCTET_STRING key_o = ri.getEncryptedKey();
+ mEncSymmKey = key_o.toByteArray();
+
+ OCTET_STRING oString = eCI.getEncryptedContent();
+ BIT_STRING encVal = new BIT_STRING(oString.toByteArray(), 0);
+ mEncValue = encVal.getBits();
+ CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENVELOPED_DATA done");
+ } else if (key.getType() == org.mozilla.jss.pkix.crmf.EncryptedKey.ENCRYPTED_VALUE) {
+ CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENCRYPTED_VALUE");
+ // this is deprecated: EncryptedValue
+ val = key.getEncryptedValue();
+ symmAlg = val.getSymmAlg();
+ mSymmAlgOID = symmAlg.getOID().toString();
+ mSymmAlgParams =
+ ((OCTET_STRING) ((ANY) symmAlg.getParameters()).decodeWith(OCTET_STRING.getTemplate()))
+ .toByteArray();
+ BIT_STRING encSymmKey = val.getEncSymmKey();
+
+ mEncSymmKey = encSymmKey.getBits();
+ BIT_STRING encVal = val.getEncValue();
+
+ mEncValue = encVal.getBits();
+ CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENCRYPTED_VALUE done");
+ } else {
+ CMS.debug("EnrollService: ArchiveOptions() invalid EncryptedKey type");
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[PKIArchiveOptions] type "
+ + key.getType()));
+ }
+
+ } catch (InvalidBERException e) {
+ CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
+ "[PKIArchiveOptions]" + e.toString()));
+ } catch (IOException e) {
+ CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
+ throw new EBaseException("ArchiveOptions() exception caught: " +
+ e.toString());
+ } catch (Exception e) {
+ CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
+ throw new EBaseException("ArchiveOptions() exception caught: " +
+ e.toString());
+ }
+
+ }
+
+ static public ArchiveOptions toArchiveOptions(byte options[]) throws
+ EBaseException {
+ ByteArrayInputStream bis = new ByteArrayInputStream(options);
+ PKIArchiveOptions archOpts = null;
+
+ try {
+ archOpts = (PKIArchiveOptions)
+ (new PKIArchiveOptions.Template()).decode(bis);
+ } catch (Exception e) {
+ throw new EBaseException("Failed to decode input PKIArchiveOptions.");
+ }
+
+ return new ArchiveOptions(archOpts);
+
+ }
+
+ public String getSymmAlgOID() {
+ return mSymmAlgOID;
+ }
+
+ public byte[] getSymmAlgParams() {
+ return mSymmAlgParams;
+ }
+
+ public byte[] getEncSymmKey() {
+ return mEncSymmKey;
+ }
+
+ public byte[] getEncValue() {
+ return mEncValue;
+ }
+}
diff --git a/base/kra/src/com/netscape/kra/EncryptionUnit.java b/base/kra/src/com/netscape/kra/EncryptionUnit.java
new file mode 100644
index 000000000..946f57613
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/EncryptionUnit.java
@@ -0,0 +1,741 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.CharConversionException;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.Cipher;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.security.IEncryptionUnit;
+import com.netscape.cmscore.util.Debug;
+
+/**
+ * A class represents the transport key pair. This key pair
+ * is used to protected EE's private key in transit.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+@SuppressWarnings("deprecation")
+public abstract class EncryptionUnit implements IEncryptionUnit {
+
+ /* Establish one constant IV for base class, to be used for
+ internal operations. Constant IV acceptable for symmetric keys.
+ */
+ private byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ protected IVParameterSpec IV = null;
+
+ public EncryptionUnit() {
+ CMS.debug("EncryptionUnit.EncryptionUnit this: " + this.toString());
+
+ IV = new IVParameterSpec(iv);
+ }
+
+ public abstract CryptoToken getToken();
+
+ public abstract CryptoToken getInternalToken();
+
+ public abstract PublicKey getPublicKey();
+
+ public abstract PrivateKey getPrivateKey();
+
+ /**
+ * Protects the private key so that it can be stored in
+ * internal database.
+ */
+ public byte[] encryptInternalPrivate(byte priKey[])
+ throws EBaseException {
+ try {
+ CMS.debug("EncryptionUnit.encryptInternalPrivate");
+ CryptoToken internalToken = getInternalToken();
+
+ // (1) generate session key
+ org.mozilla.jss.crypto.KeyGenerator kg =
+ internalToken.getKeyGenerator(KeyGenAlgorithm.DES3);
+ SymmetricKey sk = kg.generate();
+
+ // (2) wrap private key with session key
+ Cipher cipher = internalToken.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+
+ cipher.initEncrypt(sk, IV);
+ byte pri[] = cipher.doFinal(priKey);
+
+ // (3) wrap session with transport public
+ KeyWrapper rsaWrap = internalToken.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initWrap(getPublicKey(), null);
+ byte session[] = rsaWrap.wrap(sk);
+
+ // use MY own structure for now:
+ // SEQUENCE {
+ // encryptedSession OCTET STRING,
+ // encryptedPrivate OCTET STRING
+ // }
+
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream out = new DerOutputStream();
+
+ tmp.putOctetString(session);
+ tmp.putOctetString(pri);
+ out.write(DerValue.tag_Sequence, tmp);
+
+ return out.toByteArray();
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (CharConversionException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (BadPaddingException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (IllegalBlockSizeException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (Exception e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ }
+ }
+
+ public byte[] wrap(PrivateKey privKey) throws EBaseException {
+ return _wrap(privKey,null);
+ }
+
+ public byte[] wrap(SymmetricKey symmKey) throws EBaseException {
+ return _wrap(null,symmKey);
+ }
+ /**
+ * External unwrapping. Unwraps the data using
+ * the transport private key.
+ */
+ public SymmetricKey unwrap_sym(byte encSymmKey[], SymmetricKey.Usage usage) {
+ try {
+ CryptoToken token = getToken();
+
+ // (1) unwrap the session
+ PrivateKey priKey = getPrivateKey();
+ String priKeyAlgo = priKey.getAlgorithm();
+ CMS.debug("EncryptionUnit::unwrap_sym() private key algo: " + priKeyAlgo);
+ KeyWrapper keyWrapper = null;
+ if (priKeyAlgo.equals("EC")) {
+ keyWrapper = token.getKeyWrapper(KeyWrapAlgorithm.AES_ECB);
+ keyWrapper.initUnwrap(priKey, null);
+ } else {
+ keyWrapper = token.getKeyWrapper(KeyWrapAlgorithm.RSA);
+ keyWrapper.initUnwrap(priKey, null);
+ }
+ SymmetricKey sk = keyWrapper.unwrapSymmetric(encSymmKey,
+ SymmetricKey.DES3, usage,
+ 0);
+ CMS.debug("EncryptionUnit::unwrap_sym() unwrapped on slot: "
+ + token.getName());
+ return sk;
+ } catch (Exception e) {
+ CMS.debug("EncryptionUnit::unwrap_sym() error:" +
+ e.toString());
+ return null;
+ }
+ }
+
+ public SymmetricKey unwrap_sym(byte encSymmKey[]) {
+ return unwrap_sym(encSymmKey, SymmetricKey.Usage.WRAP);
+ }
+
+ public SymmetricKey unwrap_encrypt_sym(byte encSymmKey[]) {
+ return unwrap_sym(encSymmKey, SymmetricKey.Usage.ENCRYPT);
+ }
+
+ /**
+ * Decrypts the user private key.
+ */
+ public byte[] decryptExternalPrivate(byte encSymmKey[],
+ String symmAlgOID, byte symmAlgParams[],
+ byte encValue[])
+ throws EBaseException {
+ try {
+
+ CMS.debug("EncryptionUnit.decryptExternalPrivate");
+ CryptoToken token = getToken();
+
+ // (1) unwrap the session
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(encSymmKey,
+ SymmetricKey.DES3, SymmetricKey.Usage.DECRYPT,
+ 0);
+
+ // (2) unwrap the pri
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD // XXX
+ );
+
+ cipher.initDecrypt(sk, new IVParameterSpec(
+ symmAlgParams));
+ return cipher.doFinal(encValue);
+ } catch (IllegalBlockSizeException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (BadPaddingException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (Exception e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * External unwrapping. Unwraps the symmetric key using
+ * the transport private key.
+ */
+ public SymmetricKey unwrap_symmetric(byte encSymmKey[],
+ String symmAlgOID, byte symmAlgParams[],
+ byte encValue[])
+ throws EBaseException {
+ try {
+ CryptoToken token = getToken();
+
+ // (1) unwrap the session
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(encSymmKey,
+ SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP,
+ 0);
+
+ // (2) unwrap the sym key
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD // XXX
+ );
+
+ wrapper.initUnwrap(sk, new IVParameterSpec(
+ symmAlgParams));
+
+ SymmetricKey symKey = wrapper.unwrapSymmetric(encValue, SymmetricKey.DES3, SymmetricKey.Usage.DECRYPT, 0);
+
+ return symKey;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (Exception e) {
+ CMS.debug("EncryptionUnit.unwrap : Exception:" + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * External unwrapping. Unwraps the data using
+ * the transport private key.
+ */
+ public PrivateKey unwrap(byte encSymmKey[],
+ String symmAlgOID, byte symmAlgParams[],
+ byte encValue[], PublicKey pubKey)
+ throws EBaseException {
+ try {
+ CryptoToken token = getToken();
+
+ // (1) unwrap the session
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(encSymmKey,
+ SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP,
+ 0);
+
+ // (2) unwrap the pri
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD // XXX
+ );
+
+ wrapper.initUnwrap(sk, new IVParameterSpec(
+ symmAlgParams));
+
+ PrivateKey.Type keytype = null;
+ String alg = pubKey.getAlgorithm();
+ if (alg.equals("DSA")) {
+ keytype = PrivateKey.DSA;
+ } else if (alg.equals("EC")) {
+ keytype = PrivateKey.EC;
+ } else {
+ keytype = PrivateKey.RSA;
+ }
+ PrivateKey pk = wrapper.unwrapTemporaryPrivate(encValue,
+ keytype , pubKey);
+
+ return pk;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (Exception e) {
+ CMS.debug("EncryptionUnit.unwrap : Exception:"+e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * External unwrapping. Unwraps the data using
+ * the transport private key.
+ */
+
+ public byte[] decryptInternalPrivate(byte wrappedKeyData[])
+ throws EBaseException {
+ try {
+ CMS.debug("EncryptionUnit.decryptInternalPrivate");
+ DerValue val = new DerValue(wrappedKeyData);
+ // val.tag == DerValue.tag_Sequence
+ DerInputStream in = val.data;
+ DerValue dSession = in.getDerValue();
+ byte session[] = dSession.getOctetString();
+ DerValue dPri = in.getDerValue();
+ byte pri[] = dPri.getOctetString();
+
+ CryptoToken token = getToken();
+
+ // (1) unwrap the session
+ CMS.debug("decryptInternalPrivate(): getting key wrapper on slot:" + token.getName());
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(session,
+ SymmetricKey.DES3, SymmetricKey.Usage.DECRYPT, 0);
+
+ // (2) unwrap the pri
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+
+ cipher.initDecrypt(sk, IV);
+ return cipher.doFinal(pri);
+ } catch (IllegalBlockSizeException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (BadPaddingException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (Exception e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * External unwrapping of stored symmetric key.
+ */
+ public SymmetricKey unwrap(byte wrappedKeyData[])
+ throws EBaseException {
+ try {
+ DerValue val = new DerValue(wrappedKeyData);
+ // val.tag == DerValue.tag_Sequence
+ DerInputStream in = val.data;
+ DerValue dSession = in.getDerValue();
+ byte session[] = dSession.getOctetString();
+ DerValue dPri = in.getDerValue();
+ byte pri[] = dPri.getOctetString();
+
+ CryptoToken token = getToken();
+ // (1) unwrap the session key
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(session,
+ SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP, 0);
+
+ // (2) unwrap the symmetric key
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+
+ wrapper.initUnwrap(sk, IV);
+
+ SymmetricKey sk_ret = wrapper.unwrapSymmetric(pri,
+ SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP,
+ 0);
+
+ return sk_ret;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ CMS.debug(e);
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.printStackTrace(e);
+ return null;
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (Exception e) {
+ Debug.printStackTrace(e);
+ return null;
+ }
+ }
+
+ /**
+ * Internal unwrapping.
+ */
+ public PrivateKey unwrap_temp(byte wrappedKeyData[], PublicKey pubKey)
+ throws EBaseException {
+ return _unwrap(wrappedKeyData, pubKey, true);
+ }
+
+ /**
+ * Internal unwrapping.
+ */
+ public PrivateKey unwrap(byte wrappedKeyData[], PublicKey pubKey)
+ throws EBaseException {
+ return _unwrap(wrappedKeyData, pubKey, false);
+ }
+
+ /**
+ * Internal unwrapping.
+ */
+ private PrivateKey _unwrap(byte wrappedKeyData[], PublicKey
+ pubKey, boolean temporary)
+ throws EBaseException {
+ try {
+ DerValue val = new DerValue(wrappedKeyData);
+ // val.tag == DerValue.tag_Sequence
+ DerInputStream in = val.data;
+ DerValue dSession = in.getDerValue();
+ byte session[] = dSession.getOctetString();
+ DerValue dPri = in.getDerValue();
+ byte pri[] = dPri.getOctetString();
+
+ CryptoToken token = getToken();
+ // (1) unwrap the session
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(session,
+ SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP, 0);
+
+ // (2) unwrap the pri
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+
+ wrapper.initUnwrap(sk, IV);
+
+ PrivateKey pk = null;
+ if (temporary) {
+ pk = wrapper.unwrapTemporaryPrivate(pri,
+ PrivateKey.RSA, pubKey);
+ } else {
+ pk = wrapper.unwrapPrivate(pri,
+ PrivateKey.RSA, pubKey);
+ }
+ return pk;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ CMS.debug(e);
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.printStackTrace(e);
+ return null;
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (Exception e) {
+ Debug.printStackTrace(e);
+ return null;
+ }
+ }
+
+ /***
+ * Internal wrap, accounts for either private or symmetric key
+ */
+ private byte[] _wrap(PrivateKey priKey, SymmetricKey symmKey) throws EBaseException {
+ try {
+ if ((priKey == null && symmKey == null) || (priKey != null && symmKey != null)) {
+ return null;
+ }
+ CMS.debug("EncryptionUnit.wrap interal.");
+ CryptoToken token = getToken();
+
+ // (1) generate session key
+ org.mozilla.jss.crypto.KeyGenerator kg =
+ token.getKeyGenerator(KeyGenAlgorithm.DES3);
+ // internalToken.getKeyGenerator(KeyGenAlgorithm.DES3);
+ SymmetricKey.Usage usages[] = new SymmetricKey.Usage[2];
+ usages[0] = SymmetricKey.Usage.WRAP;
+ usages[1] = SymmetricKey.Usage.UNWRAP;
+ kg.setKeyUsages(usages);
+ kg.temporaryKeys(true);
+ SymmetricKey sk = kg.generate();
+ CMS.debug("EncryptionUnit:wrap() session key generated on slot: " + token.getName());
+
+ // (2) wrap private key with session key
+ // KeyWrapper wrapper = internalToken.getKeyWrapper(
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+
+ wrapper.initWrap(sk, IV);
+
+ byte pri[] = null;
+
+ if ( priKey != null) {
+ pri = wrapper.wrap(priKey);
+ } else if ( symmKey != null) {
+ pri = wrapper.wrap(symmKey);
+ }
+ CMS.debug("EncryptionUnit:wrap() privKey wrapped");
+
+ // (3) wrap session with transport public
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initWrap(getPublicKey(), null);
+ byte session[] = rsaWrap.wrap(sk);
+ CMS.debug("EncryptionUnit:wrap() sessin key wrapped");
+
+ // use MY own structure for now:
+ // SEQUENCE {
+ // encryptedSession OCTET STRING,
+ // encryptedPrivate OCTET STRING
+ // }
+
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream out = new DerOutputStream();
+
+ tmp.putOctetString(session);
+ tmp.putOctetString(pri);
+ out.write(DerValue.tag_Sequence, tmp);
+
+ return out.toByteArray();
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (CharConversionException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (Exception e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * Verify the given key pair.
+ */
+ public void verify(PublicKey publicKey, PrivateKey privateKey) throws
+ EBaseException {
+ }
+}
diff --git a/base/kra/src/com/netscape/kra/EnrollmentService.java b/base/kra/src/com/netscape/kra/EnrollmentService.java
new file mode 100644
index 000000000..37d1aea53
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/EnrollmentService.java
@@ -0,0 +1,872 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.cert.CertificateException;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import netscape.security.provider.RSAPublicKey;
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.x509.CertificateSubjectName;
+import netscape.security.x509.CertificateX509Key;
+import netscape.security.x509.X509CertInfo;
+import netscape.security.x509.X509Key;
+
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.pkix.crmf.CertReqMsg;
+import org.mozilla.jss.pkix.crmf.CertRequest;
+import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
+import org.mozilla.jss.pkix.primitive.AVA;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.AuthToken;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.SessionContext;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.certsrv.kra.EKRAException;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.kra.ProofOfArchival;
+import com.netscape.certsrv.logging.AuditFormat;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.profile.IEnrollProfile;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.certsrv.security.ITransportKeyUnit;
+import com.netscape.certsrv.util.IStatsSubsystem;
+import com.netscape.cmscore.crmf.CRMFParser;
+import com.netscape.cmscore.crmf.PKIArchiveOptionsContainer;
+import com.netscape.kra.ArchiveOptions;
+import com.netscape.cmscore.dbs.KeyRecord;
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * A class represents archival request processor. It
+ * passes the request to the policy processor, and
+ * process the request according to the policy decision.
+ * <P>
+ * If policy returns ACCEPTED, the request will be processed immediately.
+ * <P>
+ * Upon processing, the incoming user key is unwrapped with the transport key of KRA, and then wrapped with the storage
+ * key. The encrypted key is stored in the internal database for long term storage.
+ * <P>
+ *
+ * @author thomask (original)
+ * @author cfu (non-RSA keys; private keys secure handling);
+ * @version $Revision$, $Date$
+ */
+public class EnrollmentService implements IService {
+
+ // constants
+ public static final String CRMF_REQUEST = "CRMFRequest";
+ public final static String ATTR_KEY_RECORD = "keyRecord";
+ public final static String ATTR_PROOF_OF_ARCHIVAL =
+ "proofOfArchival";
+
+ // private
+ private IKeyRecoveryAuthority mKRA = null;
+ private ITransportKeyUnit mTransportUnit = null;
+ private IStorageKeyUnit mStorageUnit = null;
+ private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+
+ private final static byte EOL[] = { Character.LINE_SEPARATOR };
+ private final static String LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_4";
+ private final static String LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED_3";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_4";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_4";
+
+ /**
+ * Constructs request processor.
+ * <P>
+ *
+ * @param kra key recovery authority
+ */
+ public EnrollmentService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mTransportUnit = kra.getTransportKeyUnit();
+ mStorageUnit = kra.getStorageKeyUnit();
+ }
+
+ public PKIArchiveOptions toPKIArchiveOptions(byte options[]) {
+ ByteArrayInputStream bis = new ByteArrayInputStream(options);
+ PKIArchiveOptions archOpts = null;
+
+ try {
+ archOpts = (PKIArchiveOptions)
+ (new PKIArchiveOptions.Template()).decode(bis);
+ } catch (Exception e) {
+ CMS.debug("EnrollProfile: getPKIArchiveOptions " + e.toString());
+ }
+ return archOpts;
+ }
+
+ /**
+ * Services an enrollment/archival request.
+ * <P>
+ *
+ * @param request enrollment request
+ * @return serving successful or not
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest request)
+ throws EBaseException {
+
+ IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats");
+ if (statsSub != null) {
+ statsSub.startTiming("archival", true /* main action */);
+ }
+
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRequesterID = auditRequesterID();
+ String auditArchiveID = ILogger.UNIDENTIFIED;
+ String auditPublicKey = ILogger.UNIDENTIFIED;
+
+ String id = request.getRequestId().toString();
+ if (id != null) {
+ auditArchiveID = id.trim();
+ }
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentServlet: KRA services enrollment request");
+
+ SessionContext sContext = SessionContext.getContext();
+ String agentId = (String) sContext.get(SessionContext.USER_ID);
+ AuthToken authToken = (AuthToken) sContext.get(SessionContext.AUTH_TOKEN);
+
+ mKRA.log(ILogger.LL_INFO, "KRA services enrollment request");
+ // unwrap user key with transport
+ byte unwrapped[] = null;
+ PKIArchiveOptionsContainer aOpts[] = null;
+
+ String profileId = request.getExtDataInString("profileId");
+
+ if (profileId == null || profileId.equals("")) {
+ try {
+ aOpts = CRMFParser.getPKIArchiveOptions(
+ request.getExtDataInString(IRequest.HTTP_PARAMS, CRMF_REQUEST));
+ } catch (IOException e) {
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PRIVATE_KEY"));
+ }
+ } else {
+ // profile-based request
+ PKIArchiveOptions options = (PKIArchiveOptions)
+ toPKIArchiveOptions(
+ request.getExtDataInByteArray(IEnrollProfile.REQUEST_ARCHIVE_OPTIONS));
+
+ aOpts = new PKIArchiveOptionsContainer[1];
+ aOpts[0] = new PKIArchiveOptionsContainer(options,
+ 0/* not matter */);
+
+ request.setExtData("dbStatus", "NOT_UPDATED");
+ }
+
+ for (int i = 0; i < aOpts.length; i++) {
+ ArchiveOptions opts = new ArchiveOptions(aOpts[i].mAO);
+
+ if (statsSub != null) {
+ statsSub.startTiming("decrypt_user_key");
+ }
+ mKRA.log(ILogger.LL_INFO, "KRA decrypts external private");
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentService::about to decryptExternalPrivate");
+ unwrapped = mTransportUnit.decryptExternalPrivate(
+ opts.getEncSymmKey(),
+ opts.getSymmAlgOID(),
+ opts.getSymmAlgParams(),
+ opts.getEncValue());
+ if (statsSub != null) {
+ statsSub.endTiming("decrypt_user_key");
+ }
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentService::finished decryptExternalPrivate");
+ if (unwrapped == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_UNWRAP_USER_KEY"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PRIVATE_KEY"));
+ }
+
+ // retrieve pubic key
+ X509Key publicKey = getPublicKey(request, aOpts[i].mReqPos);
+ byte publicKeyData[] = publicKey.getEncoded();
+
+ if (publicKeyData == null) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_PUBLIC_NOT_FOUND"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PUBLIC_KEY"));
+ }
+
+ /* Bugscape #54948 - verify public and private key before archiving key */
+
+ if (statsSub != null) {
+ statsSub.startTiming("verify_key");
+ }
+ if (verifyKeyPair(publicKeyData, unwrapped) == false) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_PUBLIC_NOT_FOUND"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PUBLIC_KEY"));
+ }
+ if (statsSub != null) {
+ statsSub.endTiming("verify_key");
+ }
+
+ /**
+ * mTransportKeyUnit.verify(pKey, unwrapped);
+ **/
+ // retrieve owner name
+ String owner = getOwnerName(request, aOpts[i].mReqPos);
+
+ if (owner == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_OWNER_NAME_NOT_FOUND"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_KEYRECORD"));
+ }
+
+ //
+ // privateKeyData ::= SEQUENCE {
+ // sessionKey OCTET_STRING,
+ // encKey OCTET_STRING,
+ // }
+ //
+ mKRA.log(ILogger.LL_INFO, "KRA encrypts internal private");
+ if (statsSub != null) {
+ statsSub.startTiming("encrypt_user_key");
+ }
+ byte privateKeyData[] = mStorageUnit.encryptInternalPrivate(
+ unwrapped);
+ if (statsSub != null) {
+ statsSub.endTiming("encrypt_user_key");
+ }
+
+ if (privateKeyData == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_WRAP_USER_KEY"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PRIVATE_KEY"));
+ }
+
+ // create key record
+ KeyRecord rec = new KeyRecord(null, publicKeyData,
+ privateKeyData, owner,
+ publicKey.getAlgorithmId().getOID().toString(), agentId);
+
+ // we deal with RSA key only
+ try {
+ RSAPublicKey rsaPublicKey = new RSAPublicKey(publicKeyData);
+
+ rec.setKeySize(Integer.valueOf(rsaPublicKey.getKeySize()));
+ } catch (InvalidKeyException e) {
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_KEYRECORD"));
+ }
+
+ // if record alreay has a serial number, yell out.
+ if (rec.getSerialNumber() != null) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_INVALID_SERIAL_NUMBER",
+ rec.getSerialNumber().toString()));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"));
+ }
+ IKeyRepository storage = mKRA.getKeyRepository();
+ BigInteger serialNo = storage.getNextSerialNumber();
+
+ if (serialNo == null) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_NEXT_SERIAL"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"));
+ }
+ if (i == 0) {
+ rec.set(KeyRecord.ATTR_ID, serialNo);
+ request.setExtData(ATTR_KEY_RECORD, serialNo);
+ } else {
+ rec.set(KeyRecord.ATTR_ID + i, serialNo);
+ request.setExtData(ATTR_KEY_RECORD + i, serialNo);
+ }
+
+ mKRA.log(ILogger.LL_INFO, "KRA adding key record " + serialNo);
+ if (statsSub != null) {
+ statsSub.startTiming("store_key");
+ }
+ storage.addKeyRecord(rec);
+ if (statsSub != null) {
+ statsSub.endTiming("store_key");
+ }
+
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentService: key record 0x" + serialNo.toString(16)
+ + " (" + owner + ") archived");
+
+ mKRA.log(ILogger.LL_INFO, "key record 0x" +
+ serialNo.toString(16)
+ + " (" + owner + ") archived");
+
+ // for audit log
+ String authMgr = AuditFormat.NOAUTH;
+
+ if (authToken != null) {
+ authMgr =
+ authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME);
+ }
+ CMS.getLogger().log(ILogger.EV_AUDIT,
+ ILogger.S_KRA,
+ AuditFormat.LEVEL,
+ AuditFormat.FORMAT,
+ new Object[] {
+ IRequest.KEYARCHIVAL_REQUEST,
+ request.getRequestId(),
+ AuditFormat.FROMAGENT + " agentID: " + agentId,
+ authMgr,
+ "completed",
+ owner,
+ "serial number: 0x" + serialNo.toString(16) }
+ );
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+
+ // store a message in the signed audit log file
+ auditPublicKey = auditPublicKey(rec);
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditPublicKey);
+
+ audit(auditMessage);
+
+ // Xxx - should sign this proof of archival
+ ProofOfArchival mProof = new ProofOfArchival(serialNo,
+ owner, mKRA.getX500Name().toString(),
+ rec.getCreateTime());
+
+ DerOutputStream mProofOut = new DerOutputStream();
+ mProof.encode(mProofOut);
+ if (i == 0) {
+ request.setExtData(ATTR_PROOF_OF_ARCHIVAL,
+ mProofOut.toByteArray());
+ } else {
+ request.setExtData(ATTR_PROOF_OF_ARCHIVAL + i,
+ mProofOut.toByteArray());
+ }
+
+ } // for
+
+ /*
+ request.delete(IEnrollProfile.REQUEST_SUBJECT_NAME);
+ request.delete(IEnrollProfile.REQUEST_EXTENSIONS);
+ request.delete(IEnrollProfile.REQUEST_VALIDITY);
+ request.delete(IEnrollProfile.REQUEST_KEY);
+ request.delete(IEnrollProfile.REQUEST_SIGNING_ALGORITHM);
+ request.delete(IEnrollProfile.REQUEST_LOCALE);
+ */
+
+ request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS);
+
+ // update request
+ mKRA.log(ILogger.LL_INFO, "KRA updating request");
+ mKRA.getRequestQueue().updateRequest(request);
+
+ if (statsSub != null) {
+ statsSub.endTiming("archival");
+ }
+
+ return true;
+ }
+
+ public boolean verifyKeyPair(byte publicKeyData[], byte privateKeyData[]) {
+ try {
+ DerValue publicKeyVal = new DerValue(publicKeyData);
+ DerInputStream publicKeyIn = publicKeyVal.data;
+ publicKeyIn.getSequence(0);
+ DerValue publicKeyDer = new DerValue(publicKeyIn.getBitString());
+ DerInputStream publicKeyDerIn = publicKeyDer.data;
+ BigInt publicKeyModulus = publicKeyDerIn.getInteger();
+ BigInt publicKeyExponent = publicKeyDerIn.getInteger();
+
+ DerValue privateKeyVal = new DerValue(privateKeyData);
+ if (privateKeyVal.tag != DerValue.tag_Sequence)
+ return false;
+ DerInputStream privateKeyIn = privateKeyVal.data;
+ privateKeyIn.getInteger();
+ privateKeyIn.getSequence(0);
+ DerValue privateKeyDer = new DerValue(privateKeyIn.getOctetString());
+ DerInputStream privateKeyDerIn = privateKeyDer.data;
+
+ @SuppressWarnings("unused")
+ BigInt privateKeyVersion = privateKeyDerIn.getInteger();
+ BigInt privateKeyModulus = privateKeyDerIn.getInteger();
+ BigInt privateKeyExponent = privateKeyDerIn.getInteger();
+
+ if (!publicKeyModulus.equals(privateKeyModulus)) {
+ CMS.debug("verifyKeyPair modulus mismatch publicKeyModulus="
+ + publicKeyModulus + " privateKeyModulus=" + privateKeyModulus);
+ return false;
+ }
+
+ if (!publicKeyExponent.equals(privateKeyExponent)) {
+ CMS.debug("verifyKeyPair exponent mismatch publicKeyExponent="
+ + publicKeyExponent + " privateKeyExponent=" + privateKeyExponent);
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ CMS.debug("verifyKeyPair error " + e);
+ return false;
+ }
+ }
+
+ private static final OBJECT_IDENTIFIER PKIARCHIVEOPTIONS_OID =
+ new OBJECT_IDENTIFIER(new long[] { 1, 3, 6, 1, 5, 5, 7, 5, 1, 4 }
+ );
+
+ /**
+ * Retrieves PKIArchiveOptions from CRMF request.
+ *
+ * @param crmfBlob CRMF request
+ * @return PKIArchiveOptions
+ * @exception EBaseException failed to extrace option
+ */
+ public static PKIArchiveOptionsContainer[] getPKIArchiveOptions(String crmfBlob)
+ throws EBaseException {
+ Vector<PKIArchiveOptionsContainer> options = new Vector<PKIArchiveOptionsContainer>();
+
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentService::getPKIArchiveOptions> crmfBlob=" + crmfBlob);
+ byte[] crmfBerBlob = null;
+
+ crmfBerBlob = Utils.base64decode(crmfBlob);
+ ByteArrayInputStream crmfBerBlobIn = new
+ ByteArrayInputStream(crmfBerBlob);
+ SEQUENCE crmfmsgs = null;
+
+ try {
+ crmfmsgs = (SEQUENCE) new
+ SEQUENCE.OF_Template(new
+ CertReqMsg.Template()).decode(
+ crmfBerBlobIn);
+ } catch (IOException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[crmf msgs]" + e.toString()));
+ } catch (InvalidBERException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[crmf msgs]" + e.toString()));
+ }
+
+ for (int z = 0; z < crmfmsgs.size(); z++) {
+ CertReqMsg certReqMsg = (CertReqMsg)
+ crmfmsgs.elementAt(z);
+ CertRequest certReq = certReqMsg.getCertReq();
+
+ // try to locate PKIArchiveOption control
+ AVA archAva = null;
+
+ try {
+ for (int i = 0; i < certReq.numControls(); i++) {
+ AVA ava = certReq.controlAt(i);
+ OBJECT_IDENTIFIER oid = ava.getOID();
+
+ if (oid.equals(PKIARCHIVEOPTIONS_OID)) {
+ archAva = ava;
+ break;
+ }
+ }
+ } catch (Exception e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "no PKIArchiveOptions found "
+ + e.toString()));
+ }
+ if (archAva != null) {
+
+ ASN1Value archVal = archAva.getValue();
+ ByteArrayInputStream bis = new ByteArrayInputStream(ASN1Util.encode(archVal));
+ PKIArchiveOptions archOpts = null;
+
+ try {
+ archOpts = (PKIArchiveOptions)
+ (new PKIArchiveOptions.Template()).decode(bis);
+ } catch (IOException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
+ "[PKIArchiveOptions]" + e.toString()));
+ } catch (InvalidBERException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
+ "[PKIArchiveOptions]" + e.toString()));
+ }
+ options.addElement(new PKIArchiveOptionsContainer(archOpts, z));
+ }
+ }
+ if (options.size() == 0) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "PKIArchiveOptions found"));
+ } else {
+ PKIArchiveOptionsContainer p[] = new PKIArchiveOptionsContainer[options.size()];
+
+ options.copyInto(p);
+ return p;
+ }
+ }
+
+ /**
+ * Retrieves public key from request.
+ *
+ * @param request CRMF request
+ * @return JSS public key
+ * @exception EBaseException failed to retrieve public key
+ */
+ private X509Key getPublicKey(IRequest request, int i) throws EBaseException {
+ String profileId = request.getExtDataInString("profileId");
+
+ if (profileId != null && !profileId.equals("")) {
+ byte[] certKeyData = request.getExtDataInByteArray(IEnrollProfile.REQUEST_KEY);
+ if (certKeyData != null) {
+ try {
+ CertificateX509Key x509key = new CertificateX509Key(
+ new ByteArrayInputStream(certKeyData));
+
+ return (X509Key) x509key.get(CertificateX509Key.KEY);
+ } catch (Exception e1) {
+ CMS.debug("EnrollService: (Archival) getPublicKey " +
+ e1.toString());
+ }
+ }
+ return null;
+ }
+
+ // retrieve x509 Key from request
+ X509CertInfo certInfo[] =
+ request.getExtDataInCertInfoArray(IRequest.CERT_INFO);
+ CertificateX509Key pX509Key = null;
+
+ try {
+ pX509Key = (CertificateX509Key)
+ certInfo[i].get(X509CertInfo.KEY);
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_PUBLIC_KEY", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
+ "[" + X509CertInfo.KEY + "]" + e.toString()));
+ } catch (CertificateException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_PUBLIC_KEY", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
+ "[" + X509CertInfo.KEY + "]" + e.toString()));
+ }
+ X509Key pKey = null;
+
+ try {
+ pKey = (X509Key) pX509Key.get(
+ CertificateX509Key.KEY);
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_PUBLIC_KEY", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "["
+ + CertificateX509Key.KEY + "]" + e.toString()));
+ }
+ return pKey;
+ }
+
+ /**
+ * Retrieves key's owner name from request.
+ *
+ * @param request CRMF request
+ * @return owner name (subject name)
+ * @exception EBaseException failed to retrieve public key
+ */
+ private String getOwnerName(IRequest request, int i)
+ throws EBaseException {
+
+ String profileId = request.getExtDataInString("profileId");
+
+ if (profileId != null && !profileId.equals("")) {
+ CertificateSubjectName sub = request.getExtDataInCertSubjectName(
+ IEnrollProfile.REQUEST_SUBJECT_NAME);
+ if (sub != null) {
+ return sub.toString();
+ }
+ }
+
+ X509CertInfo certInfo[] =
+ request.getExtDataInCertInfoArray(IRequest.CERT_INFO);
+ CertificateSubjectName pSub = null;
+
+ try {
+ pSub = (CertificateSubjectName)
+ certInfo[0].get(X509CertInfo.SUBJECT);
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_OWNER_NAME", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "["
+ + X509CertInfo.SUBJECT + "]" + e.toString()));
+ } catch (CertificateException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_OWNER_NAME", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "["
+ + X509CertInfo.SUBJECT + "]" + e.toString()));
+ }
+ String owner = pSub.toString();
+
+ return owner;
+ }
+
+ /**
+ * Signed Audit Log Public Key
+ *
+ * This method is called to obtain the public key from the passed in
+ * "KeyRecord" for a signed audit log message.
+ * <P>
+ *
+ * @param rec a Key Record
+ * @return key string containing the certificate's public key
+ */
+ private String auditPublicKey(KeyRecord rec) {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ if (rec == null) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ byte rawData[] = null;
+
+ try {
+ rawData = rec.getPublicKeyData();
+ } catch (EBaseException e) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ String key = "";
+
+ // convert "rawData" into "base64Data"
+ if (rawData != null) {
+ String base64Data = null;
+
+ base64Data = CMS.BtoA(rawData).trim();
+
+ // extract all line separators from the "base64Data"
+ StringTokenizer st = new StringTokenizer(base64Data, "\r\n");
+ while (st.hasMoreTokens()) {
+ key += st.nextToken();
+ }
+ }
+
+ key = key.trim();
+
+ if (key.equals("")) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ } else {
+ return key;
+ }
+ }
+
+ /**
+ * Signed Audit Log Subject ID
+ *
+ * This method is called to obtain the "SubjectID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message SubjectID
+ */
+
+ private String auditSubjectID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String subjectID = null;
+
+ // Initialize subjectID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ subjectID = (String)
+ auditContext.get(SessionContext.USER_ID);
+
+ if (subjectID != null) {
+ subjectID = subjectID.trim();
+ } else {
+ subjectID = ILogger.NONROLEUSER;
+ }
+ } else {
+ subjectID = ILogger.UNIDENTIFIED;
+ }
+
+ return subjectID;
+ }
+
+ /**
+ * Signed Audit Log Requester ID
+ *
+ * This method is called to obtain the "RequesterID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message RequesterID
+ */
+ private String auditRequesterID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String requesterID = null;
+
+ // Initialize requesterID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ requesterID = (String)
+ auditContext.get(SessionContext.REQUESTER_ID);
+
+ if (requesterID != null) {
+ requesterID = requesterID.trim();
+ } else {
+ requesterID = ILogger.UNIDENTIFIED;
+ }
+ } else {
+ requesterID = ILogger.UNIDENTIFIED;
+ }
+
+ return requesterID;
+ }
+
+ /**
+ * Signed Audit Log
+ *
+ * This method is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ private void audit(String msg) {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if (mSignedAuditLogger == null) {
+ return;
+ }
+
+ mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg);
+ }
+}
diff --git a/base/kra/src/com/netscape/kra/KRANotify.java b/base/kra/src/com/netscape/kra/KRANotify.java
new file mode 100644
index 000000000..29eaf477a
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/KRANotify.java
@@ -0,0 +1,50 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.request.ARequestNotifier;
+
+/**
+ * A class represents a KRA request queue notify. This
+ * object will be invoked by the request subsystem
+ * when a request is requested for processing.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class KRANotify extends ARequestNotifier {
+ private IKeyRecoveryAuthority mKRA = null;
+
+ /**
+ * default constructor
+ */
+ public KRANotify() {
+ super();
+ }
+
+ /**
+ * Creates KRA notify.
+ */
+ public KRANotify(IKeyRecoveryAuthority kra) {
+ super();
+ mKRA = kra;
+ }
+
+ // XXX may want to do something else with mKRA ?
+}
diff --git a/base/kra/src/com/netscape/kra/KRAPolicy.java b/base/kra/src/com/netscape/kra/KRAPolicy.java
new file mode 100644
index 000000000..aa2b2c2de
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/KRAPolicy.java
@@ -0,0 +1,78 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.ISubsystem;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.policy.IPolicyProcessor;
+import com.netscape.certsrv.request.IPolicy;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.PolicyResult;
+import com.netscape.cmscore.policy.GenericPolicyProcessor;
+import com.netscape.cmscore.util.Debug;
+
+/**
+ * KRA Policy.
+ *
+ * @deprecated
+ * @version $Revision$, $Date$
+ */
+public class KRAPolicy implements IPolicy {
+ IConfigStore mConfig = null;
+ IKeyRecoveryAuthority mKRA = null;
+
+ public GenericPolicyProcessor mPolicies = new GenericPolicyProcessor(false);
+
+ public KRAPolicy() {
+ }
+
+ public void init(ISubsystem owner, IConfigStore config)
+ throws EBaseException {
+ mKRA = (IKeyRecoveryAuthority) owner;
+ mConfig = config;
+ mPolicies.init(mKRA, mConfig);
+ }
+
+ public IPolicyProcessor getPolicyProcessor() {
+ return mPolicies;
+ }
+
+ /**
+ */
+ public PolicyResult apply(IRequest r) {
+ if (Debug.ON)
+ Debug.trace("KRA applies policies");
+ mKRA.log(ILogger.LL_INFO, "KRA applies policies");
+ PolicyResult result = mPolicies.apply(r);
+
+ if (result.equals(PolicyResult.DEFERRED)) {
+ // For KRA request, there is deferred
+ if (Debug.ON)
+ Debug.trace("KRA policies return DEFERRED");
+ return PolicyResult.REJECTED;
+ } else {
+ if (Debug.ON)
+ Debug.trace("KRA policies return ACCEPTED");
+ return mPolicies.apply(r);
+ }
+ }
+
+}
diff --git a/base/kra/src/com/netscape/kra/KRAService.java b/base/kra/src/com/netscape/kra/KRAService.java
new file mode 100644
index 000000000..4858e286a
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/KRAService.java
@@ -0,0 +1,101 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.util.Hashtable;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.IService;
+import com.netscape.cmscore.util.Debug;
+
+/**
+ * A class represents a KRA request queue service. This
+ * is the service object that is registered with
+ * the request queue. And it acts as a broker to
+ * distribute request into different KRA specific
+ * services. This service registration allows us to support
+ * new request easier.
+ * <P>
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class KRAService implements IService {
+
+ public final static String ENROLLMENT =
+ IRequest.ENROLLMENT_REQUEST;
+ public final static String RECOVERY = IRequest.KEYRECOVERY_REQUEST;
+ public final static String NETKEY_KEYGEN = IRequest.NETKEY_KEYGEN_REQUEST;
+ public final static String NETKEY_KEYRECOVERY = IRequest.NETKEY_KEYRECOVERY_REQUEST;
+ public final static String SECURITY_DATA_ENROLLMENT = IRequest.SECURITY_DATA_ENROLLMENT_REQUEST;
+ public final static String SECURITY_DATA_RECOVERY = IRequest.SECURITY_DATA_RECOVERY_REQUEST;
+
+
+ // private variables
+ private IKeyRecoveryAuthority mKRA = null;
+ private Hashtable<String, IService> mServices = new Hashtable<String, IService>();
+
+ /**
+ * Constructs KRA service.
+ */
+ public KRAService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mServices.put(ENROLLMENT, new EnrollmentService(kra));
+ mServices.put(RECOVERY, new RecoveryService(kra));
+ mServices.put(NETKEY_KEYGEN, new NetkeyKeygenService(kra));
+ mServices.put(NETKEY_KEYRECOVERY, new TokenKeyRecoveryService(kra));
+ mServices.put(SECURITY_DATA_ENROLLMENT, new SecurityDataService(kra));
+ mServices.put(SECURITY_DATA_RECOVERY, new SecurityDataRecoveryService(kra));
+ }
+
+ /**
+ * Processes a KRA request. This method is invoked by
+ * request subsystem.
+ *
+ * @param r request from request subsystem
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest r) throws EBaseException {
+ if (Debug.ON)
+ Debug.trace("KRA services request " +
+ r.getRequestId().toString());
+ mKRA.log(ILogger.LL_INFO, "KRA services request " +
+ r.getRequestId().toString());
+ IService s = mServices.get(r.getRequestType());
+
+ if (s == null) {
+ r.setExtData(IRequest.RESULT, IRequest.RES_ERROR);
+ r.setExtData(IRequest.ERROR, new EBaseException(
+ CMS.getUserMessage("CMS_BASE_INVALID_OPERATION")));
+ return true;
+ }
+ try {
+ return s.serviceRequest(r);
+ } catch (EBaseException e) {
+ r.setExtData(IRequest.RESULT, IRequest.RES_ERROR);
+ r.setExtData(IRequest.ERROR, e);
+ // return true;
+ // #546508
+ return false;
+ }
+ }
+}
diff --git a/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java b/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
new file mode 100644
index 000000000..8d8cafb84
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
@@ -0,0 +1,1785 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.x509.CertificateChain;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertImpl;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.NoSuchTokenException;
+import org.mozilla.jss.crypto.CryptoToken;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authority.IAuthority;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.ISubsystem;
+import com.netscape.certsrv.base.SessionContext;
+import com.netscape.certsrv.dbs.IDBSubsystem;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.certsrv.dbs.replicadb.IReplicaIDRepository;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.kra.IKeyService;
+import com.netscape.certsrv.listeners.EListenersException;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.policy.IPolicyProcessor;
+import com.netscape.certsrv.request.ARequestNotifier;
+import com.netscape.certsrv.request.IPolicy;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.IRequestListener;
+import com.netscape.certsrv.request.IRequestNotifier;
+import com.netscape.certsrv.request.IRequestQueue;
+import com.netscape.certsrv.request.IRequestScheduler;
+import com.netscape.certsrv.request.IRequestSubsystem;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.certsrv.request.RequestStatus;
+import com.netscape.certsrv.security.Credential;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.certsrv.security.ITransportKeyUnit;
+import com.netscape.certsrv.usrgrp.IUGSubsystem;
+import com.netscape.cmscore.dbs.DBSubsystem;
+import com.netscape.cmscore.dbs.KeyRecord;
+import com.netscape.cmscore.dbs.KeyRepository;
+import com.netscape.cmscore.dbs.ReplicaIDRepository;
+import com.netscape.cmscore.request.RequestSubsystem;
+
+/**
+ * A class represents an key recovery authority (KRA). A KRA
+ * is responsible to maintain key pairs that have been
+ * escrowed. It provides archive and recovery key pairs
+ * functionalities.
+ * <P>
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecoveryAuthority {
+
+ public final static String OFFICIAL_NAME = "Data Recovery Manager";
+
+ /**
+ * Internal Constants
+ */
+
+ private static final String PR_INTERNAL_TOKEN_NAME = "internal";
+ private static final String PARAM_CREDS = "creds";
+ private static final String PARAM_LOCK = "lock";
+ private static final String PARAM_PK12 = "pk12";
+ private static final String PARAM_ERROR = "error";
+ private static final String PARAM_AGENT = "agent";
+
+ private final static String KEY_RESP_NAME = "keyRepository";
+ private static final String PROP_REPLICAID_DN = "dbs.replicadn";
+
+ protected boolean mInitialized = false;
+ protected IConfigStore mConfig = null;
+ protected ILogger mLogger = CMS.getLogger();
+ protected KRAPolicy mPolicy = null;
+ protected X500Name mName = null;
+ protected boolean mQueueRequests = false;
+ protected String mId = null;
+ protected IRequestQueue mRequestQueue = null;
+ protected TransportKeyUnit mTransportKeyUnit = null;
+ protected StorageKeyUnit mStorageKeyUnit = null;
+ protected Hashtable<String, Credential[]> mAutoRecovery = new Hashtable<String, Credential[]>();
+ protected boolean mAutoRecoveryOn = false;
+ protected KeyRepository mKeyDB = null;
+ protected ReplicaIDRepository mReplicaRepot = null;
+ protected IRequestNotifier mNotify = null;
+ protected IRequestNotifier mPNotify = null;
+ protected ISubsystem mOwner = null;
+ protected int mRecoveryIDCounter = 0;
+ protected Hashtable<String, Hashtable<String, Object>> mRecoveryParams =
+ new Hashtable<String, Hashtable<String, Object>>();
+ protected org.mozilla.jss.crypto.X509Certificate mJssCert = null;
+ protected CryptoToken mKeygenToken = null;
+
+ // holds the number of bits of entropy to collect for each keygen
+ private int mEntropyBitsPerKeyPair = 0;
+
+ // the number of milliseconds which it is acceptable to block while
+ // getting entropy - anything longer will cause a warning.
+ // 0 means this warning is disabled
+ private int mEntropyBlockWarnMilliseconds = 0;
+
+ // for the notification listener
+ public IRequestListener mReqInQListener = null;
+
+ private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+ private final static byte EOL[] = { Character.LINE_SEPARATOR };
+ private final static String SIGNED_AUDIT_AGENT_DELIMITER = ", ";
+ private final static String LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_4";
+ private final static String LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED_3";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_4";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC_4";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_4";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC_4";
+
+ /**
+ * Constructs an escrow authority.
+ * <P>
+ */
+ public KeyRecoveryAuthority() {
+ super();
+ }
+
+ /**
+ * Retrieves subsystem identifier.
+ *
+ * @return subsystem id
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Sets subsystem identifier.
+ *
+ * @param id subsystem id
+ * @exception EBaseException failed to set id
+ */
+ public void setId(String id) throws EBaseException {
+ mId = id;
+ }
+
+ /**
+ * @deprecated
+ */
+ public IPolicyProcessor getPolicyProcessor() {
+ return mPolicy.getPolicyProcessor();
+ }
+
+ // initialize entropy collection parameters
+ private void initEntropy(IConfigStore config) {
+ mEntropyBitsPerKeyPair = 0;
+ mEntropyBlockWarnMilliseconds = 50;
+ // initialize entropy collection
+ IConfigStore ecs = config.getSubStore("entropy");
+ if (ecs != null) {
+ try {
+ mEntropyBitsPerKeyPair = ecs.getInteger("bitsperkeypair", 0);
+ mEntropyBlockWarnMilliseconds = ecs.getInteger("blockwarnms", 50);
+ } catch (EBaseException eb) {
+ // ok - we deal with missing parameters above
+ }
+ }
+ CMS.debug("KeyRecoveryAuthority Entropy bits = " + mEntropyBitsPerKeyPair);
+ if (mEntropyBitsPerKeyPair == 0) {
+ //log(ILogger.LL_INFO,
+ //CMS.getLogMessage("CMSCORE_KRA_ENTROPY_COLLECTION_DISABLED"));
+ } else {
+ //log(ILogger.LL_INFO,
+ //CMS.getLogMessage("CMSCORE_KRA_ENTROPY_COLLECTION_ENABLED"));
+ CMS.debug("KeyRecoveryAuthority about to add Entropy");
+ addEntropy(false);
+ CMS.debug("KeyRecoveryAuthority back from add Entropy");
+ }
+
+ }
+
+ public void addEntropy(boolean logflag) {
+ CMS.debug("KeyRecoveryAuthority addEntropy()");
+ if (mEntropyBitsPerKeyPair == 0) {
+ CMS.debug("KeyRecoveryAuthority returning - disabled()");
+ return;
+ }
+ long start = System.currentTimeMillis();
+ try {
+ com.netscape.cmscore.security.JssSubsystem.getInstance().
+ addEntropy(mEntropyBitsPerKeyPair);
+ } catch (Exception e) {
+ CMS.debug("KeyRecoveryAuthority returning - error - see log file");
+ CMS.debug("exception: " + e.getMessage());
+ CMS.debug(e);
+ if (logflag) {
+ log(ILogger.LL_INFO,
+ CMS.getLogMessage("CMSCORE_KRA_ENTROPY_ERROR",
+ e.getMessage()));
+ }
+ }
+ long end = System.currentTimeMillis();
+ long duration = end - start;
+
+ if (mEntropyBlockWarnMilliseconds > 0 &&
+ duration > mEntropyBlockWarnMilliseconds) {
+
+ CMS.debug("KeyRecoveryAuthority returning - warning - entropy took too long (ms=" +
+ duration + ")");
+ if (logflag) {
+ log(ILogger.LL_INFO,
+ CMS.getLogMessage("CMSCORE_KRA_ENTROPY_BLOCKED_WARNING",
+ "" + (int) duration));
+ }
+ }
+ CMS.debug("KeyRecoveryAuthority returning ");
+ }
+
+ /**
+ * Starts this subsystem. It loads and initializes all
+ * necessary components. This subsystem is started by
+ * KRASubsystem.
+ * <P>
+ *
+ * @param owner owner of this subsystem
+ * @param config configuration store for this subsystem
+ * @exception EBaseException failed to start subsystem
+ */
+ public void init(ISubsystem owner, IConfigStore config)
+ throws EBaseException {
+ CMS.debug("KeyRecoveryAuthority init() begins");
+ if (mInitialized)
+ return;
+
+ mConfig = config;
+ mOwner = owner;
+
+ // initialize policy processor
+ mPolicy = new KRAPolicy();
+ mPolicy.init(this, mConfig.getSubStore(PROP_POLICY));
+
+ // create key repository
+ int keydb_inc = mConfig.getInteger(PROP_KEYDB_INC, 5);
+
+ mKeyDB = new KeyRepository(getDBSubsystem(),
+ keydb_inc,
+ "ou=" + KEY_RESP_NAME + ",ou=" +
+ getId() + "," +
+ getDBSubsystem().getBaseDN());
+
+ // read transport key from internal database
+ mTransportKeyUnit = new TransportKeyUnit();
+ try {
+ mTransportKeyUnit.init(this, mConfig.getSubStore(
+ PROP_TRANSPORT_KEY));
+ } catch (EBaseException e) {
+ CMS.debug("KeyRecoveryAuthority: transport unit exception " + e.toString());
+ //XXX throw e;
+ return;
+ }
+
+ // retrieve the authority name from transport cert
+ try {
+ mJssCert = mTransportKeyUnit.getCertificate();
+ X509CertImpl certImpl = new
+ X509CertImpl(mJssCert.getEncoded());
+
+ mName = (X500Name) certImpl.getSubjectDN();
+ } catch (CertificateEncodingException e) {
+ CMS.debug("KeyRecoveryAuthority: " + e.toString());
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_LOAD_FAILED",
+ "transport cert " + e.toString()));
+ } catch (CertificateException e) {
+ CMS.debug("KeyRecoveryAuthority: " + e.toString());
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_LOAD_FAILED",
+ "transport cert " + e.toString()));
+ }
+
+ // read transport key from storage key
+ mStorageKeyUnit = new StorageKeyUnit();
+ try {
+ mStorageKeyUnit.init(this,
+ mConfig.getSubStore(PROP_STORAGE_KEY));
+ } catch (EBaseException e) {
+ CMS.debug("KeyRecoveryAuthority: storage unit exception " + e.toString());
+ throw e;
+ }
+
+ // setup token for server-side key generation for user enrollments
+ String serverKeygenTokenName = mConfig.getString("serverKeygenTokenName", null);
+ if (serverKeygenTokenName == null) {
+ CMS.debug("serverKeygenTokenName set to nothing");
+ if (mStorageKeyUnit.getToken() != null) {
+ try {
+ String storageToken = mStorageKeyUnit.getToken().getName();
+ if (!storageToken.equals("internal")) {
+ CMS.debug("Auto set serverKeygenTokenName to " + storageToken);
+ serverKeygenTokenName = storageToken;
+ }
+ } catch (Exception e) {
+ }
+ }
+ }
+ if (serverKeygenTokenName == null) {
+ serverKeygenTokenName = "internal";
+ }
+ if (serverKeygenTokenName.equalsIgnoreCase(PR_INTERNAL_TOKEN_NAME))
+ serverKeygenTokenName = PR_INTERNAL_TOKEN_NAME;
+
+ try {
+ if (serverKeygenTokenName.equalsIgnoreCase(PR_INTERNAL_TOKEN_NAME)) {
+ CMS.debug("KeyRecoveryAuthority: getting internal crypto token for serverkeygen");
+ mKeygenToken = CryptoManager.getInstance().getInternalKeyStorageToken();
+ } else {
+ CMS.debug("KeyRecoveryAuthority: getting HSM token for serverkeygen");
+ mKeygenToken = CryptoManager.getInstance().getTokenByName(serverKeygenTokenName);
+ }
+ CMS.debug("KeyRecoveryAuthority: set up keygenToken");
+ } catch (NoSuchTokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_TOKEN_NOT_FOUND", serverKeygenTokenName));
+ } catch (Exception e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CRYPTOMANAGER_UNINITIALIZED"));
+ }
+
+ CMS.debug("KeyRecoveryAuthority: about to init entropy");
+ initEntropy(mConfig);
+ CMS.debug("KeyRecoveryAuthority: completed init of entropy");
+
+ getLogger().log(ILogger.EV_SYSTEM, ILogger.S_KRA,
+ ILogger.LL_INFO, mName.toString() + " is started");
+
+ // setup the KRA request queue
+ IService service = new KRAService(this);
+
+ mNotify = new KRANotify(this);
+ mPNotify = new ARequestNotifier();
+ IRequestSubsystem reqSub = RequestSubsystem.getInstance();
+ int reqdb_inc = mConfig.getInteger("reqdbInc", 5);
+
+ mRequestQueue = reqSub.getRequestQueue(getId(), reqdb_inc,
+ mPolicy, service, mNotify, mPNotify);
+
+ // set KeyStatusUpdateInterval to be 10 minutes if serial management is enabled.
+ mKeyDB.setKeyStatusUpdateInterval(
+ mRequestQueue.getRequestRepository(),
+ mConfig.getInteger("keyStatusUpdateInterval", 10 * 60));
+
+ // init request scheduler if configured
+ String schedulerClass =
+ mConfig.getString("requestSchedulerClass", null);
+
+ if (schedulerClass != null) {
+ try {
+ IRequestScheduler scheduler = (IRequestScheduler)
+ Class.forName(schedulerClass).newInstance();
+
+ mRequestQueue.setRequestScheduler(scheduler);
+ } catch (Exception e) {
+ // do nothing here
+ }
+ }
+ initNotificationListeners();
+
+ String replicaReposDN = mConfig.getString(PROP_REPLICAID_DN, null);
+ if (replicaReposDN == null) {
+ replicaReposDN = "ou=Replica," + getDBSubsystem().getBaseDN();
+ }
+
+ mReplicaRepot = new ReplicaIDRepository(
+ DBSubsystem.getInstance(), 1, replicaReposDN);
+ CMS.debug("Replica Repot inited");
+
+ }
+
+ public CryptoToken getKeygenToken() {
+ return mKeygenToken;
+ }
+
+ public IRequestListener getRequestInQListener() {
+ return mReqInQListener;
+ }
+
+ public org.mozilla.jss.crypto.X509Certificate getTransportCert() {
+ return mJssCert;
+ }
+
+ /**
+ * Clears up system during garbage collection.
+ */
+ public void finalize() {
+ shutdown();
+ }
+
+ /**
+ * Starts this service. When this method is called, all
+ * service
+ *
+ * @exception EBaseException failed to startup this subsystem
+ */
+ public void startup() throws EBaseException {
+ CMS.debug("KeyRecoveryAuthority startup() begins");
+
+ if (mRequestQueue != null) {
+ // setup administration operations if everything else is fine
+ mRequestQueue.recover();
+ CMS.debug("KeyRecoveryAuthority startup() call request Q recover");
+
+ // Note that we use our instance id for registration.
+ // This helps us to support multiple instances
+ // of a subsystem within server.
+
+ // register remote admin interface
+ mInitialized = true;
+ } else {
+ CMS.debug("KeyRecoveryAuthority: mRequestQueue is null, could be in preop mode");
+ }
+ }
+
+ /**
+ * Shutdowns this subsystem.
+ */
+ public void shutdown() {
+ if (!mInitialized)
+ return;
+
+ mTransportKeyUnit.shutdown();
+ mStorageKeyUnit.shutdown();
+ if (mKeyDB != null) {
+ mKeyDB.shutdown();
+ mKeyDB = null;
+ }
+ getLogger().log(ILogger.EV_SYSTEM, ILogger.S_KRA,
+ ILogger.LL_INFO, mName.toString() + " is stopped");
+ mInitialized = false;
+ }
+
+ /**
+ * Retrieves the configuration store of this subsystem.
+ * <P>
+ *
+ * @return configuration store
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * Changes the auto recovery state.
+ *
+ * @param cs list of recovery agent credentials
+ * @param on turn of auto recovery or not
+ * @return operation success or not
+ */
+ public boolean setAutoRecoveryState(Credential cs[], boolean on) {
+ if (on == true) {
+ // check credential before enabling it
+ try {
+ getStorageKeyUnit().login(cs);
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ // maintain in-memory variable; don't store it in config
+ mAutoRecoveryOn = on;
+ return true;
+ }
+
+ /**
+ * Retrieves the current auto recovery state.
+ *
+ * @return enable or not
+ */
+ public boolean getAutoRecoveryState() {
+ // maintain in-memory variable; don't store it in config
+ return mAutoRecoveryOn;
+ }
+
+ /**
+ * Returns a list of users who are in auto
+ * recovery mode.
+ *
+ * @return list of user IDs that are accepted in the
+ * auto recovery mode
+ */
+ public Enumeration<String> getAutoRecoveryIDs() {
+ return mAutoRecovery.keys();
+ }
+
+ /**
+ * Adds auto recovery mode to the given user id.
+ *
+ * @param id new identifier to the auto recovery mode
+ * @param creds list of credentials
+ */
+ public void addAutoRecovery(String id, Credential creds[]) {
+ mAutoRecovery.put(id, creds);
+ }
+
+ /**
+ * Removes auto recovery mode from the given user id.
+ *
+ * @param id id of user to be removed from auto
+ * recovery mode
+ */
+ public void removeAutoRecovery(String id) {
+ mAutoRecovery.remove(id);
+ }
+
+ /**
+ * Retrieves logger from escrow authority.
+ *
+ * @return logger
+ */
+ public ILogger getLogger() {
+ return CMS.getLogger();
+ }
+
+ /**
+ * Retrieves number of required agents for
+ * recovery operation.
+ *
+ * @return number of required agents
+ * @exception EBaseException failed to retrieve info
+ */
+ public int getNoOfRequiredAgents() throws EBaseException {
+ if (mConfig.getBoolean("keySplitting", false)) {
+ return mStorageKeyUnit.getNoOfRequiredAgents();
+ } else {
+ int ret = -1;
+ ret = mConfig.getInteger("noOfRequiredRecoveryAgents", 1);
+ if (ret <= 0) {
+ throw new EBaseException("Invalid parameter noOfRequiredecoveryAgents");
+ }
+ return ret;
+ }
+ }
+
+ /**
+ * Sets number of required agents for
+ * recovery operation
+ *
+ * @return none
+ * @exception EBaseException invalid setting
+ */
+ public void setNoOfRequiredAgents(int number) throws EBaseException {
+ if (mConfig.getBoolean("keySplitting")) {
+ mStorageKeyUnit.setNoOfRequiredAgents(number);
+ } else {
+ mConfig.putInteger("noOfRequiredRecoveryAgents", number);
+ }
+ }
+
+ /**
+ * Distributed recovery.
+ */
+ public String getRecoveryID() {
+ return Integer.toString(mRecoveryIDCounter++);
+ }
+
+ public Hashtable<String, Object> createRecoveryParams(String recoveryID)
+ throws EBaseException {
+ Hashtable<String, Object> h = new Hashtable<String, Object>();
+
+ h.put(PARAM_CREDS, new Vector<Credential>());
+ h.put(PARAM_LOCK, new Object());
+ mRecoveryParams.put(recoveryID, h);
+ return h;
+ }
+
+ public void destroyRecoveryParams(String recoveryID)
+ throws EBaseException {
+ mRecoveryParams.remove(recoveryID);
+ }
+
+ public Hashtable<String, Object> getRecoveryParams(String recoveryID)
+ throws EBaseException {
+ return (Hashtable<String, Object>) mRecoveryParams.get(recoveryID);
+ }
+
+ public void createPk12(String recoveryID, byte[] pk12)
+ throws EBaseException {
+ Hashtable<String, Object> h = getRecoveryParams(recoveryID);
+
+ h.put(PARAM_PK12, pk12);
+ }
+
+ public byte[] getPk12(String recoveryID)
+ throws EBaseException {
+ return (byte[]) getRecoveryParams(recoveryID).get(PARAM_PK12);
+ }
+
+ public void createError(String recoveryID, String error)
+ throws EBaseException {
+ Hashtable<String, Object> h = getRecoveryParams(recoveryID);
+
+ h.put(PARAM_ERROR, error);
+ }
+
+ public String getError(String recoveryID)
+ throws EBaseException {
+ return (String) getRecoveryParams(recoveryID).get(PARAM_ERROR);
+ }
+
+ /**
+ * Retrieve the current approval agents
+ */
+ public Vector<Credential> getAppAgents(
+ String recoveryID) throws EBaseException {
+ Hashtable<String, Object> h = getRecoveryParams(recoveryID);
+ @SuppressWarnings("unchecked")
+ Vector<Credential> dc = (Vector<Credential>) h.get(PARAM_CREDS);
+
+ return dc;
+ }
+
+ /**
+ * Retrieves a list credentials. This puts KRA in a waiting
+ * mode, it never returns until all the necessary passwords
+ * are collected.
+ */
+ public Credential[] getDistributedCredentials(
+ String recoveryID)
+ throws EBaseException {
+ Hashtable<String, Object> h = getRecoveryParams(recoveryID);
+ @SuppressWarnings("unchecked")
+ Vector<Credential> dc = (Vector<Credential>) h.get(PARAM_CREDS);
+ Object lock = (Object) h.get(PARAM_LOCK);
+
+ synchronized (lock) {
+ while (dc.size() < getNoOfRequiredAgents()) {
+ CMS.debug("KeyRecoveryAuthority: cfu in synchronized lock for getDistributedCredentials");
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ Credential creds[] = new Credential[dc.size()];
+
+ dc.copyInto(creds);
+ return creds;
+ }
+ }
+
+ /**
+ * Verifies credential.
+ */
+ private void verifyCredential(Vector<Credential> creds, String uid,
+ String pwd) throws EBaseException {
+ // see if we have the uid already
+
+ if (!mConfig.getBoolean("keySplitting")) {
+ // check if the uid is in the specified group
+ IUGSubsystem ug = (IUGSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_UG);
+ if (!ug.isMemberOf(uid, mConfig.getString("recoveryAgentGroup"))) {
+ // invalid group
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_CREDENTIALS_NOT_EXIST"));
+ }
+ }
+
+ for (int i = 0; i < creds.size(); i++) {
+ Credential c = creds.elementAt(i);
+
+ if (c.getIdentifier().equals(uid)) {
+ // duplicated uid
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_CREDENTIALS_EXIST"));
+ }
+ }
+ if (mConfig.getBoolean("keySplitting")) {
+ mStorageKeyUnit.checkPassword(uid, pwd);
+ }
+ }
+
+ /**
+ * Adds password.
+ */
+ public void addDistributedCredential(String recoveryID,
+ String uid, String pwd) throws EBaseException {
+ Hashtable<String, Object> h = getRecoveryParams(recoveryID);
+ @SuppressWarnings("unchecked")
+ Vector<Credential> dc = (Vector<Credential>) h.get(PARAM_CREDS);
+ Object lock = (Object) h.get(PARAM_LOCK);
+
+ synchronized (lock) {
+ verifyCredential(dc, uid, pwd);
+ // verify password
+ dc.addElement(new Credential(uid, pwd));
+ // modify status object
+ lock.notify();
+ }
+ }
+
+ /**
+ * Archives key. This creates a key record in the key
+ * repository.
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST used whenever a user private key archive
+ * request is made (this is when the DRM receives the request)
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED used whenever a user private key
+ * archive request is processed (this is when the DRM processes the request)
+ * </ul>
+ *
+ * @param rec key record to be archived
+ * @return executed request
+ * @exception EBaseException failed to archive key
+ * @return the request
+ * <P>
+ */
+ public IRequest archiveKey(KeyRecord rec)
+ throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRequesterID = auditRequesterID();
+ String auditPublicKey = auditPublicKey(rec);
+ String auditArchiveID = ILogger.UNIDENTIFIED;
+
+ IRequestQueue queue = null;
+ IRequest r = null;
+ String id = null;
+
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ queue = getRequestQueue();
+
+ r = queue.newRequest(KRAService.ENROLLMENT);
+
+ if (r != null) {
+ // overwrite "auditArchiveID" if and only if "id" != null
+ id = r.getRequestId().toString();
+ if (id != null) {
+ auditArchiveID = id.trim();
+ }
+ }
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ if (r != null) {
+ r.setExtData(EnrollmentService.ATTR_KEY_RECORD, rec.getSerialNumber());
+ queue.processRequest(r);
+ }
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditPublicKey);
+
+ audit(auditMessage);
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditPublicKey);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+
+ return r;
+ }
+
+ /**
+ * async key recovery initiation
+ */
+ public String initAsyncKeyRecovery(BigInteger kid, X509CertImpl cert, String agent)
+ throws EBaseException {
+
+ String auditPublicKey = auditPublicKey(cert);
+ String auditRecoveryID = "undefined";
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+
+ IRequestQueue queue = null;
+ IRequest r = null;
+
+ try {
+ queue = getRequestQueue();
+ r = queue.newRequest(KRAService.RECOVERY);
+
+ r.setExtData(RecoveryService.ATTR_SERIALNO, kid);
+ r.setExtData(RecoveryService.ATTR_USER_CERT, cert);
+ // first one in the "approvingAgents" list is the initiating agent
+ r.setExtData(RecoveryService.ATTR_APPROVE_AGENTS, agent);
+ r.setRequestStatus(RequestStatus.PENDING);
+ queue.updateRequest(r);
+ auditRecoveryID = r.getRequestId().toString();
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ auditPublicKey);
+
+ audit(auditMessage);
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditPublicKey);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+
+ //NO call to queue.processRequest(r) because it is only initiating
+ return r.getRequestId().toString();
+ }
+
+ /**
+ * is async recovery request status APPROVED -
+ * i.e. all required # of recovery agents approved
+ */
+ public boolean isApprovedAsyncKeyRecovery(String reqID)
+ throws EBaseException {
+ IRequestQueue queue = null;
+ IRequest r = null;
+
+ queue = getRequestQueue();
+ r = queue.findRequest(new RequestId(reqID));
+ if ((r.getRequestStatus() == RequestStatus.APPROVED)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * get async recovery request initiating agent
+ */
+ public String getInitAgentAsyncKeyRecovery(String reqID)
+ throws EBaseException {
+ IRequestQueue queue = null;
+ IRequest r = null;
+
+ queue = getRequestQueue();
+ r = queue.findRequest(new RequestId(reqID));
+
+ String agents = r.getExtDataInString(RecoveryService.ATTR_APPROVE_AGENTS);
+ if (agents != null) {
+ int i = agents.indexOf(",");
+ if (i == -1) {
+ return agents;
+ }
+ return agents.substring(0, i);
+ } else { // no approvingAgents existing, can't be async recovery
+ CMS.debug("getInitAgentAsyncKeyRecovery: no approvingAgents in request");
+ }
+
+ return null;
+ }
+
+ /**
+ * add async recovery agent to approving agent list of the recovery request
+ * record
+ * This method will check to see if the agent belongs to the recovery group
+ * first before adding.
+ */
+ public void addAgentAsyncKeyRecovery(String reqID, String agentID)
+ throws EBaseException {
+ IRequestQueue queue = null;
+ IRequest r = null;
+
+ // check if the uid is in the specified group
+ IUGSubsystem ug = (IUGSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_UG);
+ if (!ug.isMemberOf(agentID, mConfig.getString("recoveryAgentGroup"))) {
+ // invalid group
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_CREDENTIALS_NOT_EXIST"));
+ }
+
+ queue = getRequestQueue();
+ r = queue.findRequest(new RequestId(reqID));
+
+ String agents = r.getExtDataInString(RecoveryService.ATTR_APPROVE_AGENTS);
+ if (agents != null) {
+ int count = 0;
+ StringTokenizer st = new StringTokenizer(agents, ",");
+ for (; st.hasMoreTokens();) {
+ String a = st.nextToken();
+ // first one is the initiating agent
+ if ((count != 0) && a.equals(agentID)) {
+ // duplicated uid
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_CREDENTIALS_EXIST"));
+ }
+ count++;
+ }
+
+ // note: if count==1 and required agents is 1, it's good to add
+ // and it'd look like "agent1,agent1" - that's the only dup allowed
+ if (count <= getNoOfRequiredAgents()) { //all good, add it
+ r.setExtData(RecoveryService.ATTR_APPROVE_AGENTS,
+ agents + "," + agentID);
+ if (count == getNoOfRequiredAgents()) {
+ r.setRequestStatus(RequestStatus.APPROVED);
+ } else {
+ r.setRequestStatus(RequestStatus.PENDING);
+ }
+ queue.updateRequest(r);
+ }
+ } else { // no approvingAgents existing, can't be async recovery
+ CMS.debug("addAgentAsyncKeyRecovery: no approvingAgents in request. Async recovery request not initiated?");
+ }
+ }
+
+ /**
+ * Recovers key for administrators. This method is
+ * invoked by the agent operation of the key recovery servlet.
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST used whenever a user private key recovery request is
+ * made (this is when the DRM receives the request)
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED used whenever a user private key recovery
+ * request is processed (this is when the DRM processes the request)
+ * </ul>
+ *
+ * @param kid key identifier
+ * @param creds list of recovery agent credentials
+ * @param password password of the PKCS12 package
+ * @param cert certficate that will be put in PKCS12
+ * @param delivery file, mail or something else
+ * @param nickname string containing the nickname of the id cert for this
+ * subsystem
+ * @exception EBaseException failed to recover key
+ * @return a byte array containing the key
+ */
+ public byte[] doKeyRecovery(BigInteger kid,
+ Credential creds[], String password,
+ X509CertImpl cert,
+ String delivery, String nickname,
+ String agent)
+ throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRecoveryID = auditRecoveryID();
+ String auditPublicKey = auditPublicKey(cert);
+ String auditAgents = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+
+ IRequestQueue queue = null;
+ IRequest r = null;
+ Hashtable<String, Object> params = null;
+
+ CMS.debug("KeyRecoveryAuthority: in synchronous doKeyRecovery()");
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ queue = getRequestQueue();
+ r = queue.newRequest(KRAService.RECOVERY);
+
+ // set transient parameters
+ params = createVolatileRequest(r.getRequestId());
+
+ if (mConfig.getBoolean("keySplitting")) {
+ params.put(RecoveryService.ATTR_AGENT_CREDENTIALS, creds);
+ }
+ params.put(RecoveryService.ATTR_TRANSPORT_PWD, password);
+
+ r.setExtData(RecoveryService.ATTR_SERIALNO, kid);
+ r.setExtData(RecoveryService.ATTR_USER_CERT, cert);
+ if (nickname != null) {
+ nickname = nickname.trim();
+ if (!nickname.equals("")) {
+ r.setExtData(RecoveryService.ATTR_NICKNAME, nickname);
+ }
+ }
+ // for both sync and async recovery
+ r.setExtData(RecoveryService.ATTR_APPROVE_AGENTS, agent);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ auditPublicKey);
+
+ audit(auditMessage);
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditPublicKey);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ queue.processRequest(r);
+
+ if (r.getExtDataInString(IRequest.ERROR) == null) {
+ byte pkcs12[] = (byte[]) params.get(
+ RecoveryService.ATTR_PKCS12);
+
+ auditAgents = auditAgents(creds);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ destroyVolatileRequest(r.getRequestId());
+
+ return pkcs12;
+ } else {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ throw new EBaseException(r.getExtDataInString(IRequest.ERROR));
+ }
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+ }
+
+ /**
+ * Async Recovers key for administrators. This method is
+ * invoked by the agent operation of the key recovery servlet.
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST used whenever a user private key recovery request is
+ * made (this is when the DRM receives the request)
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED used whenever a user private key recovery
+ * request is processed (this is when the DRM processes the request)
+ * </ul>
+ *
+ * @param requestID request id
+ * @param password password of the PKCS12 package
+ * subsystem
+ * @exception EBaseException failed to recover key
+ * @return a byte array containing the key
+ */
+ public byte[] doKeyRecovery(
+ String reqID,
+ String password)
+ throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRecoveryID = reqID;
+ String auditAgents = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+
+ IRequestQueue queue = null;
+ IRequest r = null;
+ Hashtable<String, Object> params = null;
+
+ CMS.debug("KeyRecoveryAuthority: in asynchronous doKeyRecovery()");
+ queue = getRequestQueue();
+ r = queue.findRequest(new RequestId(reqID));
+
+ auditAgents =
+ r.getExtDataInString(RecoveryService.ATTR_APPROVE_AGENTS);
+
+ // set transient parameters
+ params = createVolatileRequest(r.getRequestId());
+ params.put(RecoveryService.ATTR_TRANSPORT_PWD, password);
+
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ CMS.debug("KeyRecoveryAuthority: in asynchronous doKeyRecovery(), request state ="
+ + r.getRequestStatus().toString());
+ // can only process requests in begin state
+ r.setRequestStatus(RequestStatus.BEGIN);
+ queue.processRequest(r);
+
+ if (r.getExtDataInString(IRequest.ERROR) == null) {
+ byte pkcs12[] = (byte[]) params.get(
+ RecoveryService.ATTR_PKCS12);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ destroyVolatileRequest(r.getRequestId());
+
+ return pkcs12;
+ } else {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ throw new EBaseException(r.getExtDataInString(IRequest.ERROR));
+ }
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+ throw eAudit1;
+ }
+ }
+
+ /**
+ * Constructs a recovery request and submits it
+ * to the request subsystem for processing.
+ *
+ * @param kid key identifier
+ * @param creds list of recovery agent credentials
+ * @param password password of the PKCS12 package
+ * @param cert certficate that will be put in PKCS12
+ * @param delivery file, mail or something else
+ * @return executed request
+ * @exception EBaseException failed to recover key
+ */
+ public IRequest recoverKey(BigInteger kid,
+ Credential creds[], String password,
+ X509CertImpl cert,
+ String delivery) throws EBaseException {
+ IRequestQueue queue = getRequestQueue();
+ IRequest r = queue.newRequest("recovery");
+
+ r.setExtData(RecoveryService.ATTR_SERIALNO, kid);
+ r.setExtData(RecoveryService.ATTR_TRANSPORT_PWD, password);
+ r.setExtData(RecoveryService.ATTR_USER_CERT, cert);
+ r.setExtData(RecoveryService.ATTR_DELIVERY, delivery);
+ queue.processRequest(r);
+ return r;
+ }
+
+ /**
+ * Recovers key for end-entities.
+ *
+ * @param creds list of credentials
+ * @param encryptionChain certificate chain
+ * @param signingCert signing cert
+ * @param transportCert certificate to protect in-transit key
+ * @param ownerName owner name
+ * @return executed request
+ * @exception EBaseException failed to recover key
+ */
+ public IRequest recoverKey(Credential creds[], CertificateChain
+ encryptionChain, X509CertImpl signingCert,
+ X509CertImpl transportCert,
+ X500Name ownerName) throws EBaseException {
+ IRequestQueue queue = getRequestQueue();
+ IRequest r = queue.newRequest("recovery");
+
+ ByteArrayOutputStream certChainOut = new ByteArrayOutputStream();
+ try {
+ encryptionChain.encode(certChainOut);
+ r.setExtData(RecoveryService.ATTR_ENCRYPTION_CERTS,
+ certChainOut.toByteArray());
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ "Error encoding certificate chain");
+ }
+
+ r.setExtData(RecoveryService.ATTR_SIGNING_CERT, signingCert);
+ r.setExtData(RecoveryService.ATTR_TRANSPORT_CERT, transportCert);
+
+ DerOutputStream ownerNameOut = new DerOutputStream();
+ try {
+ ownerName.encode(ownerNameOut);
+ r.setExtData(RecoveryService.ATTR_OWNER_NAME,
+ ownerNameOut.toByteArray());
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ "Error encoding X500Name for owner name");
+ }
+
+ queue.processRequest(r);
+ return r;
+ }
+
+ /**
+ * Retrieves the storage key unit. The storage key
+ * is used to wrap the user key for long term
+ * storage.
+ *
+ * @return storage key unit.
+ */
+ public IStorageKeyUnit getStorageKeyUnit() {
+ return mStorageKeyUnit;
+ }
+
+ /**
+ * Retrieves the transport key unit.
+ *
+ * @return transport key unit
+ */
+ public ITransportKeyUnit getTransportKeyUnit() {
+ return mTransportKeyUnit;
+ }
+
+ /**
+ * Returns the name of this subsystem. This name is
+ * extracted from the transport certificate.
+ *
+ * @return KRA name
+ */
+ public X500Name getX500Name() {
+ return mName;
+ }
+
+ public String getNickName() {
+ return getNickname();
+ }
+
+ /**
+ * Returns the nickname for the id cert of this
+ * subsystem.
+ *
+ * @return nickname of the transport certificate
+ */
+ public String getNickname() {
+ try {
+ return mTransportKeyUnit.getNickName();
+ } catch (EBaseException e) {
+ return null;
+ }
+ }
+
+ public void setNickname(String str) {
+ try {
+ mTransportKeyUnit.setNickName(str);
+ } catch (EBaseException e) {
+ }
+ }
+
+ public String getNewNickName() throws EBaseException {
+ return mConfig.getString(PROP_NEW_NICKNAME, "");
+ }
+
+ public void setNewNickName(String name) {
+ mConfig.putString(PROP_NEW_NICKNAME, name);
+ }
+
+ public IPolicy getPolicy() {
+ return mPolicy;
+ }
+
+ /**
+ * Retrieves KRA request repository.
+ * <P>
+ *
+ * @return request repository
+ */
+ public IRequestQueue getRequestQueue() {
+ return mRequestQueue;
+ }
+
+ /**
+ * Retrieves the key repository. The key repository
+ * stores archived keys.
+ * <P>
+ */
+ public IKeyRepository getKeyRepository() {
+ return mKeyDB;
+ }
+
+ /**
+ * Retrieves replica repository.
+ * <P>
+ *
+ * @return replica repository
+ */
+ public IReplicaIDRepository getReplicaRepository() {
+ return mReplicaRepot;
+ }
+
+ /**
+ * Retrieves the DN of this escrow authority.
+ * <P>
+ *
+ * @return distinguished name
+ */
+ protected String getDN() {
+ return getX500Name().toString();
+ }
+
+ /**
+ * Retrieves database connection.
+ */
+ public IDBSubsystem getDBSubsystem() {
+ return DBSubsystem.getInstance();
+ }
+
+ /**
+ * Logs an event.
+ *
+ * @param level log level
+ * @param msg message to log
+ */
+ public void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_KRA,
+ level, msg);
+ }
+
+ /**
+ * Registers a request listener.
+ *
+ * @param l request listener
+ */
+ public void registerRequestListener(IRequestListener l) {
+ // it's initialized.
+ if (mNotify != null)
+ mNotify.registerListener(l);
+ }
+
+ public void registerPendingListener(IRequestListener l) {
+ mPNotify.registerListener(l);
+ }
+
+ /**
+ * init notification related listeners -
+ * right now only RequestInQueue listener is available for KRA
+ */
+ private void initNotificationListeners() {
+ IConfigStore nc = null;
+
+ try {
+ nc = mConfig.getSubStore(PROP_NOTIFY_SUBSTORE);
+ if (nc != null && nc.size() > 0) {
+ // Initialize Request In Queue notification listener
+ String requestInQListenerClassName =
+ nc.getString("certificateIssuedListenerClassName",
+ "com.netscape.cms.listeners.RequestInQListener");
+
+ try {
+ mReqInQListener = (IRequestListener) Class.forName(requestInQListenerClassName).newInstance();
+ mReqInQListener.init(this, nc);
+ } catch (Exception e1) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_REGISTER_LISTENER", requestInQListenerClassName));
+ }
+ } else {
+ log(ILogger.LL_INFO,
+ "No KRA notification Module configuration found");
+ }
+ } catch (EPropertyNotFound e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_NOTIFY_ERROR", e.toString()));
+ } catch (EListenersException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_NOTIFY_ERROR", e.toString()));
+ } catch (EBaseException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_NOTIFY_ERROR", e.toString()));
+ }
+ }
+
+ /**
+ * temporary accepted ras.
+ */
+ /* code no longer used
+ public X500Name[] getAcceptedRAs() {
+ // temporary. use usr/grp for real thing.
+ X500Name radn = null;
+ String raname = null;
+
+ try {
+ raname = mConfig.getString("acceptedRA", null);
+ if (raname != null) {
+ radn = new X500Name(raname);
+ }
+ } catch (IOException e) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_KRA,
+ ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_INVALID_RA_NAME", raname, e.toString()));
+ } catch (EBaseException e) {
+ // ignore - set to null.
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_KRA,
+ ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_INVALID_RA_SETUP", e.toString()));
+ }
+ return new X500Name[] { radn };
+ }
+ */
+
+ public Hashtable<String, Hashtable<String, Object>> mVolatileRequests =
+ new Hashtable<String, Hashtable<String, Object>>();
+
+ /**
+ * Creates a request object to store attributes that
+ * will not be serialized. Currently, request queue
+ * framework will try to serialize all the attribute into
+ * persistent storage. Things like passwords are not
+ * desirable to be stored.
+ */
+ public Hashtable<String, Object> createVolatileRequest(RequestId id) {
+ Hashtable<String, Object> params = new Hashtable<String, Object>();
+
+ mVolatileRequests.put(id.toString(), params);
+ return params;
+ }
+
+ public Hashtable<String, Object> getVolatileRequest(RequestId id) {
+ return (Hashtable<String, Object>) mVolatileRequests.get(id.toString());
+ }
+
+ public void destroyVolatileRequest(RequestId id) {
+ mVolatileRequests.remove(id.toString());
+ }
+
+ public String getOfficialName() {
+ return OFFICIAL_NAME;
+ }
+
+ /**
+ * Signed Audit Log
+ *
+ * This method is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ private void audit(String msg) {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if (mSignedAuditLogger == null) {
+ return;
+ }
+
+ mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg);
+ }
+
+ /**
+ * Signed Audit Log Subject ID
+ *
+ * This method is called to obtain the "SubjectID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message SubjectID
+ */
+ private String auditSubjectID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String subjectID = null;
+
+ // Initialize subjectID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ subjectID = (String)
+ auditContext.get(SessionContext.USER_ID);
+
+ if (subjectID != null) {
+ subjectID = subjectID.trim();
+ } else {
+ subjectID = ILogger.NONROLEUSER;
+ }
+ } else {
+ subjectID = ILogger.UNIDENTIFIED;
+ }
+
+ return subjectID;
+ }
+
+ /**
+ * Signed Audit Log Requester ID
+ *
+ * This method is called to obtain the "RequesterID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message RequesterID
+ */
+ private String auditRequesterID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String requesterID = null;
+
+ // Initialize requesterID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ requesterID = (String)
+ auditContext.get(SessionContext.REQUESTER_ID);
+
+ if (requesterID != null) {
+ requesterID = requesterID.trim();
+ } else {
+ requesterID = ILogger.UNIDENTIFIED;
+ }
+ } else {
+ requesterID = ILogger.UNIDENTIFIED;
+ }
+
+ return requesterID;
+ }
+
+ /**
+ * Signed Audit Log Recovery ID
+ *
+ * This method is called to obtain the "RecoveryID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message RecoveryID
+ */
+ private String auditRecoveryID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String recoveryID = null;
+
+ // Initialize recoveryID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ recoveryID = (String)
+ auditContext.get(SessionContext.RECOVERY_ID);
+
+ if (recoveryID != null) {
+ recoveryID = recoveryID.trim();
+ } else {
+ recoveryID = ILogger.UNIDENTIFIED;
+ }
+ } else {
+ recoveryID = ILogger.UNIDENTIFIED;
+ }
+
+ return recoveryID;
+ }
+
+ /**
+ * Signed Audit Log Public Key
+ *
+ * This method is called to obtain the public key from the passed in
+ * "X509Certificate" for a signed audit log message.
+ * <P>
+ *
+ * @param cert an X509Certificate
+ * @return key string containing the certificate's public key
+ */
+ private String auditPublicKey(X509Certificate cert) {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ if (cert == null) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ byte rawData[] = cert.getPublicKey().getEncoded();
+
+ // convert "rawData" into "base64Data"
+ if (rawData != null) {
+ String base64Data = CMS.BtoA(rawData).trim();
+ String key = "";
+
+ // extract all line separators from the "base64Data"
+ for (int i = 0; i < base64Data.length(); i++) {
+ if (base64Data.substring(i, i).getBytes() != EOL) {
+ key += base64Data.substring(i, i);
+ }
+ }
+
+ return key;
+ }
+
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ /**
+ * Signed Audit Log Public Key
+ *
+ * This method is called to obtain the public key from the passed in
+ * "KeyRecord" for a signed audit log message.
+ * <P>
+ *
+ * @param rec a Key Record
+ * @return key string containing the certificate's public key
+ */
+ private String auditPublicKey(KeyRecord rec) {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ if (rec == null) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ byte rawData[] = null;
+
+ try {
+ rawData = rec.getPublicKeyData();
+ } catch (EBaseException e) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ String key = null;
+
+ // convert "rawData" into "base64Data"
+ if (rawData != null) {
+ String base64Data = null;
+
+ base64Data = CMS.BtoA(rawData).trim();
+
+ // extract all line separators from the "base64Data"
+ for (int i = 0; i < base64Data.length(); i++) {
+ if (base64Data.substring(i, i).getBytes() != EOL) {
+ key += base64Data.substring(i, i);
+ }
+ }
+ }
+
+ if (key != null) {
+ key = key.trim();
+
+ if (key.equals("")) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ } else {
+ return key;
+ }
+ } else {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+ }
+
+ /**
+ * Signed Audit Agents
+ *
+ * This method is called to extract agent uids from the passed in
+ * "Credentials[]" and return a string of comma-separated agent uids.
+ * <P>
+ *
+ * @param creds array of credentials
+ * @return a comma-separated string of agent uids
+ */
+ private String auditAgents(Credential creds[]) {
+ if (creds == null)
+ return null;
+
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String agents = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+
+ String uid = null;
+
+ for (int i = 0; i < creds.length; i++) {
+ uid = creds[i].getIdentifier();
+
+ if (uid != null) {
+ uid = uid.trim();
+ }
+
+ if (uid != null &&
+ !uid.equals("")) {
+
+ if (i == 0) {
+ agents = uid;
+ } else {
+ agents += SIGNED_AUDIT_AGENT_DELIMITER + uid;
+ }
+ }
+ }
+
+ return agents;
+ }
+}
diff --git a/base/kra/src/com/netscape/kra/NetkeyKeygenService.java b/base/kra/src/com/netscape/kra/NetkeyKeygenService.java
new file mode 100644
index 000000000..ecce2eaa9
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/NetkeyKeygenService.java
@@ -0,0 +1,608 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import netscape.security.provider.RSAPublicKey;
+
+import org.mozilla.jss.crypto.Cipher;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.KeyPairAlgorithm;
+import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.PQGParamGenException;
+import org.mozilla.jss.crypto.PQGParams;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.pkcs11.PK11SymKey;
+import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
+import org.mozilla.jss.util.Base64OutputStream;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.SessionContext;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.certsrv.security.ITransportKeyUnit;
+import com.netscape.cmscore.dbs.KeyRecord;
+import com.netscape.cmscore.util.Debug;
+
+/**
+ * A class representing keygen/archival request procesor for requests
+ * from netkey RAs.
+ * the user private key of the encryption cert is wrapped with a
+ * session symmetric key. The session symmetric key is wrapped with the
+ * storage key and stored in the internal database for long term
+ * storage.
+ * The user private key of the encryption cert is to be wrapped with the
+ * DES key which came in in the request wrapped with the KRA
+ * transport cert. The wrapped user private key is then sent back to
+ * the caller (netkey RA) ...netkey RA should already has kek-wrapped
+ * des key from the TKS. They are to be sent together back to
+ * the token.
+ *
+ * @author Christina Fu (cfu)
+ * @version $Revision$, $Date$
+ */
+
+public class NetkeyKeygenService implements IService {
+ public final static String ATTR_KEY_RECORD = "keyRecord";
+ public final static String ATTR_PROOF_OF_ARCHIVAL =
+ "proofOfArchival";
+
+ // private
+ private final static String LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_4";
+ private final static String LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED_3";
+ // these need to be defined in LogMessages_en.properties later when we do this
+ private final static String LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST =
+ "LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_3";
+ private final static String LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS =
+ "LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS_4";
+ private final static String LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE =
+ "LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE_3";
+ private final static String LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS_4";
+ private final static String LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE_4";
+ private IKeyRecoveryAuthority mKRA = null;
+ private ITransportKeyUnit mTransportUnit = null;
+ private IStorageKeyUnit mStorageUnit = null;
+ private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+
+ /**
+ * Constructs request processor.
+ * <P>
+ *
+ * @param kra key recovery authority
+ */
+ public NetkeyKeygenService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mTransportUnit = kra.getTransportKeyUnit();
+ mStorageUnit = kra.getStorageKeyUnit();
+ }
+
+ public PKIArchiveOptions toPKIArchiveOptions(byte options[]) {
+ ByteArrayInputStream bis = new ByteArrayInputStream(options);
+ PKIArchiveOptions archOpts = null;
+
+ try {
+ archOpts = (PKIArchiveOptions)
+ (new PKIArchiveOptions.Template()).decode(bis);
+ } catch (Exception e) {
+ CMS.debug("NetkeyKeygenService: getPKIArchiveOptions " + e.toString());
+ }
+ return archOpts;
+ }
+
+ public KeyPair generateKeyPair(
+ KeyPairAlgorithm kpAlg, int keySize, PQGParams pqg)
+ throws NoSuchAlgorithmException, TokenException, InvalidAlgorithmParameterException,
+ InvalidParameterException, PQGParamGenException {
+
+ CryptoToken token = mKRA.getKeygenToken();
+
+ CMS.debug("NetkeyKeygenService: key pair is to be generated on slot: " + token.getName());
+
+ /*
+ make it temporary so can work with HSM
+ netHSM works with
+ temporary == true
+ sensitive == <do not specify>
+ extractable == <do not specify>
+ LunaSA2 works with
+ temporary == true
+ sensitive == true
+ extractable == true
+ */
+ KeyPairGenerator kpGen = token.getKeyPairGenerator(kpAlg);
+ IConfigStore config = CMS.getConfigStore();
+ IConfigStore kgConfig = config.getSubStore("kra.keygen");
+ boolean tp = false;
+ boolean sp = false;
+ boolean ep = false;
+ if (kgConfig != null) {
+ try {
+ tp = kgConfig.getBoolean("temporaryPairs", false);
+ sp = kgConfig.getBoolean("sensitivePairs", false);
+ ep = kgConfig.getBoolean("extractablePairs", false);
+ // by default, let nethsm work
+ if ((tp == false) && (sp == false) && (ep == false)) {
+ tp = true;
+ }
+ } catch (Exception e) {
+ CMS.debug("NetkeyKeygenService: kgConfig.getBoolean failed");
+ // by default, let nethsm work
+ tp = true;
+ }
+ } else {
+ // by default, let nethsm work
+ CMS.debug("NetkeyKeygenService: cannot find config store: kra.keygen, assume temporaryPairs==true");
+ tp = true;
+ }
+ /* only specified to "true" will it be set */
+ if (tp == true) {
+ CMS.debug("NetkeyKeygenService: setting temporaryPairs to true");
+ kpGen.temporaryPairs(true);
+ }
+ if (sp == true) {
+ CMS.debug("NetkeyKeygenService: setting sensitivePairs to true");
+ kpGen.sensitivePairs(true);
+ }
+ if (ep == true) {
+ CMS.debug("NetkeyKeygenService: setting extractablePairs to true");
+ kpGen.extractablePairs(true);
+ }
+
+ if (kpAlg == KeyPairAlgorithm.DSA) {
+ if (pqg == null) {
+ kpGen.initialize(keySize);
+ } else {
+ kpGen.initialize(pqg);
+ }
+ } else {
+ kpGen.initialize(keySize);
+ }
+
+ if (pqg == null) {
+ KeyPair kp = null;
+ synchronized (new Object()) {
+ CMS.debug("NetkeyKeygenService: key pair generation begins");
+ kp = kpGen.genKeyPair();
+ CMS.debug("NetkeyKeygenService: key pair generation done");
+ mKRA.addEntropy(true);
+ }
+ return kp;
+ } else {
+ // DSA
+ KeyPair kp = null;
+
+ /* no DSA for now... netkey prototype
+ do {
+ // 602548 NSS bug - to overcome it, we use isBadDSAKeyPair
+ kp = kpGen.genKeyPair();
+ }
+ while (isBadDSAKeyPair(kp));
+ */
+ return kp;
+ }
+ }
+
+ public KeyPair generateKeyPair(String alg,
+ int keySize, PQGParams pqg) throws EBaseException {
+
+ KeyPairAlgorithm kpAlg = null;
+
+ if (alg.equals("RSA"))
+ kpAlg = KeyPairAlgorithm.RSA;
+ else
+ kpAlg = KeyPairAlgorithm.DSA;
+
+ try {
+ KeyPair kp = generateKeyPair(kpAlg, keySize, pqg);
+
+ return kp;
+ } catch (InvalidParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEYSIZE_PARAMS",
+ "" + keySize));
+ } catch (PQGParamGenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_PQG_GEN_FAILED"));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_ALG_NOT_SUPPORTED",
+ kpAlg.toString()));
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_TOKEN_ERROR_1", e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_ALG_NOT_SUPPORTED", "DSA"));
+ }
+ }
+
+ private static String base64Encode(byte[] bytes) throws IOException {
+ // All this streaming is lame, but Base64OutputStream needs a
+ // PrintStream
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Base64OutputStream b64 = new Base64OutputStream(new
+ PrintStream(new
+ FilterOutputStream(output)
+ )
+ );
+
+ b64.write(bytes);
+ b64.flush();
+
+ // This is internationally safe because Base64 chars are
+ // contained within 8859_1
+ return output.toString("8859_1");
+ }
+
+ // this encrypts bytes with a symmetric key
+ public byte[] encryptIt(byte[] toBeEncrypted, SymmetricKey symKey, CryptoToken token,
+ IVParameterSpec IV) {
+ try {
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+
+ cipher.initEncrypt(symKey, IV);
+ byte pri[] = cipher.doFinal(toBeEncrypted);
+ return pri;
+ } catch (Exception e) {
+ CMS.debug("NetkeyKeygenService:initEncrypt() threw exception: " + e.toString());
+ return null;
+ }
+
+ }
+
+ /**
+ * Services an archival request from netkey.
+ * <P>
+ *
+ * @param request enrollment request
+ * @return serving successful or not
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest request)
+ throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = null;
+ String auditArchiveID = ILogger.UNIDENTIFIED;
+ byte[] wrapped_des_key;
+
+ byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ String iv_s = "";
+ try {
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+ random.nextBytes(iv);
+ } catch (Exception e) {
+ CMS.debug("NetkeyKeygenService.serviceRequest: " + e.toString());
+ }
+
+ IVParameterSpec algParam = new IVParameterSpec(iv);
+
+ wrapped_des_key = null;
+ boolean archive = true;
+ PK11SymKey sk = null;
+ byte[] publicKeyData = null;
+ ;
+ String PubKey = "";
+
+ String id = request.getRequestId().toString();
+ if (id != null) {
+ auditArchiveID = id.trim();
+ }
+
+ String rArchive = request.getExtDataInString(IRequest.NETKEY_ATTR_ARCHIVE_FLAG);
+ if (rArchive.equals("true")) {
+ archive = true;
+ CMS.debug("NetkeyKeygenService: serviceRequest " + "archival requested for serverSideKeyGen");
+ } else {
+ archive = false;
+ CMS.debug("NetkeyKeygenService: serviceRequest " + "archival not requested for serverSideKeyGen");
+ }
+
+ String rCUID = request.getExtDataInString(IRequest.NETKEY_ATTR_CUID);
+ String rUserid = request.getExtDataInString(IRequest.NETKEY_ATTR_USERID);
+ String rKeysize = request.getExtDataInString(IRequest.NETKEY_ATTR_KEY_SIZE);
+ int keysize = Integer.parseInt(rKeysize);
+ auditSubjectID = rCUID + ":" + rUserid;
+
+ SessionContext sContext = SessionContext.getContext();
+ String agentId = "";
+ if (sContext != null) {
+ agentId =
+ (String) sContext.get(SessionContext.USER_ID);
+ }
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST,
+ agentId,
+ ILogger.SUCCESS,
+ auditSubjectID);
+
+ audit(auditMessage);
+
+ String rWrappedDesKeyString = request.getExtDataInString(IRequest.NETKEY_ATTR_DRMTRANS_DES_KEY);
+ // CMS.debug("NetkeyKeygenService: received DRM-trans-wrapped DES key ="+rWrappedDesKeyString);
+ wrapped_des_key = com.netscape.cmsutil.util.Utils.SpecialDecode(rWrappedDesKeyString);
+ CMS.debug("NetkeyKeygenService: wrapped_des_key specialDecoded");
+
+ // get the token for generating user keys
+ CryptoToken keygenToken = mKRA.getKeygenToken();
+ if (keygenToken == null) {
+ CMS.debug("NetkeyKeygenService: failed getting keygenToken");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(10));
+ return false;
+ } else
+ CMS.debug("NetkeyKeygenService: got keygenToken");
+
+ if ((wrapped_des_key != null) &&
+ (wrapped_des_key.length > 0)) {
+
+ // unwrap the DES key
+ sk = (PK11SymKey) mTransportUnit.unwrap_sym(wrapped_des_key);
+
+ /* XXX could be done in HSM*/
+ KeyPair keypair = null;
+
+ CMS.debug("NetkeyKeygenService: about to generate key pair");
+
+ keypair = generateKeyPair("RSA"/*alg*/,
+ keysize /*Integer.parseInt(len)*/, null /*pqgParams*/);
+
+ if (keypair == null) {
+ CMS.debug("NetkeyKeygenService: failed generating key pair for " + rCUID + ":" + rUserid);
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,
+ agentId,
+ ILogger.FAILURE,
+ auditSubjectID);
+
+ audit(auditMessage);
+
+ return false;
+ }
+ CMS.debug("NetkeyKeygenService: finished generate key pair for " + rCUID + ":" + rUserid);
+
+ try {
+ publicKeyData = keypair.getPublic().getEncoded();
+ if (publicKeyData == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("NetkeyKeygenService: failed getting publickey encoded");
+ return false;
+ } else {
+ //CMS.debug("NetkeyKeygenService: public key binary length ="+ publicKeyData.length);
+ PubKey = base64Encode(publicKeyData);
+
+ //CMS.debug("NetkeyKeygenService: public key length =" + PubKey.length());
+ request.setExtData("public_key", PubKey);
+ }
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,
+ agentId,
+ ILogger.SUCCESS,
+ auditSubjectID,
+ PubKey);
+
+ audit(auditMessage);
+
+ //...extract the private key handle (not privatekeydata)
+ java.security.PrivateKey privKey =
+ keypair.getPrivate();
+
+ if (privKey == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("NetkeyKeygenService: failed getting private key");
+ return false;
+ } else {
+ CMS.debug("NetkeyKeygenService: got private key");
+ }
+
+ if (sk == null) {
+ CMS.debug("NetkeyKeygenService: no DES key");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ return false;
+ } else {
+ CMS.debug("NetkeyKeygenService: received DES key");
+ }
+
+ // 3 wrapping should be done in HSM
+ // wrap private key with DES
+ KeyWrapper symWrap =
+ keygenToken.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+ CMS.debug("NetkeyKeygenService: wrapper token=" + keygenToken.getName());
+ CMS.debug("NetkeyKeygenService: got key wrapper");
+
+ CMS.debug("NetkeyKeygenService: key transport key is on slot: " + sk.getOwningToken().getName());
+ symWrap.initWrap((SymmetricKey) sk, algParam);
+ byte wrapped[] = symWrap.wrap((PrivateKey) privKey);
+ /*
+ CMS.debug("NetkeyKeygenService: wrap called");
+ CMS.debug(wrapped);
+ */
+ /* This is for using with my decryption tool and ASN1
+ decoder to see if the private key is indeed PKCS#8 format
+ { // cfu debug
+ String oFilePath = "/tmp/wrappedPrivKey.bin";
+ File file = new File(oFilePath);
+ FileOutputStream ostream = new FileOutputStream(oFilePath);
+ ostream.write(wrapped);
+ ostream.close();
+ }
+ */
+ String wrappedPrivKeyString = /*base64Encode(wrapped);*/
+ com.netscape.cmsutil.util.Utils.SpecialEncode(wrapped);
+ if (wrappedPrivKeyString == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("NetkeyKeygenService: failed generating wrapped private key");
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,
+ agentId,
+ ILogger.FAILURE,
+ auditSubjectID,
+ PubKey);
+
+ audit(auditMessage);
+ return false;
+ } else {
+ request.setExtData("wrappedUserPrivate", wrappedPrivKeyString);
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,
+ agentId,
+ ILogger.SUCCESS,
+ auditSubjectID,
+ PubKey);
+
+ audit(auditMessage);
+ }
+
+ iv_s = /*base64Encode(iv);*/com.netscape.cmsutil.util.Utils.SpecialEncode(iv);
+ request.setExtData("iv_s", iv_s);
+
+ /*
+ * archival - option flag "archive" controllable by the caller - TPS
+ */
+ if (archive) {
+ //
+ // privateKeyData ::= SEQUENCE {
+ // sessionKey OCTET_STRING,
+ // encKey OCTET_STRING,
+ // }
+ //
+ // mKRA.log(ILogger.LL_INFO, "KRA encrypts internal private");
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ agentId,
+ ILogger.SUCCESS,
+ auditSubjectID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ CMS.debug("KRA encrypts private key to put on internal ldap db");
+ byte privateKeyData[] =
+ mStorageUnit.wrap((org.mozilla.jss.crypto.PrivateKey) privKey);
+
+ if (privateKeyData == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("NetkeyKeygenService: privatekey encryption by storage unit failed");
+ return false;
+ } else
+ CMS.debug("NetkeyKeygenService: privatekey encryption by storage unit successful");
+
+ // create key record
+ KeyRecord rec = new KeyRecord(null, publicKeyData,
+ privateKeyData, rCUID + ":" + rUserid,
+ keypair.getPublic().getAlgorithm(),
+ agentId);
+
+ CMS.debug("NetkeyKeygenService: got key record");
+
+ // we deal with RSA key only
+ try {
+ RSAPublicKey rsaPublicKey = new RSAPublicKey(publicKeyData);
+
+ rec.setKeySize(Integer.valueOf(rsaPublicKey.getKeySize()));
+ } catch (InvalidKeyException e) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(11));
+ CMS.debug("NetkeyKeygenService: failed:InvalidKeyException");
+ return false;
+ }
+ //??
+ IKeyRepository storage = mKRA.getKeyRepository();
+ BigInteger serialNo = storage.getNextSerialNumber();
+
+ if (serialNo == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(11));
+ CMS.debug("NetkeyKeygenService: serialNo null");
+ return false;
+ }
+ CMS.debug("NetkeyKeygenService: before addKeyRecord");
+ rec.set(KeyRecord.ATTR_ID, serialNo);
+ request.setExtData(ATTR_KEY_RECORD, serialNo);
+ storage.addKeyRecord(rec);
+ CMS.debug("NetkeyKeygenService: key archived for " + rCUID + ":" + rUserid);
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,
+ agentId,
+ ILogger.SUCCESS,
+ PubKey);
+
+ audit(auditMessage);
+
+ } //if archive
+
+ request.setExtData(IRequest.RESULT, Integer.valueOf(1));
+ } catch (Exception e) {
+ CMS.debug("NetKeyKeygenService: " + e.toString());
+ Debug.printStackTrace(e);
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ }
+ } else
+ request.setExtData(IRequest.RESULT, Integer.valueOf(2));
+
+ return true;
+ } //serviceRequest
+
+ /**
+ * Signed Audit Log
+ * y
+ * This method is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ private void audit(String msg) {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if (mSignedAuditLogger == null) {
+ return;
+ }
+
+ mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg);
+ }
+}
diff --git a/base/kra/src/com/netscape/kra/RecoveryService.java b/base/kra/src/com/netscape/kra/RecoveryService.java
new file mode 100644
index 000000000..c8ecdcf5a
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/RecoveryService.java
@@ -0,0 +1,710 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.ByteArrayOutputStream;
+import java.io.CharConversionException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Hashtable;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerValue;
+import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.X509Key;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.BMPString;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.PBEAlgorithm;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.pkcs12.AuthenticatedSafes;
+import org.mozilla.jss.pkcs12.CertBag;
+import org.mozilla.jss.pkcs12.PFX;
+import org.mozilla.jss.pkcs12.PasswordConverter;
+import org.mozilla.jss.pkcs12.SafeBag;
+import org.mozilla.jss.pkix.primitive.EncryptedPrivateKeyInfo;
+import org.mozilla.jss.pkix.primitive.PrivateKeyInfo;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.AuthToken;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.SessionContext;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.certsrv.kra.EKRAException;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.logging.AuditFormat;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.security.Credential;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.certsrv.util.IStatsSubsystem;
+import com.netscape.cmscore.dbs.KeyRecord;
+import com.netscape.cmscore.util.Debug;
+
+/**
+ * A class represents recovery request processor. There
+ * are 2 types of recovery modes: (1) administrator or
+ * (2) end-entity.
+ * <P>
+ * Administrator recovery will create a PKCS12 file where stores the certificate and the recovered key.
+ * <P>
+ * End Entity recovery will send RA or CA a response where stores the recovered key.
+ *
+ * @author thomask (original)
+ * @author cfu (non-RSA keys; private keys secure handling);
+ * @version $Revision$, $Date$
+ */
+public class RecoveryService implements IService {
+
+ public static final String ATTR_NICKNAME = "nickname";
+ public static final String ATTR_OWNER_NAME = "ownerName";
+ public static final String ATTR_SERIALNO = "serialNumber";
+ public static final String ATTR_PUBLIC_KEY_DATA = "publicKeyData";
+ public static final String ATTR_PRIVATE_KEY_DATA = "privateKeyData";
+ public static final String ATTR_TRANSPORT_CERT = "transportCert";
+ public static final String ATTR_TRANSPORT_PWD = "transportPwd";
+ public static final String ATTR_SIGNING_CERT = "signingCert";
+ public static final String ATTR_PKCS12 = "pkcs12";
+ public static final String ATTR_ENCRYPTION_CERTS =
+ "encryptionCerts";
+ public static final String ATTR_AGENT_CREDENTIALS =
+ "agentCredentials";
+ // same as encryption certs
+ public static final String ATTR_USER_CERT = "cert";
+ public static final String ATTR_DELIVERY = "delivery";
+
+ // for Async Key Recovery
+ public static final String ATTR_APPROVE_AGENTS = "approvingAgents";
+
+ private IKeyRecoveryAuthority mKRA = null;
+ private IKeyRepository mStorage = null;
+ private IStorageKeyUnit mStorageUnit = null;
+
+ /**
+ * Constructs request processor.
+ */
+ public RecoveryService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mStorage = mKRA.getKeyRepository();
+ mStorageUnit = mKRA.getStorageKeyUnit();
+ }
+
+ /**
+ * Processes a recovery request. Based on the recovery mode
+ * (either Administrator or End-Entity), the method reads
+ * the key record from the database, and tried to recover the
+ * key with the storage key unit.
+ *
+ * @param request recovery request
+ * @return operation success or not
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest request) throws EBaseException {
+
+ CryptoManager cm = null;
+ IConfigStore config = null;
+ String tokName = "";
+ CryptoToken ct = null;
+ Boolean allowEncDecrypt_recovery = false;
+
+ try {
+ cm = CryptoManager.getInstance();
+ config = CMS.getConfigStore();
+ tokName = config.getString("kra.storageUnit.hardware", "internal");
+ if (tokName.equals("internal")) {
+ CMS.debug("RecoveryService: serviceRequest: use internal token ");
+ ct = cm.getInternalCryptoToken();
+ } else {
+ CMS.debug("RecoveryService: serviceRequest: tokenName=" + tokName);
+ ct = cm.getTokenByName(tokName);
+ }
+ allowEncDecrypt_recovery = config.getBoolean("kra.allowEncDecrypt.recovery", false);
+ } catch (Exception e) {
+ CMS.debug("RecoveryService exception: use internal token :"
+ + e.toString());
+ ct = cm.getInternalCryptoToken();
+ }
+ if (ct == null) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR" + "cannot get crypto token"));
+ }
+
+ IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats");
+ if (statsSub != null) {
+ statsSub.startTiming("recovery", true /* main action */);
+ }
+
+ if (Debug.ON)
+ Debug.trace("KRA services recovery request");
+ mKRA.log(ILogger.LL_INFO, "KRA services recovery request");
+
+ // byte publicKey[] = (byte[])request.get(ATTR_PUBLIC_KEY_DATA);
+ // X500Name owner = (X500Name)request.get(ATTR_OWNER_NAME);
+
+ Hashtable<String, Object> params = mKRA.getVolatileRequest(
+ request.getRequestId());
+
+ if (params == null) {
+ // possibly we are in recovery mode
+ return true;
+ }
+
+ // retrieve based on serial no
+ BigInteger serialno = request.getExtDataInBigInteger(ATTR_SERIALNO);
+
+ mKRA.log(ILogger.LL_INFO, "KRA reading key record");
+ if (statsSub != null) {
+ statsSub.startTiming("get_key");
+ }
+ KeyRecord keyRecord = (KeyRecord) mStorage.readKeyRecord(serialno);
+ if (statsSub != null) {
+ statsSub.endTiming("get_key");
+ }
+
+ // see if the certificate matches the key
+ byte pubData[] = keyRecord.getPublicKeyData();
+ X509Certificate x509cert =
+ request.getExtDataInCert(ATTR_USER_CERT);
+ byte inputPubData[] = x509cert.getPublicKey().getEncoded();
+
+ if (inputPubData.length != pubData.length) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PUBLIC_KEY_LEN"));
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_PUBLIC_KEY_NOT_MATCHED"));
+ }
+ for (int i = 0; i < pubData.length; i++) {
+ if (pubData[i] != inputPubData[i]) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PUBLIC_KEY_LEN"));
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_PUBLIC_KEY_NOT_MATCHED"));
+ }
+ }
+
+ boolean isRSA = true;
+ String keyAlg = x509cert.getPublicKey().getAlgorithm();
+ if (keyAlg != null) {
+ CMS.debug("RecoveryService: publicKey alg =" + keyAlg);
+ if (!keyAlg.equals("RSA"))
+ isRSA = false;
+ }
+
+ // Unwrap the archived private key
+ byte privateKeyData[] = null;
+ X509Certificate transportCert =
+ request.getExtDataInCert(ATTR_TRANSPORT_CERT);
+
+ if (transportCert == null) {
+ if (statsSub != null) {
+ statsSub.startTiming("recover_key");
+ }
+
+ PrivateKey privKey = null;
+ if (allowEncDecrypt_recovery == true) {
+ privateKeyData = recoverKey(params, keyRecord);
+ } else {
+ privKey = recoverKey(params, keyRecord, isRSA);
+ }
+ if (statsSub != null) {
+ statsSub.endTiming("recover_key");
+ }
+
+ if ((isRSA == true) && (allowEncDecrypt_recovery == true)) {
+ if (statsSub != null) {
+ statsSub.startTiming("verify_key");
+ }
+ // verifyKeyPair() is RSA-centric
+ if (verifyKeyPair(pubData, privateKeyData) == false) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_PUBLIC_NOT_FOUND"));
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PUBLIC_KEY"));
+ }
+ if (statsSub != null) {
+ statsSub.endTiming("verify_key");
+ }
+ }
+
+ if (statsSub != null) {
+ statsSub.startTiming("create_p12");
+ }
+ if (allowEncDecrypt_recovery == true) {
+ createPFX(request, params, privateKeyData);
+ } else {
+ createPFX(request, params, privKey, ct);
+ }
+ if (statsSub != null) {
+ statsSub.endTiming("create_p12");
+ }
+ } else {
+
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ Credential creds[] = (Credential[])
+ params.get(ATTR_AGENT_CREDENTIALS);
+ mKRA.getStorageKeyUnit().login(creds);
+ }
+ if (statsSub != null) {
+ statsSub.startTiming("unwrap_key");
+ }
+ mKRA.getStorageKeyUnit().unwrap(
+ keyRecord.getPrivateKeyData(), null); // throw exception on error
+ if (statsSub != null) {
+ statsSub.endTiming("unwrap_key");
+ }
+
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ mKRA.getStorageKeyUnit().logout();
+ }
+ }
+ mKRA.log(ILogger.LL_INFO, "key " +
+ serialno.toString() +
+ " recovered");
+
+ // for audit log
+ String authMgr = AuditFormat.NOAUTH;
+ String initiative = AuditFormat.FROMUSER;
+ SessionContext sContext = SessionContext.getContext();
+
+ if (sContext != null) {
+ String agentId =
+ (String) sContext.get(SessionContext.USER_ID);
+
+ initiative = AuditFormat.FROMAGENT + " agentID: " + agentId;
+ AuthToken authToken = (AuthToken) sContext.get(SessionContext.AUTH_TOKEN);
+
+ if (authToken != null) {
+ authMgr =
+ authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME);
+ }
+ }
+ CMS.getLogger().log(ILogger.EV_AUDIT,
+ ILogger.S_KRA,
+ AuditFormat.LEVEL,
+ AuditFormat.FORMAT,
+ new Object[] {
+ IRequest.KEYRECOVERY_REQUEST,
+ request.getRequestId(),
+ initiative,
+ authMgr,
+ "completed",
+ ((X509CertImpl) x509cert).getSubjectDN(),
+ "serial number: 0x" + serialno.toString(16) }
+ );
+
+ if (statsSub != null) {
+ statsSub.endTiming("recovery");
+ }
+
+ return true;
+ }
+
+ /*
+ * verifyKeyPair()- RSA-centric key verification
+ */
+ public boolean verifyKeyPair(byte publicKeyData[], byte privateKeyData[]) {
+ try {
+ DerValue publicKeyVal = new DerValue(publicKeyData);
+ DerInputStream publicKeyIn = publicKeyVal.data;
+ publicKeyIn.getSequence(0);
+ DerValue publicKeyDer = new DerValue(publicKeyIn.getBitString());
+ DerInputStream publicKeyDerIn = publicKeyDer.data;
+ BigInt publicKeyModulus = publicKeyDerIn.getInteger();
+ BigInt publicKeyExponent = publicKeyDerIn.getInteger();
+
+ DerValue privateKeyVal = new DerValue(privateKeyData);
+ if (privateKeyVal.tag != DerValue.tag_Sequence)
+ return false;
+ DerInputStream privateKeyIn = privateKeyVal.data;
+ privateKeyIn.getInteger();
+ privateKeyIn.getSequence(0);
+ DerValue privateKeyDer = new DerValue(privateKeyIn.getOctetString());
+ DerInputStream privateKeyDerIn = privateKeyDer.data;
+
+ @SuppressWarnings("unused")
+ BigInt privateKeyVersion = privateKeyDerIn.getInteger();
+ BigInt privateKeyModulus = privateKeyDerIn.getInteger();
+ BigInt privateKeyExponent = privateKeyDerIn.getInteger();
+
+ if (!publicKeyModulus.equals(privateKeyModulus)) {
+ CMS.debug("verifyKeyPair modulus mismatch publicKeyModulus="
+ + publicKeyModulus + " privateKeyModulus=" + privateKeyModulus);
+ return false;
+ }
+
+ if (!publicKeyExponent.equals(privateKeyExponent)) {
+ CMS.debug("verifyKeyPair exponent mismatch publicKeyExponent="
+ + publicKeyExponent + " privateKeyExponent=" + privateKeyExponent);
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ CMS.debug("verifyKeyPair error " + e);
+ return false;
+ }
+ }
+
+ /**
+ * Recovers key. (using unwrapping/wrapping on token)
+ * - used when allowEncDecrypt_recovery is false
+ */
+ public synchronized PrivateKey recoverKey(Hashtable<String, Object> request, KeyRecord keyRecord, boolean isRSA)
+ throws EBaseException {
+
+ if (!isRSA) {
+ CMS.debug("RecoverService: recoverKey: currently, non-RSA keys are not supported when allowEncDecrypt_ is false");
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", "key type not supported"));
+ }
+ try {
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ Credential creds[] = (Credential[])
+ request.get(ATTR_AGENT_CREDENTIALS);
+
+ mStorageUnit.login(creds);
+ }
+
+ /* wrapped retrieve session key and private key */
+ DerValue val = new DerValue(keyRecord.getPrivateKeyData());
+ DerInputStream in = val.data;
+ DerValue dSession = in.getDerValue();
+ byte session[] = dSession.getOctetString();
+ DerValue dPri = in.getDerValue();
+ byte pri[] = dPri.getOctetString();
+
+ /* debug */
+ byte publicKeyData[] = keyRecord.getPublicKeyData();
+ PublicKey pubkey = null;
+ try {
+ pubkey = X509Key.parsePublicKey(new DerValue(publicKeyData));
+ } catch (Exception e) {
+ CMS.debug("RecoverService: after parsePublicKey:" + e.toString());
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", "pubic key parsing failure"));
+ }
+ byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ PrivateKey privKey =
+ mStorageUnit.unwrap(
+ session,
+ keyRecord.getAlgorithm(),
+ iv,
+ pri,
+ (PublicKey) pubkey);
+
+ if (privKey == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PRIVATE_KEY_NOT_FOUND"));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+ "private key unwrapping failure"));
+ }
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ mStorageUnit.logout();
+ }
+ return privKey;
+ } catch (Exception e) {
+ CMS.debug("RecoverService: recoverKey() failed with allowEncDecrypt_recovery=false:" + e.toString());
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+ "recoverKey() failed with allowEncDecrypt_recovery=false:" + e.toString()));
+ }
+ }
+
+ /**
+ * Creates a PFX (PKCS12) file. (the unwrapping/wrapping way)
+ * - used when allowEncDecrypt_recovery is false
+ *
+ * @param request CRMF recovery request
+ * @param priKey private key handle
+ * @exception EBaseException failed to create P12 file
+ */
+ public void createPFX(IRequest request, Hashtable<String, Object> params,
+ PrivateKey priKey, CryptoToken ct) throws EBaseException {
+ CMS.debug("RecoverService: createPFX() allowEncDecrypt_recovery=false");
+ try {
+ // create p12
+ X509Certificate x509cert =
+ request.getExtDataInCert(ATTR_USER_CERT);
+ String pwd = (String) params.get(ATTR_TRANSPORT_PWD);
+
+ // add certificate
+ mKRA.log(ILogger.LL_INFO, "KRA adds certificate to P12");
+ CMS.debug("RecoverService: createPFX() adds certificate to P12");
+ SEQUENCE encSafeContents = new SEQUENCE();
+ ASN1Value cert = new OCTET_STRING(x509cert.getEncoded());
+ String nickname = request.getExtDataInString(ATTR_NICKNAME);
+
+ if (nickname == null) {
+ nickname = x509cert.getSubjectDN().toString();
+ }
+ byte localKeyId[] = createLocalKeyId(x509cert);
+ SET certAttrs = createBagAttrs(
+ nickname, localKeyId);
+ // attributes: user friendly name, Local Key ID
+ SafeBag certBag = new SafeBag(SafeBag.CERT_BAG,
+ new CertBag(CertBag.X509_CERT_TYPE, cert),
+ certAttrs);
+
+ encSafeContents.addElement(certBag);
+
+ // add key
+ mKRA.log(ILogger.LL_INFO, "KRA adds key to P12");
+ CMS.debug("RecoverService: createPFX() adds key to P12");
+ org.mozilla.jss.util.Password pass = new
+ org.mozilla.jss.util.Password(
+ pwd.toCharArray());
+
+ SEQUENCE safeContents = new SEQUENCE();
+ PasswordConverter passConverter = new
+ PasswordConverter();
+ byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
+
+ ASN1Value key = EncryptedPrivateKeyInfo.createPBE(
+ PBEAlgorithm.PBE_SHA1_DES3_CBC,
+ pass, salt, 1, passConverter, priKey, ct);
+
+ SET keyAttrs = createBagAttrs(
+ x509cert.getSubjectDN().toString(),
+ localKeyId);
+
+ SafeBag keyBag = new SafeBag(
+ SafeBag.PKCS8_SHROUDED_KEY_BAG, key,
+ keyAttrs); // ??
+
+ safeContents.addElement(keyBag);
+
+ // build contents
+ AuthenticatedSafes authSafes = new
+ AuthenticatedSafes();
+
+ authSafes.addSafeContents(
+ safeContents
+ );
+ authSafes.addSafeContents(
+ encSafeContents
+ );
+
+ // authSafes.addEncryptedSafeContents(
+ // authSafes.DEFAULT_KEY_GEN_ALG,
+ // pass, null, 1,
+ // encSafeContents);
+ PFX pfx = new PFX(authSafes);
+
+ pfx.computeMacData(pass, null, 5); // ??
+ ByteArrayOutputStream fos = new
+ ByteArrayOutputStream();
+
+ pfx.encode(fos);
+ pass.clear();
+
+ // put final PKCS12 into volatile request
+ params.put(ATTR_PKCS12, fos.toByteArray());
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_CONSTRUCT_P12", e.toString()));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_PKCS12_FAILED_1", e.toString()));
+ }
+
+ // update request
+ mKRA.getRequestQueue().updateRequest(request);
+ }
+
+ /**
+ * Recovers key.
+ * - used when allowEncDecrypt_recovery is true
+ */
+ public synchronized byte[] recoverKey(Hashtable<String, Object> request, KeyRecord keyRecord)
+ throws EBaseException {
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ Credential creds[] = (Credential[])
+ request.get(ATTR_AGENT_CREDENTIALS);
+
+ mStorageUnit.login(creds);
+ }
+ mKRA.log(ILogger.LL_INFO, "KRA decrypts internal private");
+ byte privateKeyData[] =
+ mStorageUnit.decryptInternalPrivate(
+ keyRecord.getPrivateKeyData());
+
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ mStorageUnit.logout();
+ }
+ if (privateKeyData == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PRIVATE_KEY_NOT_FOUND"));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", "no private key"));
+ }
+ return privateKeyData;
+ }
+
+ /**
+ * Creates a PFX (PKCS12) file.
+ * - used when allowEncDecrypt_recovery is true
+ *
+ * @param request CRMF recovery request
+ * @param priData decrypted private key (PrivateKeyInfo)
+ * @exception EBaseException failed to create P12 file
+ */
+ public void createPFX(IRequest request, Hashtable<String, Object> params,
+ byte priData[]) throws EBaseException {
+ CMS.debug("RecoverService: createPFX() allowEncDecrypt_recovery=true");
+ try {
+ // create p12
+ X509Certificate x509cert =
+ request.getExtDataInCert(ATTR_USER_CERT);
+ String pwd = (String) params.get(ATTR_TRANSPORT_PWD);
+
+ // add certificate
+ mKRA.log(ILogger.LL_INFO, "KRA adds certificate to P12");
+ SEQUENCE encSafeContents = new SEQUENCE();
+ ASN1Value cert = new OCTET_STRING(x509cert.getEncoded());
+ String nickname = request.getExtDataInString(ATTR_NICKNAME);
+
+ if (nickname == null) {
+ nickname = x509cert.getSubjectDN().toString();
+ }
+ byte localKeyId[] = createLocalKeyId(x509cert);
+ SET certAttrs = createBagAttrs(
+ nickname, localKeyId);
+ // attributes: user friendly name, Local Key ID
+ SafeBag certBag = new SafeBag(SafeBag.CERT_BAG,
+ new CertBag(CertBag.X509_CERT_TYPE, cert),
+ certAttrs);
+
+ encSafeContents.addElement(certBag);
+
+ // add key
+ mKRA.log(ILogger.LL_INFO, "KRA adds key to P12");
+ org.mozilla.jss.util.Password pass = new
+ org.mozilla.jss.util.Password(
+ pwd.toCharArray());
+
+ SEQUENCE safeContents = new SEQUENCE();
+ PasswordConverter passConverter = new
+ PasswordConverter();
+ byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
+ PrivateKeyInfo pki = (PrivateKeyInfo)
+ ASN1Util.decode(PrivateKeyInfo.getTemplate(),
+ priData);
+ ASN1Value key = EncryptedPrivateKeyInfo.createPBE(
+ PBEAlgorithm.PBE_SHA1_DES3_CBC,
+ pass, salt, 1, passConverter, pki);
+ SET keyAttrs = createBagAttrs(
+ x509cert.getSubjectDN().toString(),
+ localKeyId);
+ SafeBag keyBag = new SafeBag(
+ SafeBag.PKCS8_SHROUDED_KEY_BAG, key,
+ keyAttrs); // ??
+
+ safeContents.addElement(keyBag);
+
+ // build contents
+ AuthenticatedSafes authSafes = new
+ AuthenticatedSafes();
+
+ authSafes.addSafeContents(
+ safeContents
+ );
+ authSafes.addSafeContents(
+ encSafeContents
+ );
+
+ // authSafes.addEncryptedSafeContents(
+ // authSafes.DEFAULT_KEY_GEN_ALG,
+ // pass, null, 1,
+ // encSafeContents);
+ PFX pfx = new PFX(authSafes);
+
+ pfx.computeMacData(pass, null, 5); // ??
+ ByteArrayOutputStream fos = new
+ ByteArrayOutputStream();
+
+ pfx.encode(fos);
+ pass.clear();
+
+ // put final PKCS12 into volatile request
+ params.put(ATTR_PKCS12, fos.toByteArray());
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_CONSTRUCT_P12", e.toString()));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_PKCS12_FAILED_1", e.toString()));
+ }
+
+ // update request
+ mKRA.getRequestQueue().updateRequest(request);
+ }
+
+ /**
+ * Creates local key identifier.
+ */
+ public byte[] createLocalKeyId(X509Certificate cert)
+ throws EBaseException {
+ try {
+ // SHA1 hash of the X509Cert der encoding
+ byte certDer[] = cert.getEncoded();
+
+ // XXX - should use JSS
+ MessageDigest md = MessageDigest.getInstance("SHA");
+
+ md.update(certDer);
+ return md.digest();
+ } catch (CertificateEncodingException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_CREAT_KEY_ID", e.toString()));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_KEYID_FAILED_1", e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_CREAT_KEY_ID", e.toString()));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_KEYID_FAILED_1", e.toString()));
+ }
+ }
+
+ /**
+ * Creates bag attributes.
+ */
+ public SET createBagAttrs(String nickName, byte localKeyId[])
+ throws EBaseException {
+ try {
+ SET attrs = new SET();
+ SEQUENCE nickNameAttr = new SEQUENCE();
+
+ nickNameAttr.addElement(SafeBag.FRIENDLY_NAME);
+ SET nickNameSet = new SET();
+
+ nickNameSet.addElement(new BMPString(nickName));
+ nickNameAttr.addElement(nickNameSet);
+ attrs.addElement(nickNameAttr);
+ SEQUENCE localKeyAttr = new SEQUENCE();
+
+ localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID);
+ SET localKeySet = new SET();
+
+ localKeySet.addElement(new OCTET_STRING(localKeyId));
+ localKeyAttr.addElement(localKeySet);
+ attrs.addElement(localKeyAttr);
+ return attrs;
+ } catch (CharConversionException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_CREAT_KEY_BAG", e.toString()));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_KEYBAG_FAILED_1", e.toString()));
+ }
+ }
+}
diff --git a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
new file mode 100644
index 000000000..f96ece890
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
@@ -0,0 +1,388 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.ByteArrayOutputStream;
+import java.io.CharConversionException;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+import java.util.Random;
+
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.crypto.Cipher;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.KeyGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.PBEAlgorithm;
+import org.mozilla.jss.crypto.PBEKeyGenParams;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.pkcs12.PasswordConverter;
+import org.mozilla.jss.pkcs7.ContentInfo;
+import org.mozilla.jss.pkcs7.EncryptedContentInfo;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+import org.mozilla.jss.pkix.primitive.PBEParameter;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.certsrv.kra.EKRAException;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.certsrv.security.ITransportKeyUnit;
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.dbs.keydb.IKeyRecord;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.cms.servlet.request.KeyRequestResource;
+import com.netscape.cmscore.dbs.KeyRecord;
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * This implementation services SecurityData Recovery requests.
+ * <p>
+ *
+ * @version $Revision$, $Date$
+ */
+@SuppressWarnings("deprecation")
+public class SecurityDataRecoveryService implements IService {
+
+ private IKeyRecoveryAuthority mKRA = null;
+
+ private IKeyRepository mStorage = null;
+ private IStorageKeyUnit mStorageUnit = null;
+ private ITransportKeyUnit mTransportUnit = null;
+
+ public static final String ATTR_SERIALNO = "serialNumber";
+ public static final String ATTR_KEY_RECORD = "keyRecord";
+
+ public SecurityDataRecoveryService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mStorage = mKRA.getKeyRepository();
+ mStorageUnit = mKRA.getStorageKeyUnit();
+ mTransportUnit = mKRA.getTransportKeyUnit();
+
+ }
+
+ /**
+ * Performs the service (such as certificate generation)
+ * represented by this request.
+ * <p>
+ *
+ * @param request
+ * The SecurityData recovery request that needs service. The service may use
+ * attributes stored in the request, and may update the
+ * values, or store new ones.
+ * @return
+ * an indication of whether this request is still pending.
+ * 'false' means the request will wait for further notification.
+ * @exception EBaseException indicates major processing failure.
+ */
+ public boolean serviceRequest(IRequest request)
+ throws EBaseException {
+
+ //Pave the way for allowing generated IV vector
+ byte iv[]= null;
+ byte iv_default[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ byte iv_in[] = null;
+
+ Hashtable<String, Object> params = mKRA.getVolatileRequest(
+ request.getRequestId());
+
+ if (params == null) {
+ CMS.debug("Can't get volatile params.");
+ throw new EBaseException("Can't obtain volatile params!");
+ }
+
+ BigInteger serialno = request.getExtDataInBigInteger(ATTR_SERIALNO);
+
+ request.setExtData(ATTR_KEY_RECORD, serialno);
+
+ byte[] wrappedPassPhrase = null;
+ byte[] wrappedSessKey = null;
+
+ String transWrappedSessKeyStr = (String) params.get(IRequest.SECURITY_DATA_TRANS_SESS_KEY);
+ if (transWrappedSessKeyStr != null) {
+ wrappedSessKey = Utils.base64decode(transWrappedSessKeyStr);
+ }
+
+ String sessWrappedPassPhraseStr = (String) params.get(IRequest.SECURITY_DATA_SESS_PASS_PHRASE);
+ if (sessWrappedPassPhraseStr != null) {
+ wrappedPassPhrase = Utils.base64decode(sessWrappedPassPhraseStr);
+ }
+
+ String ivInStr = (String) params.get(IRequest.SECURITY_DATA_IV_STRING_IN);
+ if (ivInStr != null) {
+ iv_in = Utils.base64decode(ivInStr);
+ }
+
+ if (transWrappedSessKeyStr == null && sessWrappedPassPhraseStr == null) {
+ //We may be in recovery case where no params were initially submitted.
+ return false;
+ }
+
+ //Create the return IV if needed.
+ iv = new byte[8];
+
+ try {
+ Random rnd = new Random();
+ rnd.nextBytes(iv);
+ } catch (Exception e) {
+ iv = iv_default;
+ }
+
+ String ivStr = Utils.base64encode(iv);
+
+ KeyRecord keyRecord = (KeyRecord) mStorage.readKeyRecord(serialno);
+
+ SymmetricKey unwrappedSess = null;
+
+ String dataType = (String) keyRecord.get(IKeyRecord.ATTR_DATA_TYPE);
+ SymmetricKey symKey = null;
+ byte[] unwrappedSecData = null;
+ if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+ symKey = recoverSymKey(keyRecord);
+ } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+ unwrappedSecData = recoverSecurityData(keyRecord);
+ }
+
+ CryptoToken ct = mTransportUnit.getToken();
+
+ byte[] key_data = null;
+ String pbeWrappedData = null;
+
+ if (sessWrappedPassPhraseStr != null) { //We have a trans wrapped pass phrase, we will be doing PBE packaging
+ byte[] unwrappedPass = null;
+ Password pass = null;
+
+ try {
+ unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.DECRYPT);
+ Cipher decryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
+ decryptor.initDecrypt(unwrappedSess, new IVParameterSpec(iv_in));
+ unwrappedPass = decryptor.doFinal(wrappedPassPhrase);
+ String passStr = new String(unwrappedPass, "UTF-8");
+
+ pass = new Password(passStr.toCharArray());
+ passStr = null;
+
+ if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+ pbeWrappedData = createEncryptedContentInfo(ct, symKey, null,
+ pass);
+ } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+ pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData,
+ pass);
+ }
+
+ params.put(IRequest.SECURITY_DATA_PASS_WRAPPED_DATA, pbeWrappedData);
+
+ } catch (Exception e) {
+ throw new EBaseException("Can't unwrap pass phase! " + e.toString());
+ } finally {
+ if ( pass != null) {
+ pass.clear();
+ }
+
+ if ( unwrappedPass != null) {
+ java.util.Arrays.fill(unwrappedPass, (byte) 0);
+ }
+ }
+
+ } else { // No trans wrapped pass phrase, return session wrapped data.
+ if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+ //wrap the key with session key
+ try {
+ unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.WRAP);
+ KeyWrapper wrapper = ct.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+ wrapper.initWrap(unwrappedSess, new IVParameterSpec(iv));
+ key_data = wrapper.wrap(symKey);
+ } catch (Exception e) {
+ throw new EBaseException("Can't wrap symmetric key! " + e.toString());
+ }
+
+ } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+ try {
+ unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.ENCRYPT);
+ Cipher encryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
+ if (encryptor != null) {
+ encryptor.initEncrypt(unwrappedSess, new IVParameterSpec(iv));
+ key_data = encryptor.doFinal(unwrappedSecData);
+ } else {
+ throw new IOException("Failed to create cipher");
+ }
+ } catch (Exception e) {
+ throw new EBaseException("Can't wrap pass phrase!");
+ }
+ }
+
+ String wrappedKeyData = Utils.base64encode(key_data);
+ params.put(IRequest.SECURITY_DATA_SESS_WRAPPED_DATA, wrappedKeyData);
+ params.put(IRequest.SECURITY_DATA_IV_STRING_OUT, ivStr);
+
+ }
+ return false;
+ }
+
+ public SymmetricKey recoverSymKey(KeyRecord keyRecord)
+ throws EBaseException {
+
+ try {
+ SymmetricKey symKey =
+ mStorageUnit.unwrap(
+ keyRecord.getPrivateKeyData());
+
+ if (symKey == null) {
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+ "symmetric key unwrapping failure"));
+ }
+
+ return symKey;
+ } catch (Exception e) {
+
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+ "recoverSymKey() " + e.toString()));
+ }
+ }
+
+ public byte[] recoverSecurityData(KeyRecord keyRecord)
+ throws EBaseException {
+
+ byte[] decodedData = null;
+
+ try {
+ decodedData = mStorageUnit.decryptInternalPrivate(
+ keyRecord.getPrivateKeyData());
+
+ if (decodedData == null) {
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+ "security data unwrapping failure"));
+ }
+
+ return decodedData;
+ } catch (Exception e) {
+
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+ "recoverSecurityData() " + e.toString()));
+ }
+ }
+
+ //ToDo: This might fit in JSS.
+ private static EncryptedContentInfo
+ createEncryptedContentInfoPBEOfSymmKey(PBEAlgorithm keyGenAlg, Password password, byte[] salt,
+ int iterationCount,
+ KeyGenerator.CharToByteConverter charToByteConverter,
+ SymmetricKey symKey, CryptoToken token)
+ throws CryptoManager.NotInitializedException, NoSuchAlgorithmException,
+ InvalidKeyException, InvalidAlgorithmParameterException, TokenException,
+ CharConversionException {
+
+ if (!(keyGenAlg instanceof PBEAlgorithm)) {
+ throw new NoSuchAlgorithmException("Key generation algorithm" +
+ " is not a PBE algorithm");
+ }
+ PBEAlgorithm pbeAlg = (PBEAlgorithm) keyGenAlg;
+
+ KeyGenerator kg = token.getKeyGenerator(keyGenAlg);
+ PBEKeyGenParams pbekgParams = new PBEKeyGenParams(
+ password, salt, iterationCount);
+ if (charToByteConverter != null) {
+ kg.setCharToByteConverter(charToByteConverter);
+ }
+ kg.initialize(pbekgParams);
+ SymmetricKey key = kg.generate();
+
+ EncryptionAlgorithm encAlg = pbeAlg.getEncryptionAlg();
+ AlgorithmParameterSpec params = null;
+ if (encAlg.getParameterClass().equals(IVParameterSpec.class)) {
+ params = new IVParameterSpec(kg.generatePBE_IV());
+ } else if (encAlg.getParameterClass().equals(
+ RC2ParameterSpec.class)) {
+ params = new RC2ParameterSpec(key.getStrength(),
+ kg.generatePBE_IV());
+ }
+
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+ wrapper.initWrap(key, params);
+ byte encrypted[] = wrapper.wrap(symKey);
+
+ PBEParameter pbeParam = new PBEParameter(salt, iterationCount);
+ AlgorithmIdentifier encAlgID = new AlgorithmIdentifier(
+ keyGenAlg.toOID(), pbeParam);
+
+ EncryptedContentInfo encCI = new EncryptedContentInfo(
+ ContentInfo.DATA,
+ encAlgID,
+ new OCTET_STRING(encrypted));
+
+ return encCI;
+
+ }
+
+ private static String createEncryptedContentInfo(CryptoToken ct, SymmetricKey symKey, byte[] securityData,
+ Password password)
+ throws EBaseException {
+
+ EncryptedContentInfo cInfo = null;
+ String retData = null;
+ PBEAlgorithm keyGenAlg = PBEAlgorithm.PBE_SHA1_DES3_CBC;
+
+ byte[] encoded = null;
+ try {
+ PasswordConverter passConverter = new
+ PasswordConverter();
+ byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
+ if (symKey != null) {
+
+ cInfo = createEncryptedContentInfoPBEOfSymmKey(keyGenAlg, password, salt,
+ 1,
+ passConverter,
+ symKey, ct);
+
+ } else if (securityData != null) {
+
+ cInfo = EncryptedContentInfo.createPBE(keyGenAlg, password, salt, 1, passConverter, securityData);
+ }
+
+ if(cInfo == null) {
+ throw new EBaseException("Can't create a PBE wrapped EncryptedContentInfo!");
+ }
+
+ ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+ cInfo.encode(oStream);
+ encoded = oStream.toByteArray();
+ retData = Utils.base64encode(encoded);
+
+ } catch (Exception e) {
+ throw new EBaseException("Can't create a PBE wrapped EncryptedContentInfo! " + e.toString());
+ }
+
+ return retData;
+ }
+
+}
diff --git a/base/kra/src/com/netscape/kra/SecurityDataService.java b/base/kra/src/com/netscape/kra/SecurityDataService.java
new file mode 100644
index 000000000..fa009dac9
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/SecurityDataService.java
@@ -0,0 +1,171 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.math.BigInteger;
+import org.mozilla.jss.crypto.SymmetricKey;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.profile.IEnrollProfile;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.certsrv.security.ITransportKeyUnit;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.dbs.keydb.IKeyRecord;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.cms.servlet.request.KeyRequestResource;
+import com.netscape.cmscore.dbs.KeyRecord;
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * This implementation implements SecurityData archival operations.
+ * <p>
+ *
+ * @version $Revision$, $Date$
+ */
+public class SecurityDataService implements IService {
+
+ private final static String DEFAULT_OWNER = "IPA Agent";
+ public final static String ATTR_KEY_RECORD = "keyRecord";
+ private final static String STATUS_ACTIVE = "active";
+
+ private IKeyRecoveryAuthority mKRA = null;
+ private ITransportKeyUnit mTransportUnit = null;
+ private IStorageKeyUnit mStorageUnit = null;
+
+ public SecurityDataService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mTransportUnit = kra.getTransportKeyUnit();
+ mStorageUnit = kra.getStorageKeyUnit();
+ }
+
+ /**
+ * Performs the service of archiving Security Data.
+ * represented by this request.
+ * <p>
+ *
+ * @param request
+ * The request that needs service. The service may use
+ * attributes stored in the request, and may update the
+ * values, or store new ones.
+ * @return
+ * an indication of whether this request is still pending.
+ * 'false' means the request will wait for further notification.
+ * @exception EBaseException indicates major processing failure.
+ */
+ public boolean serviceRequest(IRequest request)
+ throws EBaseException {
+ String id = request.getRequestId().toString();
+ String clientId = request.getExtDataInString(IRequest.SECURITY_DATA_CLIENT_ID);
+ String wrappedSecurityData = request.getExtDataInString(IEnrollProfile.REQUEST_ARCHIVE_OPTIONS);
+ String dataType = request.getExtDataInString(IRequest.SECURITY_DATA_TYPE);
+
+ CMS.debug("SecurityDataService.serviceRequest. Request id: " + id);
+ CMS.debug("SecurityDataService.serviceRequest wrappedSecurityData: " + wrappedSecurityData);
+
+ String owner = getOwnerName(request);
+
+ //Check here even though restful layer checks for this.
+ if(wrappedSecurityData == null || clientId == null || dataType == null) {
+ throw new EBaseException("Bad data in SecurityDataService.serviceRequest");
+ }
+ //We need some info from the PKIArchiveOptions wrapped security data
+
+ byte[] encoded = Utils.base64decode(wrappedSecurityData);
+
+ ArchiveOptions options = ArchiveOptions.toArchiveOptions(encoded);
+
+ //Check here just in case a null ArchiveOptions makes it this far
+ if(options == null) {
+ throw new EBaseException("Problem decofing PKIArchiveOptions.");
+ }
+
+ String algStr = options.getSymmAlgOID();
+
+ SymmetricKey securitySymKey = null;
+ byte[] securityData = null;
+
+ String keyType = null;
+ if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+ // Symmetric Key
+ keyType = KeyRequestResource.SYMMETRIC_KEY_TYPE;
+ securitySymKey = mTransportUnit.unwrap_symmetric(options.getEncSymmKey(),
+ options.getSymmAlgOID(),
+ options.getSymmAlgParams(),
+ options.getEncValue());
+
+ } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+ keyType = KeyRequestResource.PASS_PHRASE_TYPE;
+ securityData = mTransportUnit.decryptExternalPrivate(options.getEncSymmKey(),
+ options.getSymmAlgOID(),
+ options.getSymmAlgParams(),
+ options.getEncValue());
+
+ }
+
+ byte[] publicKey = null;
+ byte privateSecurityData[] = null;
+
+ if (securitySymKey != null) {
+ privateSecurityData = mStorageUnit.wrap(securitySymKey);
+ } else if (securityData != null) {
+ privateSecurityData = mStorageUnit.encryptInternalPrivate(securityData);
+ } else { // We have no data.
+ throw new EBaseException("Failed to create security data to archive!");
+ }
+ // create key record
+ KeyRecord rec = new KeyRecord(null, publicKey,
+ privateSecurityData, owner,
+ algStr, owner);
+
+ rec.set(IKeyRecord.ATTR_CLIENT_ID, clientId);
+
+ //Now we need a serial number for our new key.
+
+ if (rec.getSerialNumber() != null) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"));
+ }
+
+ IKeyRepository storage = mKRA.getKeyRepository();
+ BigInteger serialNo = storage.getNextSerialNumber();
+
+ if (serialNo == null) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_NEXT_SERIAL"));
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"));
+ }
+
+ rec.set(KeyRecord.ATTR_ID, serialNo);
+ rec.set(KeyRecord.ATTR_DATA_TYPE, keyType);
+ rec.set(KeyRecord.ATTR_STATUS, STATUS_ACTIVE);
+ request.setExtData(ATTR_KEY_RECORD, serialNo);
+
+ CMS.debug("KRA adding Security Data key record " + serialNo);
+
+ storage.addKeyRecord(rec);
+
+ return true;
+
+ }
+ //ToDo: return real owner with auth
+ private String getOwnerName(IRequest request) {
+ return DEFAULT_OWNER;
+ }
+} \ No newline at end of file
diff --git a/base/kra/src/com/netscape/kra/StorageKeyUnit.java b/base/kra/src/com/netscape/kra/StorageKeyUnit.java
new file mode 100644
index 000000000..c956bf8d8
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/StorageKeyUnit.java
@@ -0,0 +1,978 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.CharConversionException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.Cipher;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
+import org.mozilla.jss.crypto.KeyGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.PBEAlgorithm;
+import org.mozilla.jss.crypto.PBEKeyGenParams;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenCertificate;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.ISubsystem;
+import com.netscape.certsrv.kra.EKRAException;
+import com.netscape.certsrv.kra.IJoinShares;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.kra.IShare;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.security.Credential;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * A class represents a storage key unit. Currently, this
+ * is implemented with cryptix, the final implementation
+ * should be built on JSS/HCL.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class StorageKeyUnit extends EncryptionUnit implements
+ ISubsystem, IStorageKeyUnit {
+
+ private IConfigStore mConfig = null;
+
+ // private RSAPublicKey mPublicKey = null;
+ // private RSAPrivateKey mPrivateKey = null;
+
+ private IConfigStore mStorageConfig = null;
+ private IKeyRecoveryAuthority mKRA = null;
+ private String mTokenFile = null;
+ private X509Certificate mCert = null;
+ private CryptoManager mManager = null;
+ private CryptoToken mToken = null;
+ private PrivateKey mPrivateKey = null;
+ private byte mPrivateKeyData[] = null;
+ private boolean mKeySplitting = false;
+
+ private static final String PROP_N = "n";
+ private static final String PROP_M = "m";
+ private static final String PROP_UID = "uid";
+ private static final String PROP_SHARE = "share";
+ private static final String PROP_HARDWARE = "hardware";
+ private static final String PROP_LOGOUT = "logout";
+ public static final String PROP_NICKNAME = "nickName";
+ public static final String PROP_KEYDB = "keydb";
+ public static final String PROP_CERTDB = "certdb";
+ public static final String PROP_MN = "mn";
+
+ /**
+ * Constructs this token.
+ */
+ public StorageKeyUnit() {
+ super();
+ }
+
+ /**
+ * Retrieves subsystem identifier.
+ */
+ public String getId() {
+ return "storageKeyUnit";
+ }
+
+ /**
+ * Sets subsystem identifier. Once the system is
+ * loaded, system identifier cannot be changed
+ * dynamically.
+ */
+ public void setId(String id) throws EBaseException {
+ throw new EBaseException(CMS.getUserMessage("CMS_INVALID_OPERATION"));
+ }
+
+ /**
+ * return true if byte arrays are equal, false otherwise
+ */
+ private boolean byteArraysMatch(byte a[], byte b[]) {
+ if (a == null || b == null) {
+ return false;
+ }
+ if (a.length != b.length) {
+ return false;
+ }
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Initializes this subsystem.
+ */
+ public void init(ISubsystem owner, IConfigStore config)
+ throws EBaseException {
+ mKRA = (IKeyRecoveryAuthority) owner;
+ mConfig = config;
+
+ mKeySplitting = owner.getConfigStore().getBoolean("keySplitting", false);
+
+ try {
+ mManager = CryptoManager.getInstance();
+ mToken = getToken();
+ } catch (org.mozilla.jss.CryptoManager.NotInitializedException e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_STORAGE_INIT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+
+ if (mConfig.getString(PROP_HARDWARE, null) != null) {
+ System.setProperty("cms.skip_token", mConfig.getString(PROP_HARDWARE));
+
+ // The strategy here is to read all the certs in the token
+ // and cycle through them until we find one that matches the
+ // kra-cert.db file
+
+ if (mKeySplitting) {
+
+ byte certFileData[] = null;
+ try {
+ File certFile = new File(
+ mConfig.getString(PROP_CERTDB));
+
+ certFileData = new byte[
+ (Long.valueOf(certFile.length())).intValue()];
+ FileInputStream fi = new FileInputStream(certFile);
+
+ fi.read(certFileData);
+ fi.close();
+
+ // pick up cert by nickName
+
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_INFO,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+
+ try {
+ X509Certificate certs[] =
+ getToken().getCryptoStore().getCertificates();
+ for (int i = 0; i < certs.length; i++) {
+ if (byteArraysMatch(certs[i].getEncoded(), certFileData)) {
+ mCert = certs[i];
+ }
+ }
+ if (mCert == null) {
+ mKRA.log(ILogger.LL_FAILURE,
+ "Storage Cert could not be initialized. No cert in token matched kra-cert file");
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", "mCert == null"));
+ } else {
+ mKRA.log(ILogger.LL_INFO, "Using Storage Cert " + mCert.getSubjectDN());
+ }
+ } catch (CertificateEncodingException e) {
+ mKRA.log(ILogger.LL_FAILURE, "Error encoding cert ");
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ } catch (TokenException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+ }
+
+ } else {
+
+ // read certificate from file
+ byte certData[] = null;
+
+ try {
+ if (mKeySplitting) {
+ File certFile = new File(
+ mConfig.getString(PROP_CERTDB));
+
+ certData = new byte[
+ (Long.valueOf(certFile.length())).intValue()];
+ FileInputStream fi = new FileInputStream(certFile);
+
+ fi.read(certData);
+ fi.close();
+
+ // pick up cert by nickName
+ mCert = mManager.findCertByNickname(
+ config.getString(PROP_NICKNAME));
+
+ } else {
+ mCert = mManager.findCertByNickname(
+ config.getString(PROP_NICKNAME));
+ }
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ } catch (TokenException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ } catch (ObjectNotFoundException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ // XXX - this import wont work
+ try {
+ mCert = mManager.importCertPackage(certData,
+ "kraStorageCert");
+ } catch (Exception ex) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_IMPORT_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", ex.toString()));
+ }
+ }
+
+ if (mKeySplitting) {
+ // read private key from the file
+ try {
+ File priFile = new File(mConfig.getString(PROP_KEYDB));
+
+ mPrivateKeyData = new byte[
+ (Long.valueOf(priFile.length())).intValue()];
+ FileInputStream fi = new FileInputStream(priFile);
+
+ fi.read(mPrivateKeyData);
+ fi.close();
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_PRIVATE", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1", e.toString()));
+ }
+ }
+
+ }
+
+ if (mKeySplitting) {
+ // open internal data storage configuration
+ mTokenFile = mConfig.getString(PROP_MN);
+ try {
+ // read m, n and no of identifier
+ mStorageConfig = CMS.createFileConfigStore(mTokenFile);
+ } catch (EBaseException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_MN",
+ e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_OPERATION"));
+
+ }
+ }
+
+ try {
+ if (mCert == null) {
+ CMS.debug("mCert is null...retrieving " + config.getString(PROP_NICKNAME));
+ mCert = mManager.findCertByNickname(
+ config.getString(PROP_NICKNAME));
+ CMS.debug("mCert = " + mCert);
+ }
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+
+ }
+
+ /**
+ * Starts up this subsystem.
+ */
+ public void startup() throws EBaseException {
+ }
+
+ /**
+ * Shutdowns this subsystem.
+ */
+ public void shutdown() {
+ }
+
+ /**
+ * Returns the configuration store of this token.
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public static SymmetricKey buildSymmetricKeyWithInternalStorage(
+ String pin) throws EBaseException {
+ try {
+ return buildSymmetricKey(CryptoManager.getInstance().getInternalKeyStorageToken(), pin);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Builds symmetric key from the given password.
+ */
+ public static SymmetricKey buildSymmetricKey(CryptoToken token,
+ String pin) throws EBaseException {
+ try {
+
+ Password pass = new Password(pin.toCharArray());
+ KeyGenerator kg = null;
+
+ kg = token.getKeyGenerator(
+ PBEAlgorithm.PBE_SHA1_DES3_CBC);
+ byte salt[] = { 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01 };
+ PBEKeyGenParams kgp = new PBEKeyGenParams(pass,
+ salt, 5);
+
+ pass.clear();
+ kg.initialize(kgp);
+ return kg.generate();
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "buildSymmetricKey:" +
+ e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "buildSymmetricKey:" +
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "buildSymmetricKey:" +
+ e.toString()));
+ } catch (CharConversionException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "buildSymmetricKey:" +
+ e.toString()));
+ }
+ }
+
+ /**
+ * Unwraps the storage key with the given symmetric key.
+ */
+ public PrivateKey unwrapStorageKey(CryptoToken token,
+ SymmetricKey sk, byte wrapped[],
+ PublicKey pubKey)
+ throws EBaseException {
+ try {
+
+ CMS.debug("StorageKeyUnit.unwrapStorageKey.");
+
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+
+ wrapper.initUnwrap(sk, IV);
+
+ // XXX - it does not like the public key that is
+ // not a crypto X509Certificate
+ PrivateKey pk = wrapper.unwrapTemporaryPrivate(wrapped,
+ PrivateKey.RSA, pubKey);
+
+ return pk;
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "unwrapStorageKey:" +
+ e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "unwrapStorageKey:" +
+ e.toString()));
+ } catch (InvalidKeyException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "unwrapStorageKey:" +
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "unwrapStorageKey:" +
+ e.toString()));
+ }
+ }
+
+ /**
+ * Used by config-cert.
+ */
+ public byte[] wrapStorageKey(CryptoToken token,
+ SymmetricKey sk, PrivateKey pri)
+ throws EBaseException {
+ CMS.debug("StorageKeyUnit.wrapStorageKey.");
+ try {
+ // move public & private to config/storage.dat
+ // delete private key
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+
+ // next to randomly generate a symmetric
+ // password
+
+ wrapper.initWrap(sk, IV);
+ return wrapper.wrap(pri);
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "wrapStorageKey:" +
+ e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "wrapStorageKey:" +
+ e.toString()));
+ } catch (InvalidKeyException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "wrapStorageKey:" +
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "wrapStorageKey:" +
+ e.toString()));
+ }
+ }
+
+ /**
+ * Logins to this token.
+ */
+ public void login(String pin) throws EBaseException {
+ if (mConfig.getString(PROP_HARDWARE, null) != null) {
+ try {
+ getToken().login(new Password(pin.toCharArray()));
+ PrivateKey pk[] = getToken().getCryptoStore().getPrivateKeys();
+
+ for (int i = 0; i < pk.length; i++) {
+ if (arraysEqual(pk[i].getUniqueID(),
+ ((TokenCertificate) mCert).getUniqueID())) {
+ mPrivateKey = pk[i];
+ }
+ }
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_STORAGE_LOGIN", e.toString()));
+ }
+
+ } else {
+ try {
+ SymmetricKey sk = buildSymmetricKey(mToken, pin);
+
+ mPrivateKey = unwrapStorageKey(mToken, sk,
+ mPrivateKeyData, getPublicKey());
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_STORAGE_LOGIN", e.toString()));
+ }
+ if (mPrivateKey == null) {
+ mPrivateKey = getPrivateKey();
+ }
+ }
+ }
+
+ /**
+ * Logins to this token.
+ */
+ public void login(Credential creds[])
+ throws EBaseException {
+ String pwd = constructPassword(creds);
+
+ login(pwd);
+ }
+
+ /**
+ * Logout from this token.
+ */
+ public void logout() {
+ try {
+ if (mConfig.getString(PROP_HARDWARE, null) != null) {
+ if (mConfig.getBoolean(PROP_LOGOUT, false)) {
+ getToken().logout();
+ }
+ }
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_STORAGE_LOGOUT", e.toString()));
+
+ }
+ mPrivateKey = null;
+ }
+
+ /**
+ * Returns a list of recovery agent identifiers.
+ */
+ public Enumeration<String> getAgentIdentifiers() {
+ Vector<String> v = new Vector<String>();
+
+ for (int i = 0;; i++) {
+ try {
+ String uid =
+ mStorageConfig.getString(PROP_UID + i);
+
+ if (uid == null)
+ break;
+ v.addElement(uid);
+ } catch (EBaseException e) {
+ break;
+ }
+ }
+ return v.elements();
+ }
+
+ /**
+ * Changes agent password.
+ */
+ public boolean changeAgentPassword(String id, String oldpwd,
+ String newpwd) throws EBaseException {
+ // locate the id(s)
+ for (int i = 0;; i++) {
+ try {
+ String uid =
+ mStorageConfig.getString(PROP_UID + i);
+
+ if (uid == null)
+ break;
+ if (id.equals(uid)) {
+ byte share[] = decryptShareWithInternalStorage(mStorageConfig.getString(PROP_SHARE + i), oldpwd);
+
+ mStorageConfig.putString(PROP_SHARE + i,
+ encryptShareWithInternalStorage(
+ share, newpwd));
+ mStorageConfig.commit(false);
+ return true;
+ }
+ } catch (Exception e) {
+ break;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Changes the m out of n recovery schema.
+ */
+ public boolean changeAgentMN(int new_n, int new_m,
+ Credential oldcreds[],
+ Credential newcreds[])
+ throws EBaseException {
+
+ if (new_n != newcreds.length) {
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_N"));
+ }
+
+ // XXX - verify and construct original password
+ String secret = constructPassword(oldcreds);
+
+ // XXX - remove extra configuration
+ for (int j = new_n; j < getNoOfAgents(); j++) {
+ mStorageConfig.remove(PROP_UID + j);
+ mStorageConfig.remove(PROP_SHARE + j);
+ }
+
+ // XXX - split pwd into n pieces
+ byte shares[][] = new byte[newcreds.length][];
+
+ IShare s = null;
+ try {
+ String className = mConfig.getString("share_class",
+ "com.netscape.cms.shares.OldShare");
+ s = (IShare) Class.forName(className).newInstance();
+ } catch (Exception e) {
+ CMS.debug("Loading Shares error " + e);
+ }
+ if (s == null) {
+ CMS.debug("Share plugin is not found");
+ return false;
+ }
+
+ try {
+ s.initialize(secret.getBytes(), new_m);
+ } catch (Exception e) {
+ CMS.debug("Failed to initialize Share plugin");
+ return false;
+ }
+
+ for (int i = 0; i < newcreds.length; i++) {
+ byte share[] = s.createShare(i + 1);
+
+ shares[i] = share;
+ }
+
+ // store the new shares into configuration
+ mStorageConfig.putInteger(PROP_N, new_n);
+ mStorageConfig.putInteger(PROP_M, new_m);
+ for (int i = 0; i < newcreds.length; i++) {
+ mStorageConfig.putString(PROP_UID + i,
+ newcreds[i].getIdentifier());
+ // use password to encrypt shares...
+ mStorageConfig.putString(PROP_SHARE + i,
+ encryptShareWithInternalStorage(shares[i],
+ newcreds[i].getPassword()));
+ }
+
+ try {
+ mStorageConfig.commit(false);
+ return true;
+ } catch (EBaseException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_CHANGE_MN", e.toString()));
+ }
+ return false;
+ }
+
+ /**
+ * Returns number of recovery agents.
+ */
+ public int getNoOfAgents() throws EBaseException {
+ return mStorageConfig.getInteger(PROP_N);
+ }
+
+ /**
+ * Returns number of recovery agents required for
+ * recovery operation.
+ */
+ public int getNoOfRequiredAgents() throws EBaseException {
+ return mStorageConfig.getInteger(PROP_M);
+ }
+
+ public void setNoOfRequiredAgents(int number) {
+ mStorageConfig.putInteger(PROP_M, number);
+ }
+
+ public CryptoToken getInternalToken() {
+ try {
+ return CryptoManager.getInstance().getInternalKeyStorageToken();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public CryptoToken getToken() {
+ try {
+ if (mConfig.getString(PROP_HARDWARE, null) != null) {
+ return mManager.getTokenByName(mConfig.getString(PROP_HARDWARE));
+ } else {
+ return CryptoManager.getInstance().getInternalKeyStorageToken();
+ }
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the certificate blob.
+ */
+ public PublicKey getPublicKey() {
+ // NEED to move this key into internal storage token.
+ return mCert.getPublicKey();
+ }
+
+ public PrivateKey getPrivateKey() {
+
+ if (!mKeySplitting) {
+ try {
+ PrivateKey pk[] = getToken().getCryptoStore().getPrivateKeys();
+ for (int i = 0; i < pk.length; i++) {
+ if (arraysEqual(pk[i].getUniqueID(),
+ ((TokenCertificate) mCert).getUniqueID())) {
+ return pk[i];
+ }
+ }
+ } catch (TokenException e) {
+ }
+ return null;
+ } else {
+ return mPrivateKey;
+ }
+ }
+
+ /**
+ * Verifies the integrity of the given key pairs.
+ */
+ public void verify(byte publicKey[], PrivateKey privateKey)
+ throws EBaseException {
+ // XXX
+ }
+
+ public String encryptShareWithInternalStorage(
+ byte share[], String pwd)
+ throws EBaseException {
+ try {
+ return encryptShare(CryptoManager.getInstance().getInternalKeyStorageToken(), share, pwd);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Protectes the share with the given password.
+ */
+ public String encryptShare(CryptoToken token,
+ byte share[], String pwd)
+ throws EBaseException {
+ try {
+ CMS.debug("StorageKeyUnit.encryptShare");
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+ SymmetricKey sk = StorageKeyUnit.buildSymmetricKey(token, pwd);
+
+ cipher.initEncrypt(sk, IV);
+ byte prev[] = preVerify(share);
+ byte enc[] = cipher.doFinal(prev);
+
+ return Utils.base64encode(enc).trim();
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (InvalidKeyException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (BadPaddingException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (IllegalBlockSizeException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ }
+ }
+
+ public static byte[] preVerify(byte share[]) {
+ byte data[] = new byte[share.length + 2];
+
+ data[0] = 0;
+ data[1] = 0;
+ for (int i = 0; i < share.length; i++) {
+ data[2 + i] = share[i];
+ }
+ return data;
+ }
+
+ public static boolean verifyShare(byte share[]) {
+ if (share[0] == 0 && share[1] == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static byte[] postVerify(byte share[]) {
+ byte data[] = new byte[share.length - 2];
+
+ for (int i = 2; i < share.length; i++) {
+ data[i - 2] = share[i];
+ }
+ return data;
+ }
+
+ public void checkPassword(String userid, String pwd) throws EBaseException {
+ for (int i = 0;; i++) {
+ String uid = null;
+
+ try {
+ uid = mStorageConfig.getString(PROP_UID + i);
+ if (uid == null)
+ break;
+ } catch (Exception e) {
+ break;
+ }
+ if (uid.equals(userid)) {
+ byte data[] = decryptShareWithInternalStorage(
+ mStorageConfig.getString(PROP_SHARE + i),
+ pwd);
+ if (data == null) {
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ return;
+ }
+ }
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ }
+
+ public byte[] decryptShareWithInternalStorage(
+ String encoding, String pwd)
+ throws EBaseException {
+ try {
+ return decryptShare(CryptoManager.getInstance().getInternalKeyStorageToken(), encoding, pwd);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Decrypts shares with the given password.
+ */
+ public byte[] decryptShare(CryptoToken token,
+ String encoding, String pwd)
+ throws EBaseException {
+ try {
+ CMS.debug("StorageKeyUnit.decryptShare");
+ byte share[] = CMS.AtoB(encoding);
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+ SymmetricKey sk = StorageKeyUnit.buildSymmetricKey(
+ token, pwd);
+
+ cipher.initDecrypt(sk, IV);
+ byte dec[] = cipher.doFinal(share);
+
+ if (dec == null || !verifyShare(dec)) {
+ // invalid passwod
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ return postVerify(dec);
+ } catch (OutOfMemoryError e) {
+ // XXX - this happens in cipher.doFinal when
+ // the given share is not valid (the password
+ // given from the agent is not correct).
+ // Actulla, cipher.doFinal should return
+ // something better than this!
+ //
+ // e.printStackTrace();
+ //
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (InvalidKeyException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (IllegalBlockSizeException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (BadPaddingException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ }
+ }
+
+ /**
+ * Reconstructs password from recovery agents.
+ */
+ private String constructPassword(Credential creds[])
+ throws EBaseException {
+ // sort the credential according to the order in
+ // configuration file
+ Hashtable<String, byte[]> v = new Hashtable<String, byte[]>();
+
+ for (int i = 0;; i++) {
+ String uid = null;
+
+ try {
+ uid = mStorageConfig.getString(PROP_UID + i);
+ if (uid == null)
+ break;
+ } catch (Exception e) {
+ break;
+ }
+ for (int j = 0; j < creds.length; j++) {
+ if (uid.equals(creds[j].getIdentifier())) {
+ byte pwd[] = decryptShareWithInternalStorage(
+ mStorageConfig.getString(
+ PROP_SHARE + i),
+ creds[j].getPassword());
+ if (pwd == null) {
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ v.put(Integer.toString(i), pwd);
+ break;
+ }
+ }
+ }
+
+ if (v.size() < 0) {
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ if (v.size() != creds.length) {
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ IJoinShares j = null;
+ try {
+ String className = mConfig.getString("joinshares_class",
+ "com.netscape.cms.shares.OldJoinShares");
+ j = (IJoinShares) Class.forName(className).newInstance();
+ } catch (Exception e) {
+ CMS.debug("JoinShares error " + e);
+ }
+ if (j == null) {
+ CMS.debug("JoinShares plugin is not found");
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ try {
+ j.initialize(v.size());
+ } catch (Exception e) {
+ CMS.debug("Failed to initialize JoinShares");
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ Enumeration<String> e = v.keys();
+
+ while (e.hasMoreElements()) {
+ String next = e.nextElement();
+
+ j.addShare(Integer.parseInt(next) + 1,
+ (byte[]) v.get(next));
+ }
+ try {
+ byte secret[] = j.recoverSecret();
+ String pwd = new String(secret);
+
+ return pwd;
+ } catch (Exception ee) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_RECONSTRUCT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ ee.toString()));
+ }
+ }
+
+ public static boolean arraysEqual(byte[] bytes, byte[] ints) {
+ if (bytes == null || ints == null) {
+ return false;
+ }
+
+ if (bytes.length != ints.length) {
+ return false;
+ }
+
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] != ints[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java b/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java
new file mode 100644
index 000000000..7575ea9f4
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java
@@ -0,0 +1,627 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.security.SecureRandom;
+import java.util.Hashtable;
+
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerValue;
+
+import org.mozilla.jss.crypto.Cipher;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.pkcs11.PK11SymKey;
+import org.mozilla.jss.util.Base64OutputStream;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.SessionContext;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.certsrv.kra.EKRAException;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.certsrv.security.ITransportKeyUnit;
+import com.netscape.cmscore.dbs.KeyRecord;
+import com.netscape.cmsutil.util.Cert;
+
+/**
+ * A class represents recovery request processor.
+ *
+ * @author Christina Fu (cfu)
+ * @version $Revision$, $Date$
+ */
+public class TokenKeyRecoveryService implements IService {
+
+ public static final String ATTR_NICKNAME = "nickname";
+ public static final String ATTR_OWNER_NAME = "ownerName";
+ public static final String ATTR_PUBLIC_KEY_DATA = "publicKeyData";
+ public static final String ATTR_PRIVATE_KEY_DATA = "privateKeyData";
+ public static final String ATTR_TRANSPORT_CERT = "transportCert";
+ public static final String ATTR_TRANSPORT_PWD = "transportPwd";
+ public static final String ATTR_SIGNING_CERT = "signingCert";
+ public static final String ATTR_PKCS12 = "pkcs12";
+ public static final String ATTR_ENCRYPTION_CERTS =
+ "encryptionCerts";
+ public static final String ATTR_AGENT_CREDENTIALS =
+ "agentCredentials";
+ // same as encryption certs
+ public static final String ATTR_USER_CERT = "cert";
+ public static final String ATTR_DELIVERY = "delivery";
+
+ private IKeyRecoveryAuthority mKRA = null;
+ private IKeyRepository mStorage = null;
+ private IStorageKeyUnit mStorageUnit = null;
+ private ITransportKeyUnit mTransportUnit = null;
+
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_4";
+
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_4";
+ private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+
+ /**
+ * Constructs request processor.
+ */
+ public TokenKeyRecoveryService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mStorage = mKRA.getKeyRepository();
+ mStorageUnit = mKRA.getStorageKeyUnit();
+ mTransportUnit = kra.getTransportKeyUnit();
+ }
+
+ /**
+ * Process the HTTP request.
+ *
+ * @param s The URL to decode
+ */
+ protected String URLdecode(String s) {
+ if (s == null)
+ return null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream(s.length());
+
+ for (int i = 0; i < s.length(); i++) {
+ int c = (int) s.charAt(i);
+
+ if (c == '+') {
+ out.write(' ');
+ } else if (c == '%') {
+ int c1 = Character.digit(s.charAt(++i), 16);
+ int c2 = Character.digit(s.charAt(++i), 16);
+
+ out.write((char) (c1 * 16 + c2));
+ } else {
+ out.write(c);
+ }
+ } // end for
+ return out.toString();
+ }
+
+ public static String normalizeCertStr(String s) {
+ String val = "";
+
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == '\\') {
+ i++;
+ continue;
+ } else if (s.charAt(i) == '\\') {
+ i++;
+ continue;
+ } else if (s.charAt(i) == '"') {
+ continue;
+ } else if (s.charAt(i) == ' ') {
+ continue;
+ }
+ val += s.charAt(i);
+ }
+ return val;
+ }
+
+ private static String base64Encode(byte[] bytes) throws IOException {
+ // All this streaming is lame, but Base64OutputStream needs a
+ // PrintStream
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Base64OutputStream b64 = new Base64OutputStream(new
+ PrintStream(new
+ FilterOutputStream(output)
+ )
+ );
+
+ b64.write(bytes);
+ b64.flush();
+
+ // This is internationally safe because Base64 chars are
+ // contained within 8859_1
+ return output.toString("8859_1");
+ }
+
+ // this encrypts bytes with a symmetric key
+ public byte[] encryptIt(byte[] toBeEncrypted, SymmetricKey symKey, CryptoToken token,
+ IVParameterSpec IV) {
+ try {
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+
+ cipher.initEncrypt(symKey, IV);
+ byte pri[] = cipher.doFinal(toBeEncrypted);
+ return pri;
+ } catch (Exception e) {
+ CMS.debug("initEncrypt() threw exception: " + e.toString());
+ return null;
+ }
+
+ }
+
+ /**
+ * Processes a recovery request. The method reads
+ * the key record from the database, and tries to recover the
+ * key with the storage key unit. Once recovered, it wraps it
+ * with desKey
+ * In the params
+ * - cert is used for recovery record search
+ * - cuid may be used for additional validation check
+ * - userid may be used for additional validation check
+ * - wrappedDesKey is used for wrapping recovered private key
+ *
+ * @param request recovery request
+ * @return operation success or not
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest request) throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = null;
+ String auditRecoveryID = ILogger.UNIDENTIFIED;
+ String iv_s = "";
+
+ CMS.debug("KRA services token key recovery request");
+
+ byte[] wrapped_des_key;
+
+ byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ try {
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+ random.nextBytes(iv);
+ } catch (Exception e) {
+ CMS.debug("TokenKeyRecoveryService.serviceRequest: " + e.toString());
+ }
+
+ String id = request.getRequestId().toString();
+ if (id != null) {
+ auditRecoveryID = id.trim();
+ }
+ SessionContext sContext = SessionContext.getContext();
+ String agentId = "";
+ if (sContext != null) {
+ agentId =
+ (String) sContext.get(SessionContext.USER_ID);
+ }
+
+ Hashtable<String, Object> params = mKRA.getVolatileRequest(
+ request.getRequestId());
+
+ if (params == null) {
+ // possibly we are in recovery mode
+ CMS.debug("getVolatileRequest params null");
+ // return true;
+ }
+
+ wrapped_des_key = null;
+
+ PK11SymKey sk = null;
+
+ String rCUID = request.getExtDataInString(IRequest.NETKEY_ATTR_CUID);
+ String rUserid = request.getExtDataInString(IRequest.NETKEY_ATTR_USERID);
+ String rWrappedDesKeyString = request.getExtDataInString(IRequest.NETKEY_ATTR_DRMTRANS_DES_KEY);
+ auditSubjectID = rCUID + ":" + rUserid;
+
+ CMS.debug("TokenKeyRecoveryService: received DRM-trans-wrapped des key =" + rWrappedDesKeyString);
+ wrapped_des_key = com.netscape.cmsutil.util.Utils.SpecialDecode(rWrappedDesKeyString);
+ CMS.debug("TokenKeyRecoveryService: wrapped_des_key specialDecoded");
+
+ if ((wrapped_des_key != null) &&
+ (wrapped_des_key.length > 0)) {
+
+ // unwrap the des key
+ sk = (PK11SymKey) mTransportUnit.unwrap_encrypt_sym(wrapped_des_key);
+
+ if (sk == null) {
+ CMS.debug("TokenKeyRecoveryService: no des key");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ } else {
+ CMS.debug("TokenKeyRecoveryService: received des key");
+ }
+ } else {
+ CMS.debug("TokenKeyRecoveryService: not receive des key");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+
+ // retrieve based on Certificate
+ String cert_s = request.getExtDataInString(ATTR_USER_CERT);
+ if (cert_s == null) {
+ CMS.debug("TokenKeyRecoveryService: not receive cert");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(3));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+
+ String cert = normalizeCertStr(cert_s);
+ java.security.cert.X509Certificate x509cert = null;
+ try {
+ x509cert = (java.security.cert.X509Certificate) Cert.mapCert(cert);
+ if (x509cert == null) {
+ CMS.debug("cert mapping failed");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(5));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+ } catch (IOException e) {
+ CMS.debug("TokenKeyRecoveryService: mapCert failed");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(6));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+
+ try {
+ /*
+ CryptoToken internalToken =
+ CryptoManager.getInstance().getInternalKeyStorageToken();
+ */
+ CryptoToken token = mStorageUnit.getToken();
+ CMS.debug("TokenKeyRecoveryService: got token slot:" + token.getName());
+ IVParameterSpec algParam = new IVParameterSpec(iv);
+
+ Cipher cipher = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
+
+ KeyRecord keyRecord = null;
+ CMS.debug("KRA reading key record");
+ try {
+ keyRecord = (KeyRecord) mStorage.readKeyRecord(cert);
+ if (keyRecord != null)
+ CMS.debug("read key record");
+ else {
+ CMS.debug("key record not found");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(8));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+ } catch (Exception e) {
+ com.netscape.cmscore.util.Debug.printStackTrace(e);
+ request.setExtData(IRequest.RESULT, Integer.valueOf(9));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+
+ // see if the owner name matches (cuid:userid) -XXX need make this optional
+ String owner = keyRecord.getOwnerName();
+ CMS.debug("TokenKeyRecoveryService: owner name on record =" + owner);
+ CMS.debug("TokenKeyRecoveryService: owner name from TPS =" + rCUID + ":" + rUserid);
+ if (owner != null) {
+ if (owner.equals(rCUID + ":" + rUserid)) {
+ CMS.debug("TokenKeyRecoveryService: owner name matches");
+ } else {
+ CMS.debug("TokenKeyRecoveryService: owner name mismatches");
+ }
+ }
+
+ // see if the certificate matches the key
+ byte pubData[] = keyRecord.getPublicKeyData();
+ byte inputPubData[] = x509cert.getPublicKey().getEncoded();
+
+ if (inputPubData.length != pubData.length) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PUBLIC_KEY_LEN"));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_PUBLIC_KEY_NOT_MATCHED"));
+ }
+
+ for (int i = 0; i < pubData.length; i++) {
+ if (pubData[i] != inputPubData[i]) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PUBLIC_KEY_LEN"));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_PUBLIC_KEY_NOT_MATCHED"));
+ }
+ }
+
+ // Unwrap the archived private key
+ byte privateKeyData[] = null;
+ privateKeyData = recoverKey(params, keyRecord);
+ if (privateKeyData == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("TokenKeyRecoveryService: failed getting private key");
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+ CMS.debug("TokenKeyRecoveryService: got private key...about to verify");
+
+ iv_s = /*base64Encode(iv);*/com.netscape.cmsutil.util.Utils.SpecialEncode(iv);
+ request.setExtData("iv_s", iv_s);
+
+ CMS.debug("request.setExtData: iv_s: " + iv_s);
+
+ /* LunaSA returns data with padding which we need to remove */
+ ByteArrayInputStream dis = new ByteArrayInputStream(privateKeyData);
+ DerValue dv = new DerValue(dis);
+ byte p[] = dv.toByteArray();
+ int l = p.length;
+ CMS.debug("length different data length=" + l +
+ " real length=" + privateKeyData.length);
+ if (l != privateKeyData.length) {
+ privateKeyData = p;
+ }
+
+ if (verifyKeyPair(pubData, privateKeyData) == false) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_PUBLIC_NOT_FOUND"));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PUBLIC_KEY"));
+ } else {
+ CMS.debug("TokenKeyRecoveryService: private key verified with public key");
+ }
+
+ //encrypt and put in private key
+ cipher.initEncrypt(sk, algParam);
+ byte wrapped[] = cipher.doFinal(privateKeyData);
+
+ String wrappedPrivKeyString =
+ com.netscape.cmsutil.util.Utils.SpecialEncode(wrapped);
+ if (wrappedPrivKeyString == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("TokenKeyRecoveryService: failed generating wrapped private key");
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ } else {
+ CMS.debug("TokenKeyRecoveryService: got private key data wrapped");
+ request.setExtData("wrappedUserPrivate",
+ wrappedPrivKeyString);
+ request.setExtData(IRequest.RESULT, Integer.valueOf(1));
+ CMS.debug("TokenKeyRecoveryService: key for " + rCUID + ":" + rUserid + " recovered");
+ }
+
+ //convert and put in the public key
+ String b64PKey = base64Encode(pubData);
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ b64PKey);
+
+ audit(auditMessage);
+
+ if (b64PKey == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("TokenKeyRecoveryService: failed getting publickey encoded");
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ } else {
+ CMS.debug("TokenKeyRecoveryService: got publicKeyData b64 = " +
+ b64PKey);
+ }
+ request.setExtData("public_key", b64PKey);
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+
+ return true;
+
+ } catch (Exception e) {
+ CMS.debug("TokenKeyRecoveryService: " + e.toString());
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ }
+
+ return true;
+ }
+
+ public boolean verifyKeyPair(byte publicKeyData[], byte privateKeyData[]) {
+ try {
+ DerValue publicKeyVal = new DerValue(publicKeyData);
+ DerInputStream publicKeyIn = publicKeyVal.data;
+ publicKeyIn.getSequence(0);
+ DerValue publicKeyDer = new DerValue(publicKeyIn.getBitString());
+ DerInputStream publicKeyDerIn = publicKeyDer.data;
+ BigInt publicKeyModulus = publicKeyDerIn.getInteger();
+ BigInt publicKeyExponent = publicKeyDerIn.getInteger();
+
+ DerValue privateKeyVal = new DerValue(privateKeyData);
+ if (privateKeyVal.tag != DerValue.tag_Sequence)
+ return false;
+ DerInputStream privateKeyIn = privateKeyVal.data;
+ privateKeyIn.getInteger();
+ privateKeyIn.getSequence(0);
+ DerValue privateKeyDer = new DerValue(privateKeyIn.getOctetString());
+ DerInputStream privateKeyDerIn = privateKeyDer.data;
+
+ @SuppressWarnings("unused")
+ BigInt privateKeyVersion = privateKeyDerIn.getInteger(); // consume stream
+ BigInt privateKeyModulus = privateKeyDerIn.getInteger();
+ BigInt privateKeyExponent = privateKeyDerIn.getInteger();
+
+ if (!publicKeyModulus.equals(privateKeyModulus)) {
+ CMS.debug("verifyKeyPair modulus mismatch publicKeyModulus="
+ + publicKeyModulus + " privateKeyModulus=" + privateKeyModulus);
+ return false;
+ }
+
+ if (!publicKeyExponent.equals(privateKeyExponent)) {
+ CMS.debug("verifyKeyPair exponent mismatch publicKeyExponent="
+ + publicKeyExponent + " privateKeyExponent=" + privateKeyExponent);
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ CMS.debug("verifyKeyPair error " + e);
+ return false;
+ }
+ }
+
+ /**
+ * Recovers key.
+ */
+ public synchronized byte[] recoverKey(Hashtable<String, Object> request, KeyRecord keyRecord)
+ throws EBaseException {
+ /*
+ Credential creds[] = (Credential[])
+ request.get(ATTR_AGENT_CREDENTIALS);
+
+ mStorageUnit.login(creds);
+ */
+ CMS.debug("KRA decrypts internal private");
+ byte privateKeyData[] =
+ mStorageUnit.decryptInternalPrivate(
+ keyRecord.getPrivateKeyData());
+ /*
+ mStorageUnit.logout();
+ */
+ if (privateKeyData == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PRIVATE_KEY_NOT_FOUND"));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", "no private key"));
+ }
+ return privateKeyData;
+ }
+
+ /**
+ * Signed Audit Log
+ * y
+ * This method is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ private void audit(String msg) {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if (mSignedAuditLogger == null) {
+ return;
+ }
+
+ mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg);
+ }
+
+}
diff --git a/base/kra/src/com/netscape/kra/TransportKeyUnit.java b/base/kra/src/com/netscape/kra/TransportKeyUnit.java
new file mode 100644
index 000000000..90ac2120f
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/TransportKeyUnit.java
@@ -0,0 +1,195 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.security.PublicKey;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.crypto.Signature;
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+import org.mozilla.jss.crypto.TokenException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.ISubsystem;
+import com.netscape.certsrv.security.ITransportKeyUnit;
+import com.netscape.cmsutil.util.Cert;
+
+/**
+ * A class represents the transport key pair. This key pair
+ * is used to protected EE's private key in transit.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class TransportKeyUnit extends EncryptionUnit implements
+ ISubsystem, ITransportKeyUnit {
+
+ public static final String PROP_NICKNAME = "nickName";
+ public static final String PROP_SIGNING_ALGORITHM = "signingAlgorithm";
+
+ // private RSAPublicKey mPublicKey = null;
+ // private RSAPrivateKey mPrivateKey = null;
+ private IConfigStore mConfig = null;
+ private org.mozilla.jss.crypto.X509Certificate mCert = null;
+ private CryptoManager mManager = null;
+
+ /**
+ * Constructs this token.
+ */
+ public TransportKeyUnit() {
+ super();
+ }
+
+ /**
+ * Retrieves subsystem identifier.
+ */
+ public String getId() {
+ return "transportKeyUnit";
+ }
+
+ /**
+ * Sets subsystem identifier.
+ */
+ public void setId(String id) throws EBaseException {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_OPERATION"));
+ }
+
+ /**
+ * Initializes this subsystem.
+ */
+ public void init(ISubsystem owner, IConfigStore config)
+ throws EBaseException {
+ mConfig = config;
+ try {
+ mManager = CryptoManager.getInstance();
+ mCert = mManager.findCertByNickname(getNickName());
+ String algo = config.getString("signingAlgorithm", "SHA256withRSA");
+
+ // #613795 - initialize this; otherwise JSS is not happy
+ CryptoToken token = getToken();
+ SignatureAlgorithm sigalg = Cert.mapAlgorithmToJss(algo);
+ Signature signer = token.getSignatureContext(sigalg);
+ signer.initSign(getPrivateKey());
+
+ } catch (org.mozilla.jss.CryptoManager.NotInitializedException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+ } catch (ObjectNotFoundException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+ } catch (Exception e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+ }
+ }
+
+ public CryptoToken getInternalToken() {
+ try {
+ return CryptoManager.getInstance().getInternalKeyStorageToken();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public CryptoToken getToken() {
+ // 390148: returning the token that owns the private
+ // key.
+ return getPrivateKey().getOwningToken();
+ }
+
+ /**
+ * Starts up this subsystem.
+ */
+ public void startup() throws EBaseException {
+ }
+
+ /**
+ * Shutdowns this subsystem.
+ */
+ public void shutdown() {
+ }
+
+ /**
+ * Returns the configuration store of this token.
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public String getNickName() throws EBaseException {
+ return mConfig.getString(PROP_NICKNAME);
+ }
+
+ public void setNickName(String str) throws EBaseException {
+ mConfig.putString(PROP_NICKNAME, str);
+ }
+
+ public String getSigningAlgorithm() throws EBaseException {
+ return mConfig.getString(PROP_SIGNING_ALGORITHM);
+ }
+
+ public void setSigningAlgorithm(String str) throws EBaseException {
+ mConfig.putString(PROP_SIGNING_ALGORITHM, str);
+ }
+
+ /**
+ * Logins to this token.
+ */
+ public void login(String pin) throws EBaseException {
+ }
+
+ /**
+ * Logout from this token.
+ */
+ public void logout() {
+ }
+
+ /**
+ * Retrieves public key.
+ */
+ public org.mozilla.jss.crypto.X509Certificate getCertificate() {
+ return mCert;
+ }
+
+ public PublicKey getPublicKey() {
+ return mCert.getPublicKey();
+ }
+
+ public PrivateKey getPrivateKey() {
+ try {
+ return mManager.findPrivKeyByCert(mCert);
+ } catch (TokenException e) {
+ return null;
+ } catch (ObjectNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Verifies the integrity of the given key pair.
+ */
+ public void verify(byte publicKey[], PrivateKey privateKey)
+ throws EBaseException {
+ // XXX
+ }
+}