diff --git a/.gitignore b/.gitignore index 419bd94..5ac3a73 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/jss-4.4.4.tar.gz +SOURCES/jss-4.4.6.tar.gz diff --git a/.jss.metadata b/.jss.metadata index 1b0aaaf..759bb43 100644 --- a/.jss.metadata +++ b/.jss.metadata @@ -1 +1 @@ -e45e8b624ee4bbbb86204eaeebd1ea450513bfc7 SOURCES/jss-4.4.4.tar.gz +19fe5139c0d258849c3905b4991145dba94f99de SOURCES/jss-4.4.6.tar.gz diff --git a/SOURCES/jss-add-TLS-SHA384-ciphers.patch b/SOURCES/jss-add-TLS-SHA384-ciphers.patch deleted file mode 100644 index 26145c4..0000000 --- a/SOURCES/jss-add-TLS-SHA384-ciphers.patch +++ /dev/null @@ -1,167 +0,0 @@ -From 82f4b9a032f942fdc005e12a408c8e87c9ea0f36 Mon Sep 17 00:00:00 2001 -From: Christina Fu -Date: Thu, 28 Jun 2018 17:42:36 -0700 -Subject: [PATCH] Ticket #4 Add support for TLS_*_SHA384 ciphers - -This patch adds support for TLS_*_SHA384 ciphers. - -Fixes https://pagure.io/jss/issue/4 ---- - org/mozilla/jss/ssl/SSLCipher.java | 7 +++++ - org/mozilla/jss/ssl/SSLSocket.java | 7 +++++ - org/mozilla/jss/tests/Constants.java | 11 ++++++-- - org/mozilla/jss/tests/SSLClientAuth.java | 45 ++++++++++++++++++++++++++++++++ - 4 files changed, 68 insertions(+), 2 deletions(-) - -diff --git a/org/mozilla/jss/ssl/SSLCipher.java b/org/mozilla/jss/ssl/SSLCipher.java -index 30acdd7..278126b 100644 ---- a/jss/org/mozilla/jss/ssl/SSLCipher.java -+++ b/jss/org/mozilla/jss/ssl/SSLCipher.java -@@ -258,8 +258,11 @@ public enum SSLCipher { - TLS_RSA_WITH_SEED_CBC_SHA (0x0096), - - TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009C), -+ TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009D), - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009E), -+ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009F), - TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 (0x00A2), -+ TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 (0x00A3), - - TLS_ECDH_ECDSA_WITH_NULL_SHA (0xc001, true), - TLS_ECDH_ECDSA_WITH_RC4_128_SHA (0xc002, true), -@@ -292,11 +295,15 @@ public enum SSLCipher { - TLS_ECDH_anon_WITH_AES_256_CBC_SHA (0xc019, true), - - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023, true), -+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024, true), - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027, true), -+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028, true), - - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02B, true), -+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02C, true), - TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02D, true), - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02F, true), -+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030, true), - TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 (0xc031, true); - - private int id; -diff --git a/org/mozilla/jss/ssl/SSLSocket.java b/org/mozilla/jss/ssl/SSLSocket.java -index 0dd39fd..e104d3c 100644 ---- a/jss/org/mozilla/jss/ssl/SSLSocket.java -+++ b/jss/org/mozilla/jss/ssl/SSLSocket.java -@@ -268,8 +268,11 @@ public class SSLSocket extends java.net.Socket { - public final static int TLS_RSA_WITH_SEED_CBC_SHA = 0x0096; - - public final static int TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C; -+ public final static int TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D; - public final static int TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E; -+ public final static int TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F; - public final static int TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2; -+ public final static int TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3; - - public final static int TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xc001; - public final static int TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xc002; -@@ -302,11 +305,15 @@ public class SSLSocket extends java.net.Socket { - public final static int TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xc019; - - public final static int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xc023; -+ public final static int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xc024; - public final static int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xc027; -+ public final static int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xc028; - - public final static int TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xc02B; -+ public final static int TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xc02C; - public final static int TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xc02D; - public final static int TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xc02F; -+ public final static int TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xc030; - public final static int TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xc031; - - /* -diff --git a/org/mozilla/jss/tests/Constants.java b/org/mozilla/jss/tests/Constants.java -index e613034..d79ad72 100755 ---- a/jss/org/mozilla/jss/tests/Constants.java -+++ b/jss/org/mozilla/jss/tests/Constants.java -@@ -142,8 +142,15 @@ public interface Constants { - /*77*/ new cipher(SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"), - /*78*/ new cipher(SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), - /*79*/ new cipher(SSLSocket.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"), --/*78*/ new cipher(SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"), --/*80*/ new cipher(SSLSocket.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256") -+/*80*/ new cipher(SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"), -+/*81*/ new cipher(SSLSocket.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"), -+/*82*/ new cipher(SSLSocket.TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_256_GCM_SHA384"), -+/*83*/ new cipher(SSLSocket.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"), -+/*84*/ new cipher(SSLSocket.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"), -+/*85*/ new cipher(SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"), -+/*86*/ new cipher(SSLSocket.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"), -+/*87*/ new cipher(SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"), -+/*88*/ new cipher(SSLSocket.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384") - }; - - /** Cipher supported by JSSE (JDK 1.5.x) */ -diff --git a/org/mozilla/jss/tests/SSLClientAuth.java b/org/mozilla/jss/tests/SSLClientAuth.java -index e1c6163..b656b82 100644 ---- a/jss/org/mozilla/jss/tests/SSLClientAuth.java -+++ b/jss/org/mozilla/jss/tests/SSLClientAuth.java -@@ -148,6 +148,8 @@ public class SSLClientAuth implements Runnable { - - } - configureDefaultSSLoptions(); -+ -+ testSpecificCiphers(); - - useNickname = false; - testConnection(); -@@ -265,6 +267,49 @@ public class SSLClientAuth implements Runnable { - System.exit(1); - } - } -+ -+ // test one or more specific ciphers -+ // -- normally for newly added ciphers -+ private void testSpecificCiphers() { -+ try { -+ //Disable SSL2 and SSL3 ciphers -+ SSLSocket.enableSSL2Default(false); -+ SSLSocket.enableSSL3Default(false); -+ /* TLS is enabled by default */ -+ -+ /* Enable Session tickets by default */ -+ SSLSocket.enableSessionTicketsDefault(true); -+ -+ /* -+ * when testing specific ciphers: -+ * 1. flip this to true -+ * 2. change the ciphers comparison (the code below was from -+ * the latest test -+ */ -+ if (false) { -+ System.out.println("testing new TLS_*SHA384 ciphers"); -+ System.out.println("Enable ony two new ciphers."); -+ int ciphers[] = -+ org.mozilla.jss.ssl.SSLSocket.getImplementedCipherSuites(); -+ for (int i = 0; i < ciphers.length; ++i) { -+ if (ciphers[i] == 157 || ciphers[i] == 159) { -+ System.out.println("enabling cipher: " + ciphers[i]); -+ /* enable a couple SHA384 ciphers */ -+ SSLSocket.setCipherPreferenceDefault(ciphers[i], true); -+ } else { -+ System.out.println("disabling cipher: " + ciphers[i]); -+ /* disable the non SHA384 ciphers */ -+ SSLSocket.setCipherPreferenceDefault(ciphers[i], false); -+ } -+ } -+ } -+ -+ } catch (SocketException ex) { -+ System.out.println("Error configuring ciphers."); -+ ex.printStackTrace(); -+ System.exit(1); -+ } -+ } - - private void testConnection() throws Exception { - serverReady = false; --- -2.14.4 - diff --git a/SOURCES/jss-add-build-sh.patch b/SOURCES/jss-add-build-sh.patch deleted file mode 100644 index 91feff3..0000000 --- a/SOURCES/jss-add-build-sh.patch +++ /dev/null @@ -1,386 +0,0 @@ -From f2357a2b5721cddb0a8924be76d0cdc9412d59dc Mon Sep 17 00:00:00 2001 -From: "Endi S. Dewata" -Date: Thu, 21 Jun 2018 21:41:21 -0600 -Subject: [PATCH] Added build.sh - -A new build script has been added to simplify the build process. ---- - build.sh | 366 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 366 insertions(+) - create mode 100755 build.sh - -diff --git a/build.sh b/build.sh -new file mode 100755 -index 00000000..ebd46e97 ---- /dev/null -+++ b/build.sh -@@ -0,0 +1,366 @@ -+#!/bin/bash -e -+ -+# BEGIN COPYRIGHT BLOCK -+# (C) 2018 Red Hat, Inc. -+# All rights reserved. -+# END COPYRIGHT BLOCK -+ -+NAME=jss -+ -+SCRIPT_PATH=`readlink -f "$0"` -+SCRIPT_NAME=`basename "$SCRIPT_PATH"` -+ -+SRC_DIR=`dirname "$SCRIPT_PATH"` -+WORK_DIR="$HOME/build/$NAME" -+ -+SOURCE_TAG= -+ -+WITH_TIMESTAMP= -+WITH_COMMIT_ID= -+DIST= -+ -+VERBOSE= -+DEBUG= -+ -+usage() { -+ echo "Usage: $SCRIPT_NAME [OPTIONS] " -+ echo -+ echo "Options:" -+ echo " --work-dir= Working directory (default: $WORK_DIR)." -+ echo " --source-tag= Generate RPM sources from a source tag." -+ echo " --with-timestamp Append timestamp to release number." -+ echo " --with-commit-id Append commit ID to release number." -+ echo " --dist= Distribution name (e.g. fc28)." -+ echo " -v,--verbose Run in verbose mode." -+ echo " --debug Run in debug mode." -+ echo " --help Show help message." -+ echo -+ echo "Target:" -+ echo " src Generate RPM sources." -+ echo " spec Generate RPM spec." -+ echo " srpm Build SRPM package." -+ echo " rpm Build RPM packages." -+} -+ -+generate_rpm_sources() { -+ -+ TARBALL="$NAME-$VERSION.tar.gz" -+ -+ if [ "$SOURCE_TAG" != "" ] ; then -+ -+ if [ "$VERBOSE" = true ] ; then -+ echo "Generating $TARBALL from $SOURCE_TAG tag" -+ fi -+ -+ git -C "$SRC_DIR" \ -+ archive \ -+ --format=tar.gz \ -+ --prefix $NAME-$VERSION/$NAME/ \ -+ -o "$WORK_DIR/SOURCES/$TARBALL" \ -+ $SOURCE_TAG -+ -+ if [ "$SOURCE_TAG" != "HEAD" ] ; then -+ -+ TAG_ID=`git -C "$SRC_DIR" rev-parse $SOURCE_TAG` -+ HEAD_ID=`git -C "$SRC_DIR" rev-parse HEAD` -+ -+ if [ "$TAG_ID" != "$HEAD_ID" ] ; then -+ generate_patch -+ fi -+ fi -+ -+ return -+ fi -+ -+ if [ "$VERBOSE" = true ] ; then -+ echo "Generating $TARBALL" -+ fi -+ -+ tar czf "$WORK_DIR/SOURCES/$TARBALL" \ -+ --transform "s,^./,$NAME-$VERSION/$NAME/," \ -+ --exclude .git \ -+ --exclude bin \ -+ -C "$SRC_DIR" \ -+ . -+} -+ -+generate_patch() { -+ -+ PATCH="$NAME-$VERSION-$RELEASE.patch" -+ -+ if [ "$VERBOSE" = true ] ; then -+ echo "Generating $PATCH for all changes since $SOURCE_TAG tag" -+ fi -+ -+ git -C "$SRC_DIR" \ -+ format-patch \ -+ --stdout \ -+ $SOURCE_TAG \ -+ > "$WORK_DIR/SOURCES/$PATCH" -+} -+ -+generate_rpm_spec() { -+ -+ RPM_SPEC="$NAME.spec" -+ -+ if [ "$VERBOSE" = true ] ; then -+ echo "Generating $RPM_SPEC" -+ fi -+ -+ # hard-code timestamp -+ commands="s/%{?_timestamp}/${_TIMESTAMP}/g" -+ -+ # hard-code commit ID -+ commands="${commands}; s/%{?_commit_id}/${_COMMIT_ID}/g" -+ -+ # hard-code patch -+ if [ "$PATCH" != "" ] ; then -+ commands="${commands}; s/# Patch: jss-VERSION-RELEASE.patch/Patch: $PATCH/g" -+ fi -+ -+ sed "$commands" "$SPEC_TEMPLATE" > "$WORK_DIR/SPECS/$RPM_SPEC" -+ -+ # rpmlint "$WORK_DIR/SPECS/$RPM_SPEC" -+} -+ -+while getopts v-: arg ; do -+ case $arg in -+ v) -+ VERBOSE=true -+ ;; -+ -) -+ LONG_OPTARG="${OPTARG#*=}" -+ -+ case $OPTARG in -+ work-dir=?*) -+ WORK_DIR=`readlink -f "$LONG_OPTARG"` -+ ;; -+ source-tag=?*) -+ SOURCE_TAG="$LONG_OPTARG" -+ ;; -+ with-timestamp) -+ WITH_TIMESTAMP=true -+ ;; -+ with-commit-id) -+ WITH_COMMIT_ID=true -+ ;; -+ dist=?*) -+ DIST="$LONG_OPTARG" -+ ;; -+ verbose) -+ VERBOSE=true -+ ;; -+ debug) -+ VERBOSE=true -+ DEBUG=true -+ ;; -+ help) -+ usage -+ exit -+ ;; -+ '') -+ break # "--" terminates argument processing -+ ;; -+ work-dir* | source-tag* | dist*) -+ echo "ERROR: Missing argument for --$OPTARG option" >&2 -+ exit 1 -+ ;; -+ *) -+ echo "ERROR: Illegal option --$OPTARG" >&2 -+ exit 1 -+ ;; -+ esac -+ ;; -+ \?) -+ exit 1 # getopts already reported the illegal option -+ ;; -+ esac -+done -+ -+# remove parsed options and args from $@ list -+shift $((OPTIND-1)) -+ -+if [ "$#" -lt 1 ] ; then -+ echo "ERROR: Missing build target" >&2 -+ usage -+ exit 1 -+fi -+ -+BUILD_TARGET=$1 -+ -+if [ "$DEBUG" = true ] ; then -+ echo "WORK_DIR: $WORK_DIR" -+ echo "BUILD_TARGET: $BUILD_TARGET" -+fi -+ -+if [ "$BUILD_TARGET" != "src" ] && -+ [ "$BUILD_TARGET" != "spec" ] && -+ [ "$BUILD_TARGET" != "srpm" ] && -+ [ "$BUILD_TARGET" != "rpm" ] ; then -+ echo "ERROR: Invalid build target: $BUILD_TARGET" >&2 -+ exit 1 -+fi -+ -+SPEC_TEMPLATE="$SRC_DIR/$NAME.spec.in" -+VERSION="`rpmspec -P "$SPEC_TEMPLATE" | grep "^Version:" | awk '{print $2;}'`" -+ -+if [ "$DEBUG" = true ] ; then -+ echo "VERSION: $VERSION" -+fi -+ -+RELEASE="`rpmspec -P "$SPEC_TEMPLATE" --undefine dist | grep "^Release:" | awk '{print $2;}'`" -+ -+if [ "$DEBUG" = true ] ; then -+ echo "RELEASE: $RELEASE" -+fi -+ -+if [ "$WITH_TIMESTAMP" = true ] ; then -+ TIMESTAMP="`date +"%Y%m%d%H%M%S"`" -+ _TIMESTAMP=".$TIMESTAMP" -+fi -+ -+if [ "$DEBUG" = true ] ; then -+ echo "TIMESTAMP: $TIMESTAMP" -+fi -+ -+if [ "$WITH_COMMIT_ID" = true ]; then -+ COMMIT_ID="`git -C "$SRC_DIR" rev-parse --short=8 HEAD`" -+ _COMMIT_ID=".$COMMIT_ID" -+fi -+ -+if [ "$DEBUG" = true ] ; then -+ echo "COMMIT_ID: $COMMIT_ID" -+fi -+ -+echo "Building $NAME-$VERSION-$RELEASE${_TIMESTAMP}${_COMMIT_ID}" -+ -+################################################################################ -+# Initialize working directory -+################################################################################ -+ -+if [ "$VERBOSE" = true ] ; then -+ echo "Initializing $WORK_DIR" -+fi -+ -+mkdir -p $WORK_DIR -+cd $WORK_DIR -+ -+rm -rf BUILD -+rm -rf RPMS -+rm -rf SOURCES -+rm -rf SPECS -+rm -rf SRPMS -+ -+mkdir BUILD -+mkdir RPMS -+mkdir SOURCES -+mkdir SPECS -+mkdir SRPMS -+ -+################################################################################ -+# Generate RPM sources -+################################################################################ -+ -+generate_rpm_sources -+ -+echo "RPM sources:" -+find "$WORK_DIR/SOURCES" -type f -printf " %p\n" -+ -+if [ "$BUILD_TARGET" = "src" ] ; then -+ exit -+fi -+ -+################################################################################ -+# Generate RPM spec -+################################################################################ -+ -+generate_rpm_spec -+ -+echo "RPM spec:" -+find "$WORK_DIR/SPECS" -type f -printf " %p\n" -+ -+if [ "$BUILD_TARGET" = "spec" ] ; then -+ exit -+fi -+ -+################################################################################ -+# Build source package -+################################################################################ -+ -+OPTIONS=() -+ -+OPTIONS+=(--quiet) -+OPTIONS+=(--define "_topdir ${WORK_DIR}") -+ -+if [ "$WITH_TIMESTAMP" = true ] ; then -+ OPTIONS+=(--define "_timestamp ${_TIMESTAMP}") -+fi -+ -+if [ "$WITH_COMMIT_ID" = true ] ; then -+ OPTIONS+=(--define "_commit_id ${_COMMIT_ID}") -+fi -+ -+if [ "$DIST" != "" ] ; then -+ OPTIONS+=(--define "dist .$DIST") -+fi -+ -+if [ "$DEBUG" = true ] ; then -+ echo "rpmbuild -bs ${OPTIONS[@]} $WORK_DIR/SPECS/$RPM_SPEC" -+fi -+ -+# build SRPM with user-provided options -+rpmbuild -bs "${OPTIONS[@]}" "$WORK_DIR/SPECS/$RPM_SPEC" -+ -+rc=$? -+ -+if [ $rc != 0 ]; then -+ echo "ERROR: Unable to build SRPM package" -+ exit 1 -+fi -+ -+SRPM=`find "$WORK_DIR/SRPMS" -type f` -+ -+echo "SRPM package:" -+echo " $SRPM" -+ -+if [ "$BUILD_TARGET" = "srpm" ] ; then -+ exit -+fi -+ -+################################################################################ -+# Build binary packages -+################################################################################ -+ -+OPTIONS=() -+ -+if [ "$VERBOSE" = true ] ; then -+ OPTIONS+=(--define "_verbose 1") -+fi -+ -+OPTIONS+=(--define "_topdir ${WORK_DIR}") -+ -+if [ "$DEBUG" = true ] ; then -+ echo "rpmbuild --rebuild ${OPTIONS[@]} $SRPM" -+fi -+ -+# rebuild RPM with hard-coded options in SRPM -+rpmbuild --rebuild "${OPTIONS[@]}" "$SRPM" -+ -+rc=$? -+ -+if [ $rc != 0 ]; then -+ echo "ERROR: Unable to build RPM packages" -+ exit 1 -+fi -+ -+# install SRPM to restore sources and spec file removed during rebuild -+rpm -i --define "_topdir $WORK_DIR" "$SRPM" -+ -+# flatten folder -+find "$WORK_DIR/RPMS" -mindepth 2 -type f -exec mv -i '{}' "$WORK_DIR/RPMS" ';' -+ -+# remove empty subfolders -+find "$WORK_DIR/RPMS" -mindepth 1 -type d -delete -+ -+echo "RPM packages:" -+find "$WORK_DIR/RPMS" -type f -printf " %p\n" --- -2.14.4 - diff --git a/SOURCES/jss-add-travis-yml.patch b/SOURCES/jss-add-travis-yml.patch deleted file mode 100644 index c4e3673..0000000 --- a/SOURCES/jss-add-travis-yml.patch +++ /dev/null @@ -1,37 +0,0 @@ -commit f6df4da0a66c9fdad6c1b794190431c265931a16 -Author: Endi S. Dewata -Date: Thu May 31 04:34:48 2018 +0200 - - Added .travis.yml - - A Travis CI configuration has been added to build JSS and run a - basic installation test. Additional tests will be added later. - -diff --git a/.travis.yml b/.travis.yml -new file mode 100644 -index 00000000..ae674cc5 ---- /dev/null -+++ b/.travis.yml -@@ -0,0 +1,22 @@ -+# BEGIN COPYRIGHT BLOCK -+# (C) 2018 Red Hat, Inc. -+# All rights reserved. -+# END COPYRIGHT BLOCK -+ -+services: -+ - docker -+ -+install: -+ - docker pull registry.fedoraproject.org/fedora:28 -+ - docker run -+ --name=container -+ --detach -+ -i -+ -v $(pwd):/root/jss -+ registry.fedoraproject.org/fedora:28 -+ - docker exec container dnf install -y dnf-plugins-core gcc make rpm-build -+ - docker exec container dnf builddep -y --spec /root/jss/jss.spec.in -+ - docker exec container /root/jss/build.sh --with-timestamp --with-commit-id rpm -+ -+script: -+ - docker exec container rpm -Uvh /root/build/jss/RPMS/* diff --git a/SOURCES/jss-add-x509-cert-and-crl-migration.patch b/SOURCES/jss-add-x509-cert-and-crl-migration.patch deleted file mode 100644 index 7399d2e..0000000 --- a/SOURCES/jss-add-x509-cert-and-crl-migration.patch +++ /dev/null @@ -1,47537 +0,0 @@ -From 06eacad918e745d632067deea398f14ce9da29ac Mon Sep 17 00:00:00 2001 -From: Jack Magne -Date: Fri, 15 Jun 2018 14:53:53 -0700 -Subject: [PATCH] Address Bugzilla: Bug 1560682 - (RFE) Migrate RHCS x509 cert - and crl functionality to JSS. - - This consists of a migration of low level X509 cert and crl related classes from dogtag into JSS. - This initial migration will allow users of jss to utilize these classes to create certs and crls. - - The initial goal is to simply provide the classes from dogtag to be used in JSS. - A later goal will be to refactor dogtag to use the classes moved to JSS, but that will be for - a future ticket. - - This migration will also address this issue: - - Bug 1577991 - org.mozilla.jss.netscape.security.util.ObjectIdentifier cannot parse OID arcs larger than Integer.MAX_VALUE. - - The file ObjectIdentifier.java has been modified to use BigInt instead of the int type, allowing for a greater range of values. - Fixed minor classpath issue. ---- - org/mozilla/jss/netscape/Makefile | 45 + - org/mozilla/jss/netscape/manifest.mn | 14 + - org/mozilla/jss/netscape/security/Makefile | 45 + - .../jss/netscape/security/acl/AclEntryImpl.java | 182 +++ - org/mozilla/jss/netscape/security/acl/AclImpl.java | 393 +++++ - .../netscape/security/acl/AllPermissionsImpl.java | 43 + - .../jss/netscape/security/acl/GroupImpl.java | 173 +++ - org/mozilla/jss/netscape/security/acl/Makefile | 45 + - .../jss/netscape/security/acl/OwnerImpl.java | 105 ++ - .../jss/netscape/security/acl/PermissionImpl.java | 73 + - .../jss/netscape/security/acl/PrincipalImpl.java | 77 + - .../jss/netscape/security/acl/WorldGroupImpl.java | 42 + - org/mozilla/jss/netscape/security/acl/manifest.mn | 8 + - .../security/extensions/AccessDescription.java | 77 + - .../extensions/AuthInfoAccessExtension.java | 275 ++++ - .../jss/netscape/security/extensions/CertInfo.java | 119 ++ - .../CertificateRenewalWindowExtension.java | 191 +++ - .../security/extensions/CertificateScopeEntry.java | 103 ++ - .../extensions/CertificateScopeOfUseExtension.java | 198 +++ - .../extensions/ExtendedKeyUsageExtension.java | 228 +++ - .../security/extensions/GenericASN1Extension.java | 461 ++++++ - .../extensions/InhibitAnyPolicyExtension.java | 183 +++ - .../netscape/security/extensions/KerberosName.java | 136 ++ - .../jss/netscape/security/extensions/Makefile | 45 + - .../security/extensions/NSCertTypeExtension.java | 382 +++++ - .../security/extensions/OCSPNoCheckExtension.java | 155 ++ - .../extensions/PresenceServerExtension.java | 341 +++++ - .../extensions/SubjectInfoAccessExtension.java | 255 ++++ - .../jss/netscape/security/extensions/manifest.mn | 8 + - org/mozilla/jss/netscape/security/manifest.mn | 12 + - .../jss/netscape/security/pkcs/ContentInfo.java | 155 ++ - .../netscape/security/pkcs/EncodingException.java | 33 + - org/mozilla/jss/netscape/security/pkcs/Makefile | 45 + - org/mozilla/jss/netscape/security/pkcs/PKCS10.java | 368 +++++ - .../netscape/security/pkcs/PKCS10Attribute.java | 235 +++ - .../netscape/security/pkcs/PKCS10Attributes.java | 177 +++ - org/mozilla/jss/netscape/security/pkcs/PKCS12.java | 209 +++ - .../jss/netscape/security/pkcs/PKCS12CertInfo.java | 65 + - .../jss/netscape/security/pkcs/PKCS12KeyInfo.java | 84 ++ - .../jss/netscape/security/pkcs/PKCS12Util.java | 667 ++++++++ - org/mozilla/jss/netscape/security/pkcs/PKCS7.java | 518 +++++++ - .../jss/netscape/security/pkcs/PKCS8Key.java | 430 ++++++ - .../jss/netscape/security/pkcs/PKCS9Attribute.java | 1119 ++++++++++++++ - .../netscape/security/pkcs/PKCS9Attributes.java | 313 ++++ - .../netscape/security/pkcs/ParsingException.java | 35 + - .../jss/netscape/security/pkcs/SignerInfo.java | 348 +++++ - org/mozilla/jss/netscape/security/pkcs/manifest.mn | 8 + - .../jss/netscape/security/provider/CMS.java | 52 + - .../jss/netscape/security/provider/DSA.java | 661 ++++++++ - .../netscape/security/provider/DSAKeyFactory.java | 232 +++ - .../security/provider/DSAKeyPairGenerator.java | 389 +++++ - .../security/provider/DSAParameterGenerator.java | 298 ++++ - .../netscape/security/provider/DSAParameters.java | 131 ++ - .../netscape/security/provider/DSAPrivateKey.java | 170 +++ - .../netscape/security/provider/DSAPublicKey.java | 159 ++ - .../jss/netscape/security/provider/MD5.java | 378 +++++ - .../jss/netscape/security/provider/Makefile | 45 + - .../netscape/security/provider/RSAPublicKey.java | 193 +++ - .../jss/netscape/security/provider/SHA.java | 349 +++++ - .../jss/netscape/security/provider/Sun.java | 135 ++ - .../security/provider/X509CertificateFactory.java | 61 + - .../jss/netscape/security/provider/manifest.mn | 8 + - .../netscape/security/util/ASN1CharStrConvMap.java | 168 +++ - .../security/util/ASN1CharsetProvider.java | 30 + - org/mozilla/jss/netscape/security/util/BigInt.java | 221 +++ - .../jss/netscape/security/util/BitArray.java | 257 ++++ - .../netscape/security/util/ByteArrayLexOrder.java | 60 + - .../netscape/security/util/ByteArrayTagOrder.java | 46 + - org/mozilla/jss/netscape/security/util/Cert.java | 201 +++ - .../netscape/security/util/CertPrettyPrint.java | 346 +++++ - .../jss/netscape/security/util/CrlPrettyPrint.java | 271 ++++ - .../jss/netscape/security/util/DerEncoder.java | 40 + - .../jss/netscape/security/util/DerInputBuffer.java | 186 +++ - .../jss/netscape/security/util/DerInputStream.java | 667 ++++++++ - .../netscape/security/util/DerOutputStream.java | 729 +++++++++ - .../jss/netscape/security/util/DerValue.java | 748 +++++++++ - .../jss/netscape/security/util/ExtPrettyPrint.java | 1586 ++++++++++++++++++++ - .../jss/netscape/security/util/IA5Charset.java | 24 + - .../netscape/security/util/IA5CharsetDecoder.java | 62 + - .../netscape/security/util/IA5CharsetEncoder.java | 69 + - org/mozilla/jss/netscape/security/util/Makefile | 45 + - .../netscape/security/util/ObjectIdentifier.java | 533 +++++++ - .../netscape/security/util/PrettyPrintFormat.java | 164 ++ - .../security/util/PrettyPrintResources.java | 301 ++++ - .../netscape/security/util/PrintableCharset.java | 46 + - .../security/util/PrintableCharsetDecoder.java | 69 + - .../security/util/PrintableCharsetEncoder.java | 71 + - .../netscape/security/util/PubKeyPrettyPrint.java | 123 ++ - .../netscape/security/util/UniversalCharset.java | 24 + - .../security/util/UniversalCharsetDecoder.java | 98 ++ - .../security/util/UniversalCharsetEncoder.java | 68 + - org/mozilla/jss/netscape/security/util/Utils.java | 356 +++++ - org/mozilla/jss/netscape/security/util/manifest.mn | 9 + - .../jss/netscape/security/x509/ACertAttrSet.java | 141 ++ - org/mozilla/jss/netscape/security/x509/AVA.java | 311 ++++ - .../netscape/security/x509/AVAValueConverter.java | 86 ++ - .../jss/netscape/security/x509/AlgIdDSA.java | 215 +++ - .../jss/netscape/security/x509/AlgorithmId.java | 805 ++++++++++ - .../jss/netscape/security/x509/Attribute.java | 327 ++++ - .../x509/AuthorityKeyIdentifierExtension.java | 342 +++++ - .../security/x509/BasicConstraintsExtension.java | 296 ++++ - org/mozilla/jss/netscape/security/x509/CPSuri.java | 66 + - .../security/x509/CRLDistributionPoint.java | 478 ++++++ - .../x509/CRLDistributionPointsExtension.java | 390 +++++ - .../jss/netscape/security/x509/CRLExtensions.java | 254 ++++ - .../netscape/security/x509/CRLNumberExtension.java | 227 +++ - .../netscape/security/x509/CRLReasonExtension.java | 243 +++ - .../jss/netscape/security/x509/CertAndKeyGen.java | 290 ++++ - .../jss/netscape/security/x509/CertAttrSet.java | 120 ++ - .../jss/netscape/security/x509/CertException.java | 165 ++ - .../jss/netscape/security/x509/CertParseError.java | 40 + - .../security/x509/CertificateAlgorithmId.java | 187 +++ - .../netscape/security/x509/CertificateChain.java | 139 ++ - .../security/x509/CertificateExtensions.java | 303 ++++ - .../security/x509/CertificateIssuerExtension.java | 241 +++ - .../security/x509/CertificateIssuerName.java | 172 +++ - .../x509/CertificateIssuerUniqueIdentity.java | 185 +++ - .../x509/CertificatePoliciesExtension.java | 339 +++++ - .../security/x509/CertificatePolicyId.java | 85 ++ - .../security/x509/CertificatePolicyInfo.java | 110 ++ - .../security/x509/CertificatePolicyMap.java | 100 ++ - .../security/x509/CertificatePolicySet.java | 86 ++ - .../security/x509/CertificateSerialNumber.java | 191 +++ - .../security/x509/CertificateSubjectName.java | 211 +++ - .../x509/CertificateSubjectUniqueIdentity.java | 185 +++ - .../security/x509/CertificateValidity.java | 301 ++++ - .../netscape/security/x509/CertificateVersion.java | 248 +++ - .../netscape/security/x509/CertificateX509Key.java | 188 +++ - .../jss/netscape/security/x509/DNSName.java | 90 ++ - .../security/x509/DeltaCRLIndicatorExtension.java | 240 +++ - .../netscape/security/x509/DirStrConverter.java | 172 +++ - .../jss/netscape/security/x509/DisplayText.java | 85 ++ - .../jss/netscape/security/x509/EDIPartyName.java | 157 ++ - .../jss/netscape/security/x509/Extension.java | 195 +++ - .../jss/netscape/security/x509/Extensions.java | 252 ++++ - .../security/x509/FreshestCRLExtension.java | 403 +++++ - .../jss/netscape/security/x509/GeneralName.java | 214 +++ - .../security/x509/GeneralNameInterface.java | 60 + - .../jss/netscape/security/x509/GeneralNames.java | 150 ++ - .../security/x509/GeneralNamesException.java | 50 + - .../jss/netscape/security/x509/GeneralSubtree.java | 162 ++ - .../netscape/security/x509/GeneralSubtrees.java | 109 ++ - .../security/x509/GenericValueConverter.java | 143 ++ - .../security/x509/HoldInstructionExtension.java | 356 +++++ - .../netscape/security/x509/IA5StringConverter.java | 123 ++ - .../jss/netscape/security/x509/IPAddressName.java | 277 ++++ - .../security/x509/InvalidIPAddressException.java | 33 + - .../security/x509/InvalidityDateExtension.java | 242 +++ - .../x509/IssuerAlternativeNameExtension.java | 239 +++ - .../security/x509/IssuingDistributionPoint.java | 323 ++++ - .../x509/IssuingDistributionPointExtension.java | 425 ++++++ - .../jss/netscape/security/x509/KeyIdentifier.java | 87 ++ - .../netscape/security/x509/KeyUsageExtension.java | 420 ++++++ - .../netscape/security/x509/LdapDNStrConverter.java | 144 ++ - .../security/x509/LdapV3DNStrConverter.java | 824 ++++++++++ - org/mozilla/jss/netscape/security/x509/Makefile | 45 + - .../security/x509/NSCCommentExtension.java | 229 +++ - .../security/x509/NameConstraintsExtension.java | 315 ++++ - .../netscape/security/x509/NoticeReference.java | 96 ++ - org/mozilla/jss/netscape/security/x509/OIDMap.java | 337 +++++ - .../jss/netscape/security/x509/OIDName.java | 90 ++ - .../jss/netscape/security/x509/OtherName.java | 214 +++ - .../jss/netscape/security/x509/PKIXExtensions.java | 185 +++ - .../netscape/security/x509/PolicyConstraint.java | 136 ++ - .../security/x509/PolicyConstraintsExtension.java | 307 ++++ - .../security/x509/PolicyMappingsExtension.java | 259 ++++ - .../security/x509/PolicyQualifierInfo.java | 118 ++ - .../netscape/security/x509/PolicyQualifiers.java | 107 ++ - .../netscape/security/x509/PrintableConverter.java | 114 ++ - .../security/x509/PrivateKeyUsageExtension.java | 340 +++++ - .../jss/netscape/security/x509/Qualifier.java | 63 + - org/mozilla/jss/netscape/security/x509/RDN.java | 304 ++++ - .../security/x509/RFC1779StrConverter.java | 102 ++ - .../jss/netscape/security/x509/RFC822Name.java | 85 ++ - .../jss/netscape/security/x509/ReasonFlags.java | 283 ++++ - .../netscape/security/x509/RevocationReason.java | 129 ++ - .../security/x509/RevocationReasonAdapter.java | 38 + - .../netscape/security/x509/RevokedCertImpl.java | 447 ++++++ - .../netscape/security/x509/RevokedCertificate.java | 95 ++ - .../jss/netscape/security/x509/SerialNumber.java | 127 ++ - .../x509/SubjectAlternativeNameExtension.java | 257 ++++ - .../x509/SubjectDirAttributesExtension.java | 289 ++++ - .../x509/SubjectKeyIdentifierExtension.java | 222 +++ - .../jss/netscape/security/x509/URIName.java | 85 ++ - .../jss/netscape/security/x509/UniqueIdentity.java | 112 ++ - .../jss/netscape/security/x509/UserNotice.java | 96 ++ - .../jss/netscape/security/x509/X500Name.java | 723 +++++++++ - .../netscape/security/x509/X500NameAttrMap.java | 376 +++++ - .../jss/netscape/security/x509/X500Signer.java | 110 ++ - .../netscape/security/x509/X509AttributeName.java | 64 + - .../jss/netscape/security/x509/X509CRLImpl.java | 1078 +++++++++++++ - .../jss/netscape/security/x509/X509Cert.java | 846 +++++++++++ - .../jss/netscape/security/x509/X509CertImpl.java | 1239 +++++++++++++++ - .../jss/netscape/security/x509/X509CertInfo.java | 976 ++++++++++++ - .../security/x509/X509ExtensionException.java | 54 + - .../jss/netscape/security/x509/X509Key.java | 501 +++++++ - org/mozilla/jss/netscape/security/x509/manifest.mn | 10 + - org/mozilla/jss/netscape/security/x509/rules.mk | 18 + - org/mozilla/jss/tests/X509CertTest.java | 155 ++ - 199 files changed, 45920 insertions(+), 0 deletion(-) - create mode 100644 org/mozilla/jss/netscape/Makefile - create mode 100644 org/mozilla/jss/netscape/manifest.mn - create mode 100644 org/mozilla/jss/netscape/security/Makefile - create mode 100644 org/mozilla/jss/netscape/security/acl/AclEntryImpl.java - create mode 100644 org/mozilla/jss/netscape/security/acl/AclImpl.java - create mode 100644 org/mozilla/jss/netscape/security/acl/AllPermissionsImpl.java - create mode 100644 org/mozilla/jss/netscape/security/acl/GroupImpl.java - create mode 100644 org/mozilla/jss/netscape/security/acl/Makefile - create mode 100644 org/mozilla/jss/netscape/security/acl/OwnerImpl.java - create mode 100644 org/mozilla/jss/netscape/security/acl/PermissionImpl.java - create mode 100644 org/mozilla/jss/netscape/security/acl/PrincipalImpl.java - create mode 100644 org/mozilla/jss/netscape/security/acl/WorldGroupImpl.java - create mode 100644 org/mozilla/jss/netscape/security/acl/manifest.mn - create mode 100644 org/mozilla/jss/netscape/security/extensions/AccessDescription.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/AuthInfoAccessExtension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/CertInfo.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/CertificateRenewalWindowExtension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/CertificateScopeEntry.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/CertificateScopeOfUseExtension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/ExtendedKeyUsageExtension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/GenericASN1Extension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/InhibitAnyPolicyExtension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/KerberosName.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/Makefile - create mode 100644 org/mozilla/jss/netscape/security/extensions/NSCertTypeExtension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/OCSPNoCheckExtension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/PresenceServerExtension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/SubjectInfoAccessExtension.java - create mode 100644 org/mozilla/jss/netscape/security/extensions/manifest.mn - create mode 100644 org/mozilla/jss/netscape/security/manifest.mn - create mode 100644 org/mozilla/jss/netscape/security/pkcs/ContentInfo.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/EncodingException.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/Makefile - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS10.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS10Attribute.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS10Attributes.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS12.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS12CertInfo.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS12KeyInfo.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS12Util.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS7.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS8Key.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS9Attribute.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/PKCS9Attributes.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/ParsingException.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/SignerInfo.java - create mode 100644 org/mozilla/jss/netscape/security/pkcs/manifest.mn - create mode 100644 org/mozilla/jss/netscape/security/provider/CMS.java - create mode 100644 org/mozilla/jss/netscape/security/provider/DSA.java - create mode 100755 org/mozilla/jss/netscape/security/provider/DSAKeyFactory.java - create mode 100644 org/mozilla/jss/netscape/security/provider/DSAKeyPairGenerator.java - create mode 100755 org/mozilla/jss/netscape/security/provider/DSAParameterGenerator.java - create mode 100755 org/mozilla/jss/netscape/security/provider/DSAParameters.java - create mode 100644 org/mozilla/jss/netscape/security/provider/DSAPrivateKey.java - create mode 100644 org/mozilla/jss/netscape/security/provider/DSAPublicKey.java - create mode 100644 org/mozilla/jss/netscape/security/provider/MD5.java - create mode 100644 org/mozilla/jss/netscape/security/provider/Makefile - create mode 100644 org/mozilla/jss/netscape/security/provider/RSAPublicKey.java - create mode 100644 org/mozilla/jss/netscape/security/provider/SHA.java - create mode 100644 org/mozilla/jss/netscape/security/provider/Sun.java - create mode 100644 org/mozilla/jss/netscape/security/provider/X509CertificateFactory.java - create mode 100644 org/mozilla/jss/netscape/security/provider/manifest.mn - create mode 100644 org/mozilla/jss/netscape/security/util/ASN1CharStrConvMap.java - create mode 100644 org/mozilla/jss/netscape/security/util/ASN1CharsetProvider.java - create mode 100644 org/mozilla/jss/netscape/security/util/BigInt.java - create mode 100644 org/mozilla/jss/netscape/security/util/BitArray.java - create mode 100644 org/mozilla/jss/netscape/security/util/ByteArrayLexOrder.java - create mode 100644 org/mozilla/jss/netscape/security/util/ByteArrayTagOrder.java - create mode 100644 org/mozilla/jss/netscape/security/util/Cert.java - create mode 100644 org/mozilla/jss/netscape/security/util/CertPrettyPrint.java - create mode 100644 org/mozilla/jss/netscape/security/util/CrlPrettyPrint.java - create mode 100644 org/mozilla/jss/netscape/security/util/DerEncoder.java - create mode 100644 org/mozilla/jss/netscape/security/util/DerInputBuffer.java - create mode 100644 org/mozilla/jss/netscape/security/util/DerInputStream.java - create mode 100644 org/mozilla/jss/netscape/security/util/DerOutputStream.java - create mode 100644 org/mozilla/jss/netscape/security/util/DerValue.java - create mode 100644 org/mozilla/jss/netscape/security/util/ExtPrettyPrint.java - create mode 100644 org/mozilla/jss/netscape/security/util/IA5Charset.java - create mode 100644 org/mozilla/jss/netscape/security/util/IA5CharsetDecoder.java - create mode 100644 org/mozilla/jss/netscape/security/util/IA5CharsetEncoder.java - create mode 100644 org/mozilla/jss/netscape/security/util/Makefile - create mode 100644 org/mozilla/jss/netscape/security/util/ObjectIdentifier.java - create mode 100644 org/mozilla/jss/netscape/security/util/PrettyPrintFormat.java - create mode 100644 org/mozilla/jss/netscape/security/util/PrettyPrintResources.java - create mode 100644 org/mozilla/jss/netscape/security/util/PrintableCharset.java - create mode 100644 org/mozilla/jss/netscape/security/util/PrintableCharsetDecoder.java - create mode 100644 org/mozilla/jss/netscape/security/util/PrintableCharsetEncoder.java - create mode 100644 org/mozilla/jss/netscape/security/util/PubKeyPrettyPrint.java - create mode 100644 org/mozilla/jss/netscape/security/util/UniversalCharset.java - create mode 100644 org/mozilla/jss/netscape/security/util/UniversalCharsetDecoder.java - create mode 100644 org/mozilla/jss/netscape/security/util/UniversalCharsetEncoder.java - create mode 100644 org/mozilla/jss/netscape/security/util/Utils.java - create mode 100644 org/mozilla/jss/netscape/security/util/manifest.mn - create mode 100755 org/mozilla/jss/netscape/security/x509/ACertAttrSet.java - create mode 100644 org/mozilla/jss/netscape/security/x509/AVA.java - create mode 100644 org/mozilla/jss/netscape/security/x509/AVAValueConverter.java - create mode 100644 org/mozilla/jss/netscape/security/x509/AlgIdDSA.java - create mode 100644 org/mozilla/jss/netscape/security/x509/AlgorithmId.java - create mode 100644 org/mozilla/jss/netscape/security/x509/Attribute.java - create mode 100644 org/mozilla/jss/netscape/security/x509/AuthorityKeyIdentifierExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/BasicConstraintsExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CPSuri.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CRLDistributionPoint.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CRLDistributionPointsExtension.java - create mode 100755 org/mozilla/jss/netscape/security/x509/CRLExtensions.java - create mode 100755 org/mozilla/jss/netscape/security/x509/CRLNumberExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CRLReasonExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertAndKeyGen.java - create mode 100755 org/mozilla/jss/netscape/security/x509/CertAttrSet.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertException.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertParseError.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateAlgorithmId.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateChain.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateExtensions.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateIssuerExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateIssuerName.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateIssuerUniqueIdentity.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificatePoliciesExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificatePolicyId.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificatePolicyInfo.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificatePolicyMap.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificatePolicySet.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateSerialNumber.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateSubjectName.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateSubjectUniqueIdentity.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateValidity.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateVersion.java - create mode 100644 org/mozilla/jss/netscape/security/x509/CertificateX509Key.java - create mode 100644 org/mozilla/jss/netscape/security/x509/DNSName.java - create mode 100755 org/mozilla/jss/netscape/security/x509/DeltaCRLIndicatorExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/DirStrConverter.java - create mode 100644 org/mozilla/jss/netscape/security/x509/DisplayText.java - create mode 100644 org/mozilla/jss/netscape/security/x509/EDIPartyName.java - create mode 100644 org/mozilla/jss/netscape/security/x509/Extension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/Extensions.java - create mode 100644 org/mozilla/jss/netscape/security/x509/FreshestCRLExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/GeneralName.java - create mode 100644 org/mozilla/jss/netscape/security/x509/GeneralNameInterface.java - create mode 100644 org/mozilla/jss/netscape/security/x509/GeneralNames.java - create mode 100644 org/mozilla/jss/netscape/security/x509/GeneralNamesException.java - create mode 100644 org/mozilla/jss/netscape/security/x509/GeneralSubtree.java - create mode 100644 org/mozilla/jss/netscape/security/x509/GeneralSubtrees.java - create mode 100644 org/mozilla/jss/netscape/security/x509/GenericValueConverter.java - create mode 100644 org/mozilla/jss/netscape/security/x509/HoldInstructionExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/IA5StringConverter.java - create mode 100644 org/mozilla/jss/netscape/security/x509/IPAddressName.java - create mode 100644 org/mozilla/jss/netscape/security/x509/InvalidIPAddressException.java - create mode 100755 org/mozilla/jss/netscape/security/x509/InvalidityDateExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/IssuerAlternativeNameExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/IssuingDistributionPoint.java - create mode 100644 org/mozilla/jss/netscape/security/x509/IssuingDistributionPointExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/KeyIdentifier.java - create mode 100644 org/mozilla/jss/netscape/security/x509/KeyUsageExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/LdapDNStrConverter.java - create mode 100644 org/mozilla/jss/netscape/security/x509/LdapV3DNStrConverter.java - create mode 100644 org/mozilla/jss/netscape/security/x509/Makefile - create mode 100644 org/mozilla/jss/netscape/security/x509/NSCCommentExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/NameConstraintsExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/NoticeReference.java - create mode 100644 org/mozilla/jss/netscape/security/x509/OIDMap.java - create mode 100644 org/mozilla/jss/netscape/security/x509/OIDName.java - create mode 100644 org/mozilla/jss/netscape/security/x509/OtherName.java - create mode 100644 org/mozilla/jss/netscape/security/x509/PKIXExtensions.java - create mode 100644 org/mozilla/jss/netscape/security/x509/PolicyConstraint.java - create mode 100644 org/mozilla/jss/netscape/security/x509/PolicyConstraintsExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/PolicyMappingsExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/PolicyQualifierInfo.java - create mode 100644 org/mozilla/jss/netscape/security/x509/PolicyQualifiers.java - create mode 100644 org/mozilla/jss/netscape/security/x509/PrintableConverter.java - create mode 100644 org/mozilla/jss/netscape/security/x509/PrivateKeyUsageExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/Qualifier.java - create mode 100644 org/mozilla/jss/netscape/security/x509/RDN.java - create mode 100644 org/mozilla/jss/netscape/security/x509/RFC1779StrConverter.java - create mode 100644 org/mozilla/jss/netscape/security/x509/RFC822Name.java - create mode 100755 org/mozilla/jss/netscape/security/x509/ReasonFlags.java - create mode 100644 org/mozilla/jss/netscape/security/x509/RevocationReason.java - create mode 100644 org/mozilla/jss/netscape/security/x509/RevocationReasonAdapter.java - create mode 100755 org/mozilla/jss/netscape/security/x509/RevokedCertImpl.java - create mode 100644 org/mozilla/jss/netscape/security/x509/RevokedCertificate.java - create mode 100644 org/mozilla/jss/netscape/security/x509/SerialNumber.java - create mode 100644 org/mozilla/jss/netscape/security/x509/SubjectAlternativeNameExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/SubjectDirAttributesExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/SubjectKeyIdentifierExtension.java - create mode 100644 org/mozilla/jss/netscape/security/x509/URIName.java - create mode 100644 org/mozilla/jss/netscape/security/x509/UniqueIdentity.java - create mode 100644 org/mozilla/jss/netscape/security/x509/UserNotice.java - create mode 100644 org/mozilla/jss/netscape/security/x509/X500Name.java - create mode 100644 org/mozilla/jss/netscape/security/x509/X500NameAttrMap.java - create mode 100644 org/mozilla/jss/netscape/security/x509/X500Signer.java - create mode 100644 org/mozilla/jss/netscape/security/x509/X509AttributeName.java - create mode 100755 org/mozilla/jss/netscape/security/x509/X509CRLImpl.java - create mode 100644 org/mozilla/jss/netscape/security/x509/X509Cert.java - create mode 100755 org/mozilla/jss/netscape/security/x509/X509CertImpl.java - create mode 100644 org/mozilla/jss/netscape/security/x509/X509CertInfo.java - create mode 100644 org/mozilla/jss/netscape/security/x509/X509ExtensionException.java - create mode 100644 org/mozilla/jss/netscape/security/x509/X509Key.java - create mode 100644 org/mozilla/jss/netscape/security/x509/manifest.mn - create mode 100644 org/mozilla/jss/netscape/security/x509/rules.mk - create mode 100644 org/mozilla/jss/tests/X509CertTest.java - -diff --git a/org/mozilla/jss/netscape/Makefile b/org/mozilla/jss/netscape/Makefile -new file mode 100644 -index 00000000..8fd7054b ---- /dev/null -+++ b/org/mozilla/jss/netscape/Makefile -@@ -0,0 +1,45 @@ -+#! gmake -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+####################################################################### -+# (1) Include initial platform-independent assignments (MANDATORY). # -+####################################################################### -+ -+include manifest.mn -+ -+####################################################################### -+# (2) Include "global" configuration information. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/config.mk -+ -+####################################################################### -+# (3) Include "component" configuration information. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (4) Include "local" platform-dependent assignments (OPTIONAL). # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (5) Execute "global" rules. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/rules.mk -+ -+####################################################################### -+# (6) Execute "component" rules. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -diff --git a/org/mozilla/jss/netscape/manifest.mn b/org/mozilla/jss/netscape/manifest.mn -new file mode 100644 -index 00000000..a69b9346 ---- /dev/null -+++ b/org/mozilla/jss/netscape/manifest.mn -@@ -0,0 +1,14 @@ -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+CORE_DEPTH = ../../../.. -+ -+NS_USE_JDK = 1 -+ -+MODULE = jss -+ -+ -+DIRS = security \ -+ $(NULL) -diff --git a/org/mozilla/jss/netscape/security/Makefile b/org/mozilla/jss/netscape/security/Makefile -new file mode 100644 -index 00000000..8fd7054b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/Makefile -@@ -0,0 +1,45 @@ -+#! gmake -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+####################################################################### -+# (1) Include initial platform-independent assignments (MANDATORY). # -+####################################################################### -+ -+include manifest.mn -+ -+####################################################################### -+# (2) Include "global" configuration information. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/config.mk -+ -+####################################################################### -+# (3) Include "component" configuration information. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (4) Include "local" platform-dependent assignments (OPTIONAL). # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (5) Execute "global" rules. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/rules.mk -+ -+####################################################################### -+# (6) Execute "component" rules. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -diff --git a/org/mozilla/jss/netscape/security/acl/AclEntryImpl.java b/org/mozilla/jss/netscape/security/acl/AclEntryImpl.java -new file mode 100644 -index 00000000..790da68f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/AclEntryImpl.java -@@ -0,0 +1,182 @@ -+// --- 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 netscape.security.acl; -+ -+import java.security.Principal; -+import java.security.acl.AclEntry; -+import java.security.acl.Group; -+import java.security.acl.Permission; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+/** -+ * This is a class that describes one entry that associates users -+ * or groups with permissions in the ACL. -+ * The entry may be used as a way of granting or denying permissions. -+ * -+ * @author Satish Dharmaraj -+ */ -+public class AclEntryImpl implements AclEntry { -+ private Principal user = null; -+ private Vector permissionSet = new Vector(10, 10); -+ private boolean negative = false; -+ -+ /** -+ * Construct an ACL entry that associates a user with permissions -+ * in the ACL. -+ * -+ * @param user The user that is associated with this entry. -+ */ -+ public AclEntryImpl(Principal user) { -+ this.user = user; -+ } -+ -+ /** -+ * Construct a null ACL entry -+ */ -+ public AclEntryImpl() { -+ } -+ -+ /** -+ * Sets the principal in the entity. If a group or a -+ * principal had already been set, a false value is -+ * returned, otherwise a true value is returned. -+ * -+ * @param user The user that is associated with this entry. -+ * @return true if the principal is set, false if there is -+ * one already. -+ */ -+ public boolean setPrincipal(Principal user) { -+ if (this.user != null) -+ return false; -+ this.user = user; -+ return true; -+ } -+ -+ /** -+ * This method sets the ACL to have negative permissions. -+ * That is the user or group is denied the permission set -+ * specified in the entry. -+ */ -+ public void setNegativePermissions() { -+ negative = true; -+ } -+ -+ /** -+ * Returns true if this is a negative ACL. -+ */ -+ public boolean isNegative() { -+ return negative; -+ } -+ -+ /** -+ * A principal or a group can be associated with multiple -+ * permissions. This method adds a permission to the ACL entry. -+ * -+ * @param permission The permission to be associated with -+ * the principal or the group in the entry. -+ * @return true if the permission was added, false if the -+ * permission was already part of the permission set. -+ */ -+ public boolean addPermission(Permission permission) { -+ -+ if (permissionSet.contains(permission)) -+ return false; -+ -+ permissionSet.addElement(permission); -+ -+ return true; -+ } -+ -+ /** -+ * The method disassociates the permission from the Principal -+ * or the Group in this ACL entry. -+ * -+ * @param permission The permission to be disassociated with -+ * the principal or the group in the entry. -+ * @return true if the permission is removed, false if the -+ * permission is not part of the permission set. -+ */ -+ public boolean removePermission(Permission permission) { -+ return permissionSet.removeElement(permission); -+ } -+ -+ /** -+ * Checks if the passed permission is part of the allowed -+ * permission set in this entry. -+ * -+ * @param permission The permission that has to be part of -+ * the permission set in the entry. -+ * @return true if the permission passed is part of the -+ * permission set in the entry, false otherwise. -+ */ -+ public boolean checkPermission(Permission permission) { -+ return permissionSet.contains(permission); -+ } -+ -+ /** -+ * return an enumeration of the permissions in this ACL entry. -+ */ -+ public Enumeration permissions() { -+ return permissionSet.elements(); -+ } -+ -+ /** -+ * Return a string representation of the contents of the ACL entry. -+ */ -+ public String toString() { -+ StringBuffer s = new StringBuffer(); -+ if (negative) -+ s.append("-"); -+ else -+ s.append("+"); -+ if (user instanceof Group) -+ s.append("Group."); -+ else -+ s.append("User."); -+ s.append(user + "="); -+ Enumeration e = permissions(); -+ while (e.hasMoreElements()) { -+ Permission p = e.nextElement(); -+ s.append(p); -+ if (e.hasMoreElements()) -+ s.append(","); -+ } -+ return new String(s); -+ } -+ -+ /** -+ * Clones an AclEntry. -+ */ -+ public synchronized Object clone() { -+ AclEntryImpl cloned; -+ cloned = new AclEntryImpl(user); -+ cloned.permissionSet = new Vector(permissionSet); -+ cloned.negative = negative; -+ return cloned; -+ } -+ -+ /** -+ * Return the Principal associated in this ACL entry. -+ * The method returns null if the entry uses a group -+ * instead of a principal. -+ */ -+ public Principal getPrincipal() { -+ return user; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/acl/AclImpl.java b/org/mozilla/jss/netscape/security/acl/AclImpl.java -new file mode 100644 -index 00000000..9ccb0fc1 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/AclImpl.java -@@ -0,0 +1,393 @@ -+// --- 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 netscape.security.acl; -+ -+import java.security.Principal; -+import java.security.acl.Acl; -+import java.security.acl.AclEntry; -+import java.security.acl.Group; -+import java.security.acl.NotOwnerException; -+import java.security.acl.Permission; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.NoSuchElementException; -+import java.util.Vector; -+ -+/** -+ * An Access Control List (ACL) is encapsulated by this class. -+ * -+ * @author Satish Dharmaraj -+ */ -+public class AclImpl extends OwnerImpl implements Acl { -+ // -+ // Maintain four tables. one each for positive and negative -+ // ACLs. One each depending on whether the entity is a group -+ // or principal. -+ // -+ private Hashtable allowedUsersTable = new Hashtable(23); -+ private Hashtable allowedGroupsTable = new Hashtable(23); -+ private Hashtable deniedUsersTable = new Hashtable(23); -+ private Hashtable deniedGroupsTable = new Hashtable(23); -+ private String aclName = null; -+ private Vector zeroSet = new Vector(1, 1); -+ -+ /** -+ * Constructor for creating an empty ACL. -+ */ -+ public AclImpl(Principal owner, String name) { -+ super(owner); -+ try { -+ setName(owner, name); -+ } catch (Exception e) { -+ } -+ } -+ -+ /** -+ * Sets the name of the ACL. -+ * -+ * @param caller the principal who is invoking this method. -+ * @param name the name of the ACL. -+ * @exception NotOwnerException if the caller principal is -+ * not on the owners list of the Acl. -+ */ -+ public void setName(Principal caller, String name) -+ throws NotOwnerException { -+ if (!isOwner(caller)) -+ throw new NotOwnerException(); -+ -+ aclName = name; -+ } -+ -+ /** -+ * Returns the name of the ACL. -+ * -+ * @return the name of the ACL. -+ */ -+ public String getName() { -+ return aclName; -+ } -+ -+ /** -+ * Adds an ACL entry to this ACL. An entry associates a -+ * group or a principal with a set of permissions. Each -+ * user or group can have one positive ACL entry and one -+ * negative ACL entry. If there is one of the type (negative -+ * or positive) already in the table, a false value is returned. -+ * The caller principal must be a part of the owners list of -+ * the ACL in order to invoke this method. -+ * -+ * @param caller the principal who is invoking this method. -+ * @param entry the ACL entry that must be added to the ACL. -+ * @return true on success, false if the entry is already present. -+ * @exception NotOwnerException if the caller principal -+ * is not on the owners list of the Acl. -+ */ -+ public synchronized boolean addEntry(Principal caller, AclEntry entry) -+ throws NotOwnerException { -+ if (!isOwner(caller)) -+ throw new NotOwnerException(); -+ -+ Hashtable aclTable = findTable(entry); -+ Principal key = entry.getPrincipal(); -+ -+ if (aclTable.get(key) != null) -+ return false; -+ -+ aclTable.put(key, entry); -+ return true; -+ } -+ -+ /** -+ * Removes an ACL entry from this ACL. -+ * The caller principal must be a part of the owners list of the ACL -+ * in order to invoke this method. -+ * -+ * @param caller the principal who is invoking this method. -+ * @param entry the ACL entry that must be removed from the ACL. -+ * @return true on success, false if the entry is not part of the ACL. -+ * @exception NotOwnerException if the caller principal is not -+ * the owners list of the Acl. -+ */ -+ public synchronized boolean removeEntry(Principal caller, AclEntry entry) -+ throws NotOwnerException { -+ if (!isOwner(caller)) -+ throw new NotOwnerException(); -+ -+ Hashtable aclTable = findTable(entry); -+ Object key = entry.getPrincipal(); -+ -+ Object o = aclTable.remove(key); -+ return (o != null); -+ } -+ -+ /** -+ * This method returns the set of allowed permissions for the -+ * specified principal. This set of allowed permissions is calculated -+ * as follows: -+ * -+ * If there is no entry for a group or a principal an empty permission -+ * set is assumed. -+ * -+ * The group positive permission set is the union of all -+ * the positive permissions of each group that the individual belongs to. -+ * The group negative permission set is the union of all -+ * the negative permissions of each group that the individual belongs to. -+ * If there is a specific permission that occurs in both -+ * the postive permission set and the negative permission set, -+ * it is removed from both. The group positive and negatoive permission -+ * sets are calculated. -+ * -+ * The individial positive permission set and the individual negative -+ * permission set is then calculated. Again abscence of an entry means -+ * the empty set. -+ * -+ * The set of permissions granted to the principal is then calculated using -+ * the simple rule: Individual permissions always override the Group permissions. -+ * Specifically, individual negative permission set (specific -+ * denial of permissions) overrides the group positive permission set. -+ * And the individual positive permission set override the group negative -+ * permission set. -+ * -+ * @param user the principal for which the ACL entry is returned. -+ * @return The resulting permission set that the principal is allowed. -+ */ -+ public synchronized Enumeration getPermissions(Principal user) { -+ -+ Enumeration individualPositive; -+ Enumeration individualNegative; -+ Enumeration groupPositive; -+ Enumeration groupNegative; -+ -+ // -+ // canonicalize the sets. That is remove common permissions from -+ // positive and negative sets. -+ // -+ groupPositive = subtract(getGroupPositive(user), getGroupNegative(user)); -+ groupNegative = subtract(getGroupNegative(user), getGroupPositive(user)); -+ individualPositive = subtract(getIndividualPositive(user), getIndividualNegative(user)); -+ individualNegative = subtract(getIndividualNegative(user), getIndividualPositive(user)); -+ -+ // -+ // net positive permissions is individual positive permissions -+ // plus (group positive - individual negative). -+ // -+ Enumeration temp1 = subtract(groupPositive, individualNegative); -+ Enumeration netPositive = union(individualPositive, temp1); -+ -+ // recalculate the enumeration since we lost it in performing the -+ // subtraction -+ // -+ individualPositive = subtract(getIndividualPositive(user), getIndividualNegative(user)); -+ individualNegative = subtract(getIndividualNegative(user), getIndividualPositive(user)); -+ -+ // -+ // net negative permissions is individual negative permissions -+ // plus (group negative - individual positive). -+ // -+ temp1 = subtract(groupNegative, individualPositive); -+ Enumeration netNegative = union(individualNegative, temp1); -+ -+ return subtract(netPositive, netNegative); -+ } -+ -+ /** -+ * This method checks whether or not the specified principal -+ * has the required permission. If permission is denied -+ * permission false is returned, a true value is returned otherwise. -+ * This method does not authenticate the principal. It presumes that -+ * the principal is a valid authenticated principal. -+ * -+ * @param principal the name of the authenticated principal -+ * @param permission the permission that the principal must have. -+ * @return true of the principal has the permission desired, false -+ * otherwise. -+ */ -+ public boolean checkPermission(Principal principal, Permission permission) { -+ Enumeration permSet = getPermissions(principal); -+ while (permSet.hasMoreElements()) { -+ Permission p = permSet.nextElement(); -+ if (p.equals(permission)) -+ return true; -+ } -+ return false; -+ } -+ -+ /** -+ * returns an enumeration of the entries in this ACL. -+ */ -+ public synchronized Enumeration entries() { -+ return new AclEnumerator(this, -+ allowedUsersTable, allowedGroupsTable, -+ deniedUsersTable, deniedGroupsTable); -+ } -+ -+ /** -+ * return a stringified version of the -+ * ACL. -+ */ -+ public String toString() { -+ StringBuffer sb = new StringBuffer(); -+ Enumeration entries = entries(); -+ while (entries.hasMoreElements()) { -+ AclEntry entry = entries.nextElement(); -+ sb.append(entry.toString().trim()); -+ sb.append("\n"); -+ } -+ -+ return sb.toString(); -+ } -+ -+ // -+ // Find the table that this entry belongs to. There are 4 -+ // tables that are maintained. One each for postive and -+ // negative ACLs and one each for groups and users. -+ // This method figures out which -+ // table is the one that this AclEntry belongs to. -+ // -+ private Hashtable findTable(AclEntry entry) { -+ Hashtable aclTable = null; -+ -+ Principal p = entry.getPrincipal(); -+ if (p instanceof Group) { -+ if (entry.isNegative()) -+ aclTable = deniedGroupsTable; -+ else -+ aclTable = allowedGroupsTable; -+ } else { -+ if (entry.isNegative()) -+ aclTable = deniedUsersTable; -+ else -+ aclTable = allowedUsersTable; -+ } -+ return aclTable; -+ } -+ -+ // -+ // returns the set e1 U e2. -+ // -+ private Enumeration union(Enumeration e1, Enumeration e2) { -+ Vector v = new Vector(20, 20); -+ -+ while (e1.hasMoreElements()) -+ v.addElement(e1.nextElement()); -+ -+ while (e2.hasMoreElements()) { -+ T o = e2.nextElement(); -+ if (!v.contains(o)) -+ v.addElement(o); -+ } -+ -+ return v.elements(); -+ } -+ -+ // -+ // returns the set e1 - e2. -+ // -+ private Enumeration subtract(Enumeration e1, Enumeration e2) { -+ Vector v = new Vector(20, 20); -+ -+ while (e1.hasMoreElements()) -+ v.addElement(e1.nextElement()); -+ -+ while (e2.hasMoreElements()) { -+ T o = e2.nextElement(); -+ if (v.contains(o)) -+ v.removeElement(o); -+ } -+ -+ return v.elements(); -+ } -+ -+ private Enumeration getGroupPositive(Principal user) { -+ Enumeration groupPositive = zeroSet.elements(); -+ Enumeration e = allowedGroupsTable.keys(); -+ while (e.hasMoreElements()) { -+ Group g = (Group) e.nextElement(); -+ if (g.isMember(user)) { -+ AclEntry ae = allowedGroupsTable.get(g); -+ groupPositive = union(ae.permissions(), groupPositive); -+ } -+ } -+ return groupPositive; -+ } -+ -+ private Enumeration getGroupNegative(Principal user) { -+ Enumeration groupNegative = zeroSet.elements(); -+ Enumeration e = deniedGroupsTable.keys(); -+ while (e.hasMoreElements()) { -+ Group g = (Group) e.nextElement(); -+ if (g.isMember(user)) { -+ AclEntry ae = deniedGroupsTable.get(g); -+ groupNegative = union(ae.permissions(), groupNegative); -+ } -+ } -+ return groupNegative; -+ } -+ -+ private Enumeration getIndividualPositive(Principal user) { -+ Enumeration individualPositive = zeroSet.elements(); -+ AclEntry ae = allowedUsersTable.get(user); -+ if (ae != null) -+ individualPositive = ae.permissions(); -+ return individualPositive; -+ } -+ -+ private Enumeration getIndividualNegative(Principal user) { -+ Enumeration individualNegative = zeroSet.elements(); -+ AclEntry ae = deniedUsersTable.get(user); -+ if (ae != null) -+ individualNegative = ae.permissions(); -+ return individualNegative; -+ } -+} -+ -+final class AclEnumerator implements Enumeration { -+ Acl acl; -+ Enumeration u1, u2, g1, g2; -+ -+ AclEnumerator(Acl acl, Hashtable u1, Hashtable g1, -+ Hashtable u2, Hashtable g2) { -+ this.acl = acl; -+ this.u1 = u1.elements(); -+ this.u2 = u2.elements(); -+ this.g1 = g1.elements(); -+ this.g2 = g2.elements(); -+ } -+ -+ public boolean hasMoreElements() { -+ synchronized (acl) { -+ return (u1.hasMoreElements() || -+ u2.hasMoreElements() || -+ g1.hasMoreElements() || g2.hasMoreElements()); -+ } -+ } -+ -+ public AclEntry nextElement() { -+ synchronized (acl) { -+ if (u1.hasMoreElements()) -+ return u1.nextElement(); -+ if (u2.hasMoreElements()) -+ return u2.nextElement(); -+ if (g1.hasMoreElements()) -+ return g1.nextElement(); -+ if (g2.hasMoreElements()) -+ return g2.nextElement(); -+ } -+ throw new NoSuchElementException("Acl Enumerator"); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/acl/AllPermissionsImpl.java b/org/mozilla/jss/netscape/security/acl/AllPermissionsImpl.java -new file mode 100644 -index 00000000..df3ff645 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/AllPermissionsImpl.java -@@ -0,0 +1,43 @@ -+// --- 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 netscape.security.acl; -+ -+import java.security.acl.Permission; -+ -+/** -+ * This class implements the principal interface for the set of all permissions. -+ * -+ * @author Satish Dharmaraj -+ */ -+public class AllPermissionsImpl extends PermissionImpl { -+ -+ public AllPermissionsImpl(String s) { -+ super(s); -+ } -+ -+ /** -+ * This function returns true if the permission passed matches the permission represented in -+ * this interface. -+ * -+ * @param another The Permission object to compare with. -+ * @return true always -+ */ -+ public boolean equals(Permission another) { -+ return true; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/acl/GroupImpl.java b/org/mozilla/jss/netscape/security/acl/GroupImpl.java -new file mode 100644 -index 00000000..d28e83f0 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/GroupImpl.java -@@ -0,0 +1,173 @@ -+// --- 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 netscape.security.acl; -+ -+import java.security.Principal; -+import java.security.acl.Group; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+/** -+ * This class implements a group of principals. -+ * -+ * @author Satish Dharmaraj -+ */ -+public class GroupImpl implements Group { -+ private Vector groupMembers = new Vector(50, 100); -+ private String group; -+ -+ /** -+ * Constructs a Group object with no members. -+ * -+ * @param groupName the name of the group -+ */ -+ public GroupImpl(String groupName) { -+ this.group = groupName; -+ } -+ -+ /** -+ * adds the specified member to the group. -+ * -+ * @param user The principal to add to the group. -+ * @return true if the member was added - false if the -+ * member could not be added. -+ */ -+ public boolean addMember(Principal user) { -+ if (groupMembers.contains(user)) -+ return false; -+ -+ // do not allow groups to be added to itself. -+ if (group.equals(user.toString())) -+ throw new IllegalArgumentException(); -+ -+ groupMembers.addElement(user); -+ return true; -+ } -+ -+ /** -+ * removes the specified member from the group. -+ * -+ * @param user The principal to remove from the group. -+ * @param true if the principal was removed false if -+ * the principal was not a member -+ */ -+ public boolean removeMember(Principal user) { -+ return groupMembers.removeElement(user); -+ } -+ -+ /** -+ * returns the enumeration of the members in the group. -+ */ -+ public Enumeration members() { -+ return groupMembers.elements(); -+ } -+ -+ /** -+ * This function returns true if the group passed matches -+ * the group represented in this interface. -+ * -+ * @param another The group to compare this group to. -+ */ -+ public boolean equals(Group another) { -+ return group.equals(another.toString()); -+ } -+ -+ /** -+ * Prints a stringified version of the group. -+ */ -+ public String toString() { -+ return group; -+ } -+ -+ /** -+ * return a hashcode for the principal. -+ */ -+ public int hashCode() { -+ return group.hashCode(); -+ } -+ -+ /** -+ * returns true if the passed principal is a member of the group. -+ * -+ * @param member The principal whose membership must be checked for. -+ * @return true if the principal is a member of this group, -+ * false otherwise -+ */ -+ public boolean isMember(Principal member) { -+ -+ // -+ // if the member is part of the group (common case), return true. -+ // if not, recursively search depth first in the group looking for the -+ // principal. -+ // -+ if (groupMembers.contains(member)) { -+ return true; -+ } else { -+ Vector alreadySeen = new Vector(10); -+ return isMemberRecurse(member, alreadySeen); -+ } -+ } -+ -+ /** -+ * return the name of the principal. -+ */ -+ public String getName() { -+ return group; -+ } -+ -+ // -+ // This function is the recursive search of groups for this -+ // implementation of the Group. The search proceeds building up -+ // a vector of already seen groups. Only new groups are considered, -+ // thereby avoiding loops. -+ // -+ boolean isMemberRecurse(Principal member, Vector alreadySeen) { -+ Enumeration e = members(); -+ while (e.hasMoreElements()) { -+ boolean mem = false; -+ Principal p = e.nextElement(); -+ -+ // if the member is in this collection, return true -+ if (p.equals(member)) { -+ return true; -+ } else if (p instanceof GroupImpl) { -+ // -+ // if not recurse if the group has not been checked already. -+ // Can call method in this package only if the object is an -+ // instance of this class. Otherwise call the method defined -+ // in the interface. (This can lead to a loop if a mixture of -+ // implementations form a loop, but we live with this improbable -+ // case rather than clutter the interface by forcing the -+ // implementation of this method.) -+ // -+ GroupImpl g = (GroupImpl) p; -+ alreadySeen.addElement(this); -+ if (!alreadySeen.contains(g)) -+ mem = g.isMemberRecurse(member, alreadySeen); -+ } else if (p instanceof Group) { -+ Group g = (Group) p; -+ if (!alreadySeen.contains(g)) -+ mem = g.isMember(member); -+ } -+ -+ if (mem) -+ return mem; -+ } -+ return false; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/acl/Makefile b/org/mozilla/jss/netscape/security/acl/Makefile -new file mode 100644 -index 00000000..8fd7054b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/Makefile -@@ -0,0 +1,45 @@ -+#! gmake -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+####################################################################### -+# (1) Include initial platform-independent assignments (MANDATORY). # -+####################################################################### -+ -+include manifest.mn -+ -+####################################################################### -+# (2) Include "global" configuration information. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/config.mk -+ -+####################################################################### -+# (3) Include "component" configuration information. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (4) Include "local" platform-dependent assignments (OPTIONAL). # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (5) Execute "global" rules. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/rules.mk -+ -+####################################################################### -+# (6) Execute "component" rules. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -diff --git a/org/mozilla/jss/netscape/security/acl/OwnerImpl.java b/org/mozilla/jss/netscape/security/acl/OwnerImpl.java -new file mode 100644 -index 00000000..0e6e13e5 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/OwnerImpl.java -@@ -0,0 +1,105 @@ -+// --- 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 netscape.security.acl; -+ -+import java.security.Principal; -+import java.security.acl.Group; -+import java.security.acl.LastOwnerException; -+import java.security.acl.NotOwnerException; -+import java.security.acl.Owner; -+import java.util.Enumeration; -+ -+/** -+ * Class implementing the Owner interface. The -+ * initial owner principal is configured as -+ * part of the constructor. -+ * -+ * @author Satish Dharmaraj -+ */ -+public class OwnerImpl implements Owner { -+ private Group ownerGroup; -+ -+ public OwnerImpl(Principal owner) { -+ ownerGroup = new GroupImpl("AclOwners"); -+ ownerGroup.addMember(owner); -+ } -+ -+ /** -+ * Adds an owner. Owners can modify ACL contents and can disassociate -+ * ACLs from the objects they protect in the AclConfig interface. -+ * The caller principal must be a part of the owners list of the ACL in -+ * order to invoke this method. The initial owner is configured -+ * at ACL construction time. -+ * -+ * @param caller the principal who is invoking this method. -+ * @param owner The owner that should be added to the owners list. -+ * @return true if success, false if already an owner. -+ * @exception NotOwnerException if the caller principal is not on -+ * the owners list of the Acl. -+ */ -+ public synchronized boolean addOwner(Principal caller, Principal owner) -+ throws NotOwnerException { -+ if (!isOwner(caller)) -+ throw new NotOwnerException(); -+ -+ ownerGroup.addMember(owner); -+ return false; -+ } -+ -+ /** -+ * Delete owner. If this is the last owner in the ACL, an exception is -+ * raised. -+ * The caller principal must be a part of the owners list of the ACL in -+ * order to invoke this method. -+ * -+ * @param caller the principal who is invoking this method. -+ * @param owner The owner to be removed from the owners list. -+ * @return true if the owner is removed, false if the owner is not part -+ * of the owners list. -+ * @exception NotOwnerException if the caller principal is not on -+ * the owners list of the Acl. -+ * @exception LastOwnerException if there is only one owner left in the group, then -+ * deleteOwner would leave the ACL owner-less. This exception is raised in such a case. -+ */ -+ public synchronized boolean deleteOwner(Principal caller, Principal owner) -+ throws NotOwnerException, LastOwnerException { -+ if (!isOwner(caller)) -+ throw new NotOwnerException(); -+ -+ Enumeration e = ownerGroup.members(); -+ // -+ // check if there is atleast 2 members left. -+ // -+ e.nextElement(); // consume next element -+ if (e.hasMoreElements()) -+ return ownerGroup.removeMember(owner); -+ else -+ throw new LastOwnerException(); -+ -+ } -+ -+ /** -+ * returns if the given principal belongs to the owner list. -+ * -+ * @param owner The owner to check if part of the owners list -+ * @return true if the passed principal is in the owner list, false if not. -+ */ -+ public synchronized boolean isOwner(Principal owner) { -+ return ownerGroup.isMember(owner); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/acl/PermissionImpl.java b/org/mozilla/jss/netscape/security/acl/PermissionImpl.java -new file mode 100644 -index 00000000..80b36e1d ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/PermissionImpl.java -@@ -0,0 +1,73 @@ -+// --- 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 netscape.security.acl; -+ -+import java.security.acl.Permission; -+ -+/** -+ * The PermissionImpl class implements the permission -+ * interface for permissions that are strings. -+ * -+ * @author Satish Dharmaraj -+ */ -+public class PermissionImpl implements Permission { -+ -+ private String permission; -+ -+ /** -+ * Construct a permission object using a string. -+ * -+ * @param permission the stringified version of the permission. -+ */ -+ public PermissionImpl(String permission) { -+ this.permission = permission; -+ } -+ -+ /** -+ * This function returns true if the object passed matches the permission -+ * represented in this interface. -+ * -+ * @param another The Permission object to compare with. -+ * @return true if the Permission objects are equal, false otherwise -+ */ -+ public boolean equals(Object another) { -+ if (another instanceof Permission) { -+ Permission p = (Permission) another; -+ return permission.equals(p.toString()); -+ } else { -+ return false; -+ } -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + ((permission == null) ? 0 : permission.hashCode()); -+ return result; -+ } -+ -+ /** -+ * Prints a stringified version of the permission. -+ * -+ * @return the string representation of the Permission. -+ */ -+ public String toString() { -+ return permission; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/acl/PrincipalImpl.java b/org/mozilla/jss/netscape/security/acl/PrincipalImpl.java -new file mode 100644 -index 00000000..54de845d ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/PrincipalImpl.java -@@ -0,0 +1,77 @@ -+// --- 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 netscape.security.acl; -+ -+import java.security.Principal; -+ -+/** -+ * This class implements the principal interface. -+ * -+ * @author Satish Dharmaraj -+ */ -+public class PrincipalImpl implements Principal { -+ -+ private String user; -+ -+ /** -+ * Construct a principal from a string user name. -+ * -+ * @param user The string form of the principal name. -+ */ -+ public PrincipalImpl(String user) { -+ this.user = user; -+ } -+ -+ /** -+ * This function returns true if the object passed matches -+ * the principal represented in this implementation -+ * -+ * @param another the Principal to compare with. -+ * @return true if the Principal passed is the same as that -+ * encapsulated in this object, false otherwise -+ */ -+ public boolean equals(Object another) { -+ if (another instanceof PrincipalImpl) { -+ PrincipalImpl p = (PrincipalImpl) another; -+ return user.equals(p.toString()); -+ } else -+ return false; -+ } -+ -+ /** -+ * Prints a stringified version of the principal. -+ */ -+ public String toString() { -+ return user; -+ } -+ -+ /** -+ * return a hashcode for the principal. -+ */ -+ public int hashCode() { -+ return user.hashCode(); -+ } -+ -+ /** -+ * return the name of the principal. -+ */ -+ public String getName() { -+ return user; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/acl/WorldGroupImpl.java b/org/mozilla/jss/netscape/security/acl/WorldGroupImpl.java -new file mode 100644 -index 00000000..a8eea8a7 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/WorldGroupImpl.java -@@ -0,0 +1,42 @@ -+// --- 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 netscape.security.acl; -+ -+import java.security.Principal; -+ -+/** -+ * This class implements a group of principals. -+ * -+ * @author Satish Dharmaraj -+ */ -+public class WorldGroupImpl extends GroupImpl { -+ -+ public WorldGroupImpl(String s) { -+ super(s); -+ } -+ -+ /** -+ * returns true for all passed principals -+ * -+ * @param member The principal whose membership must be checked in this Group. -+ * @return true always since this is the "world" group. -+ */ -+ public boolean isMember(Principal member) { -+ return true; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/acl/manifest.mn b/org/mozilla/jss/netscape/security/acl/manifest.mn -new file mode 100644 -index 00000000..fc465961 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/acl/manifest.mn -@@ -0,0 +1,8 @@ -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+CORE_DEPTH = ../../../../../.. -+PACKAGE = org/mozilla/jss/netscape/security/acl -+MODULE = jss -diff --git a/org/mozilla/jss/netscape/security/extensions/AccessDescription.java b/org/mozilla/jss/netscape/security/extensions/AccessDescription.java -new file mode 100644 -index 00000000..48ca81e8 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/AccessDescription.java -@@ -0,0 +1,77 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.IOException; -+import java.io.Serializable; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.GeneralName; -+ -+public class AccessDescription implements Serializable { -+ ObjectIdentifier mOID = null; -+ GeneralName mLocation = null; -+ -+ AccessDescription(ObjectIdentifier oid, GeneralName location) { -+ mOID = oid; -+ mLocation = location; -+ } -+ -+ public ObjectIdentifier getMethod() { -+ return mOID; -+ } -+ -+ public GeneralName getLocation() { -+ return mLocation; -+ } -+ -+ /** -+ * For serialization: -+ * Note that GeneralName is not serializable. That is -+ * why we need to define our own serialization method. -+ */ -+ private void writeObject(java.io.ObjectOutputStream out) -+ throws IOException { -+ try (DerOutputStream seq = new DerOutputStream(); -+ DerOutputStream tmp = new DerOutputStream()) { -+ -+ tmp.putOID(mOID); -+ mLocation.encode(tmp); -+ seq.write(DerValue.tag_Sequence, tmp); -+ out.write(seq.toByteArray()); -+ } -+ } -+ -+ /** -+ * For serialization -+ * Note that GeneralName is not serializable. That is -+ * why we need to define our own serialization method. -+ */ -+ private void readObject(java.io.ObjectInputStream in) -+ throws IOException { -+ DerValue val = new DerValue(in); -+ DerValue seq = val.data.getDerValue(); -+ -+ mOID = seq.getOID(); -+ DerValue derLoc = val.data.getDerValue(); -+ -+ mLocation = new GeneralName(derLoc); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/AuthInfoAccessExtension.java b/org/mozilla/jss/netscape/security/extensions/AuthInfoAccessExtension.java -new file mode 100644 -index 00000000..ae84a5bf ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/AuthInfoAccessExtension.java -@@ -0,0 +1,275 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.ByteArrayInputStream; -+import java.io.ByteArrayOutputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.GeneralName; -+import org.mozilla.jss.netscape.security.x509.URIName; -+ -+import org.mozilla.jss.netscape.security.util.Utils; -+ -+/** -+ * This represents the authority information access extension -+ * as defined in RFC2459. -+ * -+ * id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) dod(6) -+ * internet(1) security(5) mechanisms(5) -+ * pkix(7) } } -+ * id-pe OBJECT IDENTIFIER ::= { id-pkix 1 } -+ * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } -+ * AuthorityInfoAccessSyntax ::= SEQUENCE SIZE (1..MAX) OF AccessDescription -+ * AccessDescription ::= SEQUENCE { -+ * accessMethod OBJECT IDENTIFIER, -+ * accessLocation GeneralName -+ * } -+ * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } -+ * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } -+ * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } -+ * -+ * Need to make sure the following is added to CMS.cfg: -+ * oidmap.auth_info_access.class=com.netscape.certsrv.cert.AuthInfoAccessExtension -+ * oidmap.auth_info_access.oid=1.3.6.1.5.5.7.1.1 -+ * -+ * @author thomask -+ * @version $Revision$, $Date$ -+ */ -+public class AuthInfoAccessExtension extends Extension implements CertAttrSet { -+ private static final long serialVersionUID = 7373316523212538446L; -+ public static final String NAME = "AuthInfoAccessExtension"; -+ public static final String NAME2 = "AuthorityInformationAccess"; -+ -+ public static final int OID_OCSP[] = { 1, 3, 6, 1, 5, 5, 7, 48, 1 }; -+ public static final ObjectIdentifier METHOD_OCSP = new -+ ObjectIdentifier(OID_OCSP); -+ -+ public static final int OID_CA_ISSUERS[] = { 1, 3, 6, 1, 5, 5, 7, 48, 2 }; -+ public static final ObjectIdentifier METHOD_CA_ISSUERS = new -+ ObjectIdentifier(OID_CA_ISSUERS); -+ -+ public static final int OID[] = { 1, 3, 6, 1, 5, 5, 7, 1, 1 }; -+ public static final ObjectIdentifier ID = new ObjectIdentifier(OID); -+ -+ private Vector mDesc = new Vector(); -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public AuthInfoAccessExtension(boolean critical) { -+ this.extensionId = ID; -+ this.critical = critical; -+ this.extensionValue = null; // build this when encodeThis() is called -+ } -+ -+ public AuthInfoAccessExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = ID; -+ this.critical = critical.booleanValue(); -+ this.extensionValue = ((byte[]) value).clone(); -+ decodeThis(); -+ } -+ -+ /** -+ * Sets extension attribute. -+ */ -+ public void set(String name, Object obj) throws CertificateException { -+ // NOT USED -+ } -+ -+ /** -+ * Retrieves extension attribute. -+ */ -+ public Object get(String name) throws CertificateException { -+ // NOT USED -+ return null; -+ } -+ -+ /** -+ * Deletes attribute. -+ */ -+ public void delete(String name) throws CertificateException { -+ // NOT USED -+ } -+ -+ /** -+ * Decodes this extension. -+ */ -+ public void decode(InputStream in) throws IOException { -+ // NOT USED -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ // NOT USED -+ return null; -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return NAME; -+ } -+ -+ /** -+ * Adds Access Description. -+ */ -+ public void addAccessDescription( -+ ObjectIdentifier method, -+ GeneralName gn) { -+ clearValue(); -+ mDesc.addElement(new AccessDescription(method, gn)); -+ } -+ -+ public AccessDescription getAccessDescription(int pos) { -+ return mDesc.elementAt(pos); -+ } -+ -+ /** -+ * Returns the number of access description. -+ */ -+ public int numberOfAccessDescription() { -+ return mDesc.size(); -+ } -+ -+ private void decodeThis() throws IOException { -+ DerValue val = new DerValue(this.extensionValue); -+ -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding of AuthInfoAccess extension"); -+ } -+ while (val.data.available() != 0) { -+ DerValue seq = val.data.getDerValue(); -+ ObjectIdentifier method = seq.data.getDerValue().getOID(); -+ GeneralName gn = new GeneralName(seq.data.getDerValue()); -+ -+ addAccessDescription(method, gn); -+ } -+ } -+ -+ private void encodeThis() throws IOException { -+ try (DerOutputStream seq = new DerOutputStream(); -+ DerOutputStream tmp = new DerOutputStream()) { -+ -+ for (int i = 0; i < mDesc.size(); i++) { -+ DerOutputStream tmp0 = new DerOutputStream(); -+ AccessDescription ad = mDesc.elementAt(i); -+ -+ tmp0.putOID(ad.getMethod()); -+ ad.getLocation().encode(tmp0); -+ tmp.write(DerValue.tag_Sequence, tmp0); -+ } -+ seq.write(DerValue.tag_Sequence, tmp); -+ this.extensionValue = seq.toByteArray(); -+ } -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Returns a printable representation of the AuthInfoAccess. -+ */ -+ public String toString() { -+ StringBuffer s = new StringBuffer(); -+ String b = super.toString() + "AuthInfoAccess [\n"; -+ s.append(b); -+ -+ for (int i = 0; i < mDesc.size(); i++) { -+ AccessDescription ad = mDesc.elementAt(i); -+ -+ s.append("(" + i + ")"); -+ s.append(" "); -+ s.append(ad.getMethod().toString() + " " + ad.getLocation().toString()); -+ } -+ return (s.toString() + "]\n"); -+ } -+ -+ public static void main(String[] argv) { -+ AuthInfoAccessExtension aia = new AuthInfoAccessExtension(false); -+ GeneralName ocspName = new GeneralName(new -+ URIName("http://ocsp.netscape.com")); -+ -+ aia.addAccessDescription(METHOD_OCSP, ocspName); -+ GeneralName caIssuersName = new GeneralName(new -+ URIName("http://ocsp.netscape.com")); -+ -+ aia.addAccessDescription(METHOD_CA_ISSUERS, caIssuersName); -+ ByteArrayOutputStream os = new ByteArrayOutputStream(); -+ -+ try { -+ aia.encode(os); -+ -+ System.out.println(Utils.base64encode(os.toByteArray(), true)); -+ } catch (IOException e) { -+ System.out.println(e.toString()); -+ } -+ -+ try { -+ // test serialization -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ ObjectOutputStream oos = new ObjectOutputStream(bos); -+ -+ oos.writeObject(aia); -+ -+ ByteArrayInputStream bis = new ByteArrayInputStream( -+ bos.toByteArray()); -+ ObjectInputStream ois = new ObjectInputStream(bis); -+ AuthInfoAccessExtension clone = (AuthInfoAccessExtension) -+ ois.readObject(); -+ -+ System.out.println(clone); -+ } catch (Exception e) { -+ System.out.println(e.toString()); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/CertInfo.java b/org/mozilla/jss/netscape/security/extensions/CertInfo.java -new file mode 100644 -index 00000000..10ebd40e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/CertInfo.java -@@ -0,0 +1,119 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.IOException; -+import java.math.BigInteger; -+import java.security.NoSuchAlgorithmException; -+import java.security.cert.CertificateException; -+import java.util.Date; -+ -+import org.mozilla.jss.netscape.security.x509.AlgorithmId; -+import org.mozilla.jss.netscape.security.x509.CertificateAlgorithmId; -+import org.mozilla.jss.netscape.security.x509.CertificateIssuerName; -+import org.mozilla.jss.netscape.security.x509.CertificateSerialNumber; -+import org.mozilla.jss.netscape.security.x509.CertificateSubjectName; -+import org.mozilla.jss.netscape.security.x509.CertificateValidity; -+import org.mozilla.jss.netscape.security.x509.CertificateVersion; -+import org.mozilla.jss.netscape.security.x509.X500Name; -+import org.mozilla.jss.netscape.security.x509.X509CertInfo; -+ -+/** -+ * Extends X509CertInfo class so that minimal fields are initialized at -+ * creation time so an object of this type is always serializable. -+ */ -+public class CertInfo extends X509CertInfo { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -2883888348288591989L; -+ public static final CertificateSubjectName SERIALIZE_SUBJECT; -+ public static final CertificateIssuerName SERIALIZE_ISSUER; -+ public static final CertificateValidity SERIALIZE_VALIDITY; -+ public static final CertificateSerialNumber SERIALIZE_SERIALNO; -+ public static final CertificateAlgorithmId SERIALIZE_ALGOR; -+ public static final CertificateVersion FORCE_VERSION_3; -+ -+ static { -+ try { -+ // force version 3 -+ FORCE_VERSION_3 = -+ new CertificateVersion(CertificateVersion.V3); -+ SERIALIZE_SUBJECT = -+ new CertificateSubjectName( -+ new X500Name("cn=uninitialized")); -+ SERIALIZE_ISSUER = -+ new CertificateIssuerName( -+ new X500Name("cn=uninitialized")); -+ SERIALIZE_VALIDITY = -+ new CertificateValidity(new Date(0), new Date(0)); -+ SERIALIZE_SERIALNO = -+ new CertificateSerialNumber(new BigInteger("0")); -+ SERIALIZE_ALGOR = -+ new CertificateAlgorithmId(AlgorithmId.get("MD5withRSA")); -+ } catch (IOException e) { -+ // should never happen. If does, system is hosed. -+ System.out.println("**** Impossible Error encountered ****"); -+ throw new RuntimeException(e.toString()); -+ } catch (NoSuchAlgorithmException e) { -+ // should never happen. If does, system is hosed. -+ System.out.println("**** Impossible Error encountered ****"); -+ throw new RuntimeException(e.toString()); -+ } -+ } -+ -+ /** -+ * Initializes most fields required by der encoding so object will -+ * serialize properly. -+ */ -+ // XXX should write a class to use something else for serialization -+ // but this is faster and done now for the time crunch. -+ public CertInfo() { -+ super(); -+ makeSerializable(this); -+ } -+ -+ public static void makeSerializable(X509CertInfo certinfo) { -+ try { -+ // force version 3. -+ certinfo.set(X509CertInfo.VERSION, FORCE_VERSION_3); -+ -+ if (certinfo.get(X509CertInfo.SERIAL_NUMBER) == null) { -+ certinfo.set(X509CertInfo.SERIAL_NUMBER, SERIALIZE_SERIALNO); -+ } -+ if (certinfo.get(X509CertInfo.ALGORITHM_ID) == null) { -+ certinfo.set(X509CertInfo.ALGORITHM_ID, SERIALIZE_ALGOR); -+ } -+ if (certinfo.get(X509CertInfo.ISSUER) == null) { -+ certinfo.set(X509CertInfo.ISSUER, SERIALIZE_ISSUER); -+ } -+ if (certinfo.get(X509CertInfo.VALIDITY) == null) { -+ certinfo.set(X509CertInfo.VALIDITY, SERIALIZE_VALIDITY); -+ } -+ // set subject name anyway - it'll get overwritten. -+ if (certinfo.get(X509CertInfo.SUBJECT) == null) { -+ certinfo.set(X509CertInfo.SUBJECT, SERIALIZE_SUBJECT); -+ } -+ // key is set later in the request. -+ } // these exceptions shouldn't happen here unless the -+ // whole process is hosed. -+ catch (CertificateException e) { -+ } catch (IOException e) { -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/CertificateRenewalWindowExtension.java b/org/mozilla/jss/netscape/security/extensions/CertificateRenewalWindowExtension.java -new file mode 100644 -index 00000000..470a6737 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/CertificateRenewalWindowExtension.java -@@ -0,0 +1,191 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Date; -+import java.util.Enumeration; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+ -+/** -+ * This represents the CertificateRenewalWindow extension -+ * as defined in draft-thayes-cert-renewal-00 -+ * -+ * CertificateRenewalWindow ::= SEQUENCE { -+ * beginTime GeneralizedTime, -+ * endTime GeneralizedTime OPTIONAL } -+ * -+ * @author thomask -+ * @version $Revision$, $Date$ -+ */ -+public class CertificateRenewalWindowExtension extends Extension -+ implements CertAttrSet { -+ private static final long serialVersionUID = 4470220533545299271L; -+ public static final String NAME = "CertificateRenewalWindow"; -+ public static final int OID[] = { 2, 16, 840, 1, 113730, 1, 15 }; -+ public static final ObjectIdentifier ID = new ObjectIdentifier(OID); -+ -+ private Date mBeginTime = null; -+ private Date mEndTime = null; // optional -+ -+ public CertificateRenewalWindowExtension(boolean critical, Date beginTime, -+ Date endTime) throws IOException { -+ this.extensionId = ID; -+ this.critical = critical; -+ mBeginTime = beginTime; -+ mEndTime = endTime; -+ encodeThis(); -+ } -+ -+ public CertificateRenewalWindowExtension(boolean critical) { -+ this.extensionId = ID; -+ this.critical = critical; -+ this.extensionValue = null; // build this when encodeThis() is called -+ } -+ -+ public CertificateRenewalWindowExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = ID; -+ this.critical = critical.booleanValue(); -+ this.extensionValue = ((byte[]) value).clone(); -+ decodeThis(); -+ } -+ -+ public String getName() { -+ return NAME; -+ } -+ -+ /** -+ * Sets extension attribute. -+ */ -+ public void set(String name, Object obj) throws CertificateException { -+ // NOT USED -+ } -+ -+ /** -+ * Retrieves extension attribute. -+ */ -+ public Object get(String name) throws CertificateException { -+ // NOT USED -+ return null; -+ } -+ -+ /** -+ * Deletes attribute. -+ */ -+ public void delete(String name) throws CertificateException { -+ // NOT USED -+ } -+ -+ /** -+ * Decodes this extension. -+ */ -+ public void decode(InputStream in) throws IOException { -+ // NOT USED -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ // NOT USED -+ return null; -+ } -+ -+ public Date getBeginTime() { -+ return mBeginTime; -+ } -+ -+ public Date getEndTime() { -+ return mEndTime; -+ } -+ -+ public void setBeginTime(Date d) { -+ mBeginTime = d; -+ } -+ -+ public void setEndTime(Date d) { -+ mEndTime = d; -+ } -+ -+ private void decodeThis() throws IOException { -+ DerValue val = new DerValue(this.extensionValue); -+ -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding of CertificateWindow extension"); -+ } -+ while (val.data.available() != 0) { -+ if (mBeginTime == null) { -+ mBeginTime = val.data.getGeneralizedTime(); -+ } else { -+ mEndTime = val.data.getGeneralizedTime(); -+ } -+ } -+ } -+ -+ private void encodeThis() throws IOException { -+ try (DerOutputStream seq = new DerOutputStream(); -+ DerOutputStream tmp = new DerOutputStream()) { -+ -+ tmp.putGeneralizedTime(mBeginTime); -+ if (mEndTime != null) { -+ tmp.putGeneralizedTime(mEndTime); -+ } -+ seq.write(DerValue.tag_Sequence, tmp); -+ this.extensionValue = seq.toByteArray(); -+ } -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Returns a printable representation of the CertificateRenewalWindow. -+ */ -+ public String toString() { -+ String s = super.toString() + "CertificateRenewalWindow [\n"; -+ -+ s += "BeginTime: " + mBeginTime + "\n"; -+ if (mEndTime != null) { -+ s += "EndTime: " + mEndTime; -+ } -+ return (s + "]\n"); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/CertificateScopeEntry.java b/org/mozilla/jss/netscape/security/extensions/CertificateScopeEntry.java -new file mode 100644 -index 00000000..747557b8 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/CertificateScopeEntry.java -@@ -0,0 +1,103 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.x509.GeneralName; -+ -+/** -+ * This represents the CertificateScopeOfUse extension -+ * as defined in draft-thayes-cert-scope-00 -+ * -+ * CertificateScopeEntry ::= SEQUENCE { -+ * name GeneralName, -- pattern, as for NameConstraints -+ * portNumber INTEGER OPTIONAL -+ * } -+ * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry -+ * -+ * @author thomask -+ * @version $Revision$, $Date$ -+ */ -+public class CertificateScopeEntry { -+ private GeneralName mGn = null; -+ private BigInt mPort = null; -+ -+ /** -+ * Constructs scope with der value. -+ */ -+ public CertificateScopeEntry(DerValue val) throws IOException { -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for PolicyQualifierInfo."); -+ } -+ DerValue gn = val.data.getDerValue(); -+ -+ mGn = new GeneralName(gn); -+ if (val.data.available() != 0) { -+ mPort = val.data.getInteger(); -+ } -+ } -+ -+ /** -+ * Constructs scope wit -+ */ -+ public CertificateScopeEntry(GeneralName gn, BigInt port) { -+ mGn = gn; -+ mPort = port; // optional -+ } -+ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ mGn.encode(tmp); -+ if (mPort != null) { -+ tmp.putInteger(mPort); -+ } -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+ -+ /** -+ * Returns a GeneralName -+ */ -+ public GeneralName getGeneralName() { -+ return mGn; -+ } -+ -+ /** -+ * Returns a port -+ */ -+ public BigInt getPort() { -+ return mPort; -+ } -+ -+ /** -+ * Returns a printable representation of the CertificateRenewalWindow. -+ */ -+ public String toString() { -+ String s = super.toString() + "CertificateScopeEntry [\n"; -+ -+ s += "GeneralName: " + mGn; -+ if (mPort != null) { -+ s += "PortNumber: " + mPort; -+ } -+ return (s + "]\n"); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/CertificateScopeOfUseExtension.java b/org/mozilla/jss/netscape/security/extensions/CertificateScopeOfUseExtension.java -new file mode 100644 -index 00000000..649e6ef4 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/CertificateScopeOfUseExtension.java -@@ -0,0 +1,198 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.OIDMap; -+ -+/** -+ * This represents the CertificateScopeOfUse extension -+ * as defined in draft-thayes-cert-scope-00 -+ * -+ * CertificateScopeEntry ::= SEQUENCE { -+ * name GeneralName, -- pattern, as for NameConstraints -+ * portNumber INTEGER OPTIONAL -+ * } -+ * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry -+ * -+ * @author thomask -+ * @version $Revision$, $Date$ -+ */ -+public class CertificateScopeOfUseExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 2143292831971567770L; -+ public static final String NAME = "CertificateScopeOfUse"; -+ public static final int OID[] = { 2, 16, 840, 1, 113730, 1, 17 }; -+ public static final ObjectIdentifier ID = new ObjectIdentifier(OID); -+ -+ private Vector mEntries = null; -+ -+ static { -+ try { -+ OIDMap.addAttribute(CertificateScopeOfUseExtension.class.getName(), -+ ID.toString(), NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ public CertificateScopeOfUseExtension(boolean critical, Vector scopeEntries) -+ throws IOException { -+ this.extensionId = ID; -+ this.critical = critical; -+ this.extensionValue = null; // build this when encodeThis() is called -+ mEntries = scopeEntries; -+ encodeThis(); -+ } -+ -+ public CertificateScopeOfUseExtension(boolean critical) { -+ this.extensionId = ID; -+ this.critical = critical; -+ this.extensionValue = null; // build this when encodeThis() is called -+ } -+ -+ public CertificateScopeOfUseExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = ID; -+ this.critical = critical.booleanValue(); -+ this.extensionValue = ((byte[]) value).clone(); -+ decodeThis(); -+ } -+ -+ public String getName() { -+ return NAME; -+ } -+ -+ public Vector getCertificateScopeEntries() { -+ return mEntries; -+ } -+ -+ /** -+ * Sets extension attribute. -+ */ -+ public void set(String name, Object obj) throws CertificateException { -+ // NOT USED -+ } -+ -+ /** -+ * Retrieves extension attribute. -+ */ -+ public Object get(String name) throws CertificateException { -+ // NOT USED -+ return null; -+ } -+ -+ /** -+ * Deletes attribute. -+ */ -+ public void delete(String name) throws CertificateException { -+ // NOT USED -+ } -+ -+ /** -+ * Decodes this extension. -+ */ -+ public void decode(InputStream in) throws IOException { -+ // NOT USED -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ // NOT USED -+ return null; -+ } -+ -+ private void decodeThis() throws IOException { -+ DerValue val = new DerValue(this.extensionValue); -+ -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding of CertificateWindow extension"); -+ } -+ mEntries = new Vector(); -+ while (val.data.available() != 0) { -+ mEntries.addElement(new CertificateScopeEntry( -+ val.data.getDerValue())); -+ } -+ } -+ -+ private void encodeThis() throws IOException { -+ try (DerOutputStream seq = new DerOutputStream(); -+ DerOutputStream tmp = new DerOutputStream()) { -+ -+ if (mEntries == null) -+ throw new IOException("Invalid Scope Entries"); -+ -+ for (int i = 0; i < mEntries.size(); i++) { -+ CertificateScopeEntry se = mEntries.elementAt(i); -+ -+ se.encode(tmp); -+ } -+ -+ seq.write(DerValue.tag_Sequence, tmp); -+ this.extensionValue = seq.toByteArray(); -+ } -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Returns a printable representation of the CertificateRenewalWindow. -+ */ -+ public String toString() { -+ StringBuffer s = new StringBuffer(super.toString() + "CertificateUseOfScope [\n"); -+ -+ if (mEntries != null) { -+ for (int i = 0; i < mEntries.size(); i++) { -+ CertificateScopeEntry se = mEntries.elementAt(i); -+ -+ s.append(se.toString()); -+ } -+ } -+ return (s.toString() + "]\n"); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/ExtendedKeyUsageExtension.java b/org/mozilla/jss/netscape/security/extensions/ExtendedKeyUsageExtension.java -new file mode 100644 -index 00000000..d52233b0 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/ExtendedKeyUsageExtension.java -@@ -0,0 +1,228 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.OIDMap; -+ -+/** -+ * This represents the extended key usage extension. -+ */ -+public class ExtendedKeyUsageExtension extends Extension implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 765403075764697489L; -+ public static final String OID = "2.5.29.37"; -+ public static final String NAME = OIDMap.EXT_KEY_USAGE_NAME; -+ public static final String OID_OCSPSigning = "1.3.6.1.5.5.7.3.9"; -+ public static final String OID_CODESigning = "1.3.6.1.5.5.7.3.3"; -+ -+ public static final int OID_OCSP_SIGNING_STR[] = -+ { 1, 3, 6, 1, 5, 5, 7, 3, 9 }; -+ public static final ObjectIdentifier OID_OCSP_SIGNING = new -+ ObjectIdentifier(OID_OCSP_SIGNING_STR); -+ -+ public static final int OID_CODE_SIGNING_STR[] = -+ { 1, 3, 6, 1, 5, 5, 7, 3, 3 }; -+ public static final ObjectIdentifier OID_CODE_SIGNING = new -+ ObjectIdentifier(OID_OCSP_SIGNING_STR); -+ -+ private Vector oidSet = null; -+ private byte mCached[] = null; -+ -+ static { -+ try { -+ OIDMap.addAttribute(ExtendedKeyUsageExtension.class.getName(), -+ OID, ExtendedKeyUsageExtension.NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ public ExtendedKeyUsageExtension() throws IOException { -+ this(false, null); -+ } -+ -+ public ExtendedKeyUsageExtension(boolean crit, Vector oids) throws IOException { -+ try { -+ extensionId = ObjectIdentifier.getObjectIdentifier(OID); -+ } catch (IOException e) { -+ // never here -+ } -+ critical = crit; -+ if (oids != null) { -+ oidSet = new Vector(oids); -+ } else { -+ oidSet = new Vector(); -+ } -+ encodeExtValue(); -+ } -+ -+ public ExtendedKeyUsageExtension(Boolean crit, Object byteVal) -+ throws IOException { -+ extensionId = ObjectIdentifier.getObjectIdentifier(OID); -+ critical = crit.booleanValue(); -+ extensionValue = ((byte[]) byteVal).clone(); -+ decodeThis(); -+ } -+ -+ public void setCritical(boolean newValue) { -+ if (critical != newValue) { -+ critical = newValue; -+ mCached = null; -+ } -+ } -+ -+ public Enumeration getOIDs() { -+ if (oidSet == null) -+ return null; -+ return oidSet.elements(); -+ } -+ -+ public void deleteAllOIDs() { -+ if (oidSet == null) -+ return; -+ oidSet.clear(); -+ } -+ -+ public void addOID(ObjectIdentifier oid) { -+ if (oidSet == null) { -+ oidSet = new Vector(); -+ } -+ -+ if (oidSet.contains(oid)) -+ return; -+ oidSet.addElement(oid); -+ mCached = null; -+ } -+ -+ public void encode(DerOutputStream out) throws IOException { -+ if (mCached == null) { -+ encodeExtValue(); -+ super.encode(out); -+ mCached = out.toByteArray(); -+ } -+ } -+ -+ @Override -+ public String toString() { -+ String presentation = "oid=" + ExtendedKeyUsageExtension.OID + " "; -+ -+ if (critical) { -+ presentation += "critical=true"; -+ } -+ if (extensionValue != null) { -+ StringBuffer extByteValue = new StringBuffer(" val="); -+ for (int i = 0; i < extensionValue.length; i++) { -+ extByteValue.append(extensionValue[i] + " "); -+ } -+ presentation += extByteValue.toString(); -+ } -+ return presentation; -+ } -+ -+ public void decode(InputStream in) -+ throws CertificateException, IOException { -+ } -+ -+ public void encode(OutputStream out) -+ throws CertificateException, IOException { -+ if (mCached == null) { -+ DerOutputStream temp = new DerOutputStream(); -+ -+ encode(temp); -+ } -+ out.write(mCached); -+ } -+ -+ public void set(String name, Object obj) -+ throws CertificateException, IOException { -+ // NOT USED -+ } -+ -+ public Object get(String name) throws CertificateException, IOException { -+ // NOT USED -+ return null; -+ } -+ -+ public Enumeration getAttributeNames() { -+ return null; -+ } -+ -+ public String getName() { -+ return NAME; -+ } -+ -+ public void delete(String name) -+ throws CertificateException, IOException { -+ // NOT USED -+ } -+ -+ private void decodeThis() throws IOException { -+ DerValue val = new DerValue(this.extensionValue); -+ -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding of AuthInfoAccess extension"); -+ } -+ if (oidSet == null) -+ oidSet = new Vector(); -+ while (val.data.available() != 0) { -+ DerValue oidVal = val.data.getDerValue(); -+ -+ oidSet.addElement(oidVal.getOID()); -+ } -+ } -+ -+ private void encodeExtValue() throws IOException { -+ DerOutputStream out = new DerOutputStream(); -+ DerOutputStream temp = new DerOutputStream(); -+ -+ if (!oidSet.isEmpty()) { -+ Enumeration oidList = oidSet.elements(); -+ -+ try { -+ while (oidList.hasMoreElements()) { -+ temp.putOID(oidList.nextElement()); -+ } -+ } catch (IOException ex) { -+ ex.printStackTrace(); -+ } -+ } -+ -+ try { -+ out.write(DerValue.tag_Sequence, temp); -+ } catch (IOException ex) { -+ } finally { -+ out.close(); -+ } -+ -+ extensionValue = out.toByteArray(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/GenericASN1Extension.java b/org/mozilla/jss/netscape/security/extensions/GenericASN1Extension.java -new file mode 100644 -index 00000000..3fc58bac ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/GenericASN1Extension.java -@@ -0,0 +1,461 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.FileInputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.security.cert.CertificateException; -+import java.text.DateFormat; -+import java.text.ParseException; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.StringTokenizer; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.OIDMap; -+ -+/** -+ * Represent the AsnInteger Extension. -+ */ -+public class GenericASN1Extension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 8047548816784949009L; -+ -+ protected static final int MAX_ATTR = 10; -+ -+ protected static final String PROP_CRITICAL = -+ "critical"; -+ protected static final String PROP_NAME = -+ "name"; -+ protected static final String PROP_OID = -+ "oid"; -+ protected static final String PROP_PATTERN = -+ "pattern"; -+ protected static final String PROP_ATTRIBUTE = -+ "attribute"; -+ protected static final String PROP_TYPE = -+ "type"; -+ protected static final String PROP_SOURCE = -+ "source"; -+ protected static final String PROP_VALUE = -+ "value"; -+ protected static final String PROP_PREDICATE = -+ "predicate"; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ private String name; -+ public String OID = null; -+ public static Hashtable mConfig = null; -+ public String pattern = null; -+ private int index = 0; -+ -+ // Encode this value -+ private void encodeThis() -+ throws IOException, ParseException { -+ this.extensionValue = encodePattern(); -+ } -+ -+ // Encode pattern -+ private byte[] encodePattern() -+ throws IOException, ParseException { -+ DerOutputStream tmp = new DerOutputStream(); -+ String type = null; -+ String value = null; -+ String source = null; -+ while (index < pattern.length()) { -+ char ch = pattern.charAt(index); -+ switch (ch) { -+ case '{': -+ index++; -+ byte[] buff = encodePattern(); -+ tmp.putDerValue(new DerValue(buff)); -+ break; -+ case '}': -+ try (DerOutputStream os = new DerOutputStream()) { -+ os.write(DerValue.tag_Sequence, tmp); -+ return os.toByteArray(); -+ } -+ default: -+ type = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_TYPE); -+ if (type.equalsIgnoreCase("integer")) { -+ int num = Integer.parseInt(mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE)); -+ PutInteger(tmp, num); -+ } else if (type.equalsIgnoreCase("ia5string")) { -+ source = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE); -+ value = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE); -+ if (source.equalsIgnoreCase("file")) -+ PutIA5String(tmp, getFromFile(value)); -+ else -+ PutIA5String(tmp, value); -+ } else if (type.equalsIgnoreCase("octetstring")) { -+ source = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE); -+ value = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE); -+ // It should be colon seperated ASCII Hexdecimal String -+ if (source.equalsIgnoreCase("file")) -+ PutOctetString(tmp, getFromFile(value)); -+ else -+ PutOctetString(tmp, value); -+ } else if (type.equalsIgnoreCase("bmpstring")) { -+ source = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE); -+ value = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE); -+ if (source.equalsIgnoreCase("file")) -+ PutBMPString(tmp, getFromFile(value)); -+ else -+ PutBMPString(tmp, value); -+ } else if (type.equalsIgnoreCase("printablestring")) { -+ source = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE); -+ value = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE); -+ if (source.equalsIgnoreCase("file")) -+ PutPrintableString(tmp, getFromFile(value)); -+ else -+ PutPrintableString(tmp, value); -+ } else if (type.equalsIgnoreCase("visiblestring")) { -+ source = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE); -+ value = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE); -+ if (source.equalsIgnoreCase("file")) -+ PutVisibleString(tmp, getFromFile(value)); -+ else -+ PutVisibleString(tmp, value); -+ } else if (type.equalsIgnoreCase("utctime")) { -+ value = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE); -+ PutUTCtime(tmp, value); -+ } else if (type.equalsIgnoreCase("oid")) { -+ value = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE); -+ PutOID(tmp, value); -+ } else if (type.equalsIgnoreCase("boolean")) { -+ boolean bool = false; -+ String b = mConfig.get(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE); -+ if (b.equalsIgnoreCase("true")) -+ bool = true; -+ else -+ bool = false; -+ PutBoolean(tmp, bool); -+ } else if (type.equalsIgnoreCase("null")) { -+ tmp.putNull(); -+ } else { -+ throw new ParseException("Unknown Attribute Type", 0); -+ } -+ } -+ index++; -+ } -+ -+ return tmp.toByteArray(); -+ } -+ -+ /** -+ * Create a GenericASN1Extension with the value and oid. -+ * The criticality is set to false. -+ * -+ * @param the values to be set for the extension. -+ */ -+ public GenericASN1Extension(String name, String oid, String pattern, boolean critical, -+ Hashtable config) -+ throws IOException, ParseException { -+ ObjectIdentifier tmpid = new ObjectIdentifier(oid); -+ this.name = name; -+ OID = oid; -+ mConfig = config; -+ this.pattern = pattern; -+ -+ try { -+ if (OIDMap.getName(tmpid) == null) -+ OIDMap.addAttribute("org.mozilla.jss.netscape.security.x509.GenericASN1Extension", oid, name); -+ } catch (CertificateException e) { -+ } -+ -+ this.extensionId = tmpid; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a GenericASN1Extension with the value and oid. -+ * The criticality is set to false. -+ * -+ * @param the values to be set for the extension. -+ */ -+ public GenericASN1Extension(Hashtable config) -+ throws IOException, ParseException { -+ mConfig = config; -+ ObjectIdentifier tmpid = new ObjectIdentifier(mConfig.get(PROP_OID)); -+ name = mConfig.get(PROP_NAME); -+ OID = mConfig.get(PROP_OID); -+ pattern = mConfig.get(PROP_PATTERN); -+ -+ try { -+ if (OIDMap.getName(tmpid) == null) -+ OIDMap.addAttribute("GenericASN1Extension", OID, name); -+ } catch (CertificateException e) { -+ } -+ -+ this.extensionId = tmpid; -+ this.critical = false; -+ String b = mConfig.get(PROP_CRITICAL); -+ if (b.equalsIgnoreCase("true")) -+ this.critical = true; -+ else -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public GenericASN1Extension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = new ObjectIdentifier(OID); -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ return null; -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Returns a printable representation of the GenericASN1Extension. -+ */ -+ @Override -+ public String toString() { -+ return (null); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) -+ throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ try { -+ if (this.extensionValue == null) { -+ this.extensionId = new ObjectIdentifier(OID); -+ this.critical = true; -+ encodeThis(); -+ } -+ } catch (ParseException e) { -+ } -+ -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return name; -+ } -+ -+ /** -+ * Set the name of this attribute. -+ */ -+ public void setName(String name) { -+ this.name = name; -+ } -+ -+ /** -+ * Return the OID of this attribute. -+ */ -+ public String getOID() { -+ return OID; -+ } -+ -+ /** -+ * Set the OID of this attribute. -+ */ -+ public void setOID(String oid) { -+ OID = oid; -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement("octet"); -+ -+ return (elements.elements()); -+ } -+ -+ private void PutInteger(DerOutputStream os, int number) -+ throws IOException, ParseException { -+ os.putInteger(new BigInt(number)); -+ return; -+ } -+ -+ private void PutIA5String(DerOutputStream os, String value) -+ throws IOException, ParseException { -+ os.putIA5String(value); -+ return; -+ } -+ -+ private void PutOctetString(DerOutputStream os, String value) -+ throws IOException, ParseException { -+ StringTokenizer token = new StringTokenizer(value, ":"); -+ byte[] octets = new byte[token.countTokens()]; -+ for (int i = 0; token.hasMoreElements(); i++) { -+ String num = (String) token.nextElement(); -+ octets[i] = (byte) Integer.parseInt(num, 16); -+ } -+ -+ os.putOctetString(octets); -+ return; -+ } -+ -+ private void PutBMPString(DerOutputStream os, String value) -+ throws IOException, ParseException { -+ os.putBMPString(value); -+ return; -+ } -+ -+ private void PutPrintableString(DerOutputStream os, String value) -+ throws IOException, ParseException { -+ os.putPrintableString(value); -+ return; -+ } -+ -+ private void PutVisibleString(DerOutputStream os, String value) -+ throws IOException, ParseException { -+ os.putVisibleString(value); -+ return; -+ } -+ -+ private void PutUTCtime(DerOutputStream os, String value) -+ throws IOException, ParseException { -+ DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); -+ os.putUTCTime(df.parse(value)); -+ return; -+ } -+ -+ private void PutOID(DerOutputStream os, String value) -+ throws IOException, ParseException { -+ os.putOID(new ObjectIdentifier(value)); -+ return; -+ } -+ -+ private void PutBoolean(DerOutputStream os, boolean value) -+ throws IOException, ParseException { -+ os.putBoolean(value); -+ return; -+ } -+ -+ private String getFromFile(String fname) throws IOException { -+ String s = null; -+ byte[] buff = null; -+ int i = 0; -+ int j = 0; -+ if ((fname == null) || (fname.equals(""))) { -+ throw new IOException("File name is not provided."); -+ } -+ -+ FileInputStream fis = null; -+ try { -+ fis = new FileInputStream(fname); -+ int n = 0; -+ while ((n = fis.available()) > 0) { -+ buff = new byte[n]; -+ int result = fis.read(buff); -+ if (result == -1) -+ break; -+ s = new String(buff); -+ } -+ } finally { -+ if (fis != null) { -+ fis.close(); -+ } -+ } -+ -+ if (s == null) { -+ return ""; -+ } -+ -+ for (i = 0, j = 0; j < s.length(); j++) { -+ int ch = s.charAt(j); -+ if (ch == 10 || ch == 13 || ch == 9) -+ continue; -+ i++; -+ } -+ buff = new byte[i]; -+ for (i = 0, j = 0; j < s.length(); j++) { -+ int ch = s.charAt(j); -+ if (ch == 10 || ch == 13 || ch == 9) -+ continue; -+ buff[i++] = (byte) ch; -+ } -+ s = new String(buff); -+ -+ return s; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/InhibitAnyPolicyExtension.java b/org/mozilla/jss/netscape/security/extensions/InhibitAnyPolicyExtension.java -new file mode 100644 -index 00000000..a658f724 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/InhibitAnyPolicyExtension.java -@@ -0,0 +1,183 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.OIDMap; -+ -+/** -+ * RFC3280: -+ * -+ * id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } -+ * -+ * InhibitAnyPolicy ::= SkipCerts -+ * -+ * SkipCerts ::= INTEGER (0..MAX) -+ */ -+public class InhibitAnyPolicyExtension -+ extends Extension implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -8963439897419343166L; -+ public static final String OID = "2.5.29.54"; -+ public static final String NAME = OIDMap.EXT_INHIBIT_ANY_POLICY_NAME; -+ -+ private BigInt mSkipCerts = new BigInt(-1); -+ -+ static { -+ try { -+ OIDMap.addAttribute(InhibitAnyPolicyExtension.class.getName(), -+ OID, NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ public InhibitAnyPolicyExtension() throws IOException { -+ this(false, null); -+ } -+ -+ public InhibitAnyPolicyExtension(boolean crit, BigInt skipCerts) throws IOException { -+ try { -+ extensionId = ObjectIdentifier.getObjectIdentifier(OID); -+ } catch (IOException e) { -+ // never here -+ } -+ critical = crit; -+ mSkipCerts = skipCerts; -+ encodeExtValue(); -+ } -+ -+ public InhibitAnyPolicyExtension(Boolean crit, Object value) -+ throws IOException { -+ extensionId = ObjectIdentifier.getObjectIdentifier(OID); -+ critical = crit.booleanValue(); -+ //extensionValue = (byte[]) ((byte[]) byteVal).clone(); -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ -+ extensionValue = extValue; -+ decodeThis(); -+ } -+ -+ public void setCritical(boolean newValue) { -+ if (critical != newValue) { -+ critical = newValue; -+ } -+ } -+ -+ public BigInt getSkipCerts() { -+ return mSkipCerts; -+ } -+ -+ @Override -+ public String toString() { -+ String presentation = "ObjectId: " + OID + " "; -+ -+ if (critical) { -+ presentation += "Criticality=true"; -+ } else { -+ presentation += "Criticality=false"; -+ } -+ if (extensionValue != null) { -+ String extByteValue = " skipCerts=" + mSkipCerts; -+ -+ presentation += extByteValue; -+ } -+ return presentation; -+ } -+ -+ public void decode(InputStream in) -+ throws CertificateException, IOException { -+ } -+ -+ public void set(String name, Object obj) -+ throws CertificateException, IOException { -+ // NOT USED -+ } -+ -+ public Object get(String name) throws CertificateException, IOException { -+ // NOT USED -+ return null; -+ } -+ -+ public Enumeration getAttributeNames() { -+ return null; -+ } -+ -+ public String getName() { -+ return NAME; -+ } -+ -+ public void delete(String name) -+ throws CertificateException, IOException { -+ // NOT USED -+ } -+ -+ private void decodeThis() throws IOException { -+ DerValue val = new DerValue(this.extensionValue); -+ -+ mSkipCerts = val.getInteger(); -+ } -+ -+ public void encode(OutputStream out) throws IOException { -+ try (DerOutputStream os = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ try { -+ extensionId = ObjectIdentifier.getObjectIdentifier(OID); -+ } catch (IOException e) { -+ // never here -+ } -+ os.putInteger(mSkipCerts); -+ this.extensionValue = os.toByteArray(); -+ } -+ -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ } -+ -+ private void encodeExtValue() throws IOException { -+ DerOutputStream out = new DerOutputStream(); -+ try { -+ out.putInteger(mSkipCerts); -+ } catch (IOException e) { -+ } finally { -+ out.close(); -+ } -+ extensionValue = out.toByteArray(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/KerberosName.java b/org/mozilla/jss/netscape/security/extensions/KerberosName.java -new file mode 100644 -index 00000000..cc6e1192 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/KerberosName.java -@@ -0,0 +1,136 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.ByteArrayOutputStream; -+import java.io.FileOutputStream; -+import java.io.IOException; -+import java.io.OutputStream; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * This represents a KerberosName as defined in -+ * RFC 1510. -+ * -+ * KerberosName ::= SEQUENCE { -+ * realm [0] Realm, -+ * principalName [1] CertPrincipalName -- defined above -+ * } -+ * -+ * CertPrincipalName ::= SEQUENCE { -+ * name-type[0] INTEGER, -+ * name-string[1] SEQUENCE OF UTF8String -+ * } -+ * -+ * @author thomask -+ * @version $Revision$, $Date$ -+ */ -+public class KerberosName { -+ -+ public static final int OID[] = { 1, 3, 6, 1, 5, 2, 2 }; -+ public static final ObjectIdentifier KRB5_PRINCIPAL_NAME = new -+ ObjectIdentifier(OID); -+ -+ private String m_realm = null; -+ private int m_name_type = 0; -+ private Vector m_name_strings = null; -+ -+ public KerberosName(String realm, int name_type, Vector name_strings) { -+ m_realm = realm; -+ m_name_type = name_type; -+ m_name_strings = name_strings; -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ -+ try (DerOutputStream seq = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ DerOutputStream realm = new DerOutputStream(); -+ realm.putGeneralString(m_realm); -+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, (byte) 0), realm); -+ -+ DerOutputStream seq1 = new DerOutputStream(); -+ DerOutputStream tmp1 = new DerOutputStream(); -+ DerOutputStream name_type = new DerOutputStream(); -+ name_type.putInteger(new BigInt(m_name_type)); -+ tmp1.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, (byte) 0), name_type); -+ -+ DerOutputStream name_strings = new DerOutputStream(); -+ DerOutputStream name_string = new DerOutputStream(); -+ for (int i = 0; i < m_name_strings.size(); i++) { -+ name_string.putGeneralString(m_name_strings.elementAt(i)); -+ } -+ name_strings.write(DerValue.tag_SequenceOf, name_string); -+ tmp1.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, (byte) 1), name_strings); -+ seq1.write(DerValue.tag_Sequence, tmp1); -+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, (byte) 1), seq1); -+ -+ seq.write(DerValue.tag_Sequence, tmp); -+ out.write(seq.toByteArray()); -+ } -+ } -+ -+ public byte[] toByteArray() throws IOException { -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ encode(bos); -+ return bos.toByteArray(); -+ } -+ -+ public String toString() { -+ String strings = null; -+ for (int i = 0; i < m_name_strings.size(); i++) { -+ if (strings == null) { -+ strings = m_name_strings.elementAt(i); -+ } else { -+ strings += ","; -+ strings += m_name_strings.elementAt(i); -+ } -+ } -+ return "Realm: " + m_realm + " Name Type: " + m_name_type + " Name String(s):" + strings; -+ } -+ -+ public static void main(String[] argv) { -+ Vector strings = new Vector(); -+ strings.addElement("name"); -+ KerberosName k = new KerberosName("realm", 0, strings); -+ -+ System.out.println(k.toString()); -+ try { -+ FileOutputStream os = new FileOutputStream("/tmp/out.der"); -+ k.encode(os); -+ os.close(); -+ } catch (Exception e) { -+ System.out.println(e.toString()); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/Makefile b/org/mozilla/jss/netscape/security/extensions/Makefile -new file mode 100644 -index 00000000..8fd7054b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/Makefile -@@ -0,0 +1,45 @@ -+#! gmake -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+####################################################################### -+# (1) Include initial platform-independent assignments (MANDATORY). # -+####################################################################### -+ -+include manifest.mn -+ -+####################################################################### -+# (2) Include "global" configuration information. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/config.mk -+ -+####################################################################### -+# (3) Include "component" configuration information. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (4) Include "local" platform-dependent assignments (OPTIONAL). # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (5) Execute "global" rules. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/rules.mk -+ -+####################################################################### -+# (6) Execute "component" rules. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -diff --git a/org/mozilla/jss/netscape/security/extensions/NSCertTypeExtension.java b/org/mozilla/jss/netscape/security/extensions/NSCertTypeExtension.java -new file mode 100644 -index 00000000..bd8b3fd5 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/NSCertTypeExtension.java -@@ -0,0 +1,382 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BitArray; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+ -+/** -+ * NSCertTypeExtension -+ * Represents Netscape Certificate Type Extension -+ * -+ *

-+ * This deprecated extension, if present, defines both the purpose (e.g., encipherment, signature, certificate signing) -+ * and the application (e.g., SSL, S/Mime or Object Signing of the key contained in the certificate. -+ * -+ * @author galperin -+ * @version $Revision$, $Date$ -+ */ -+public class NSCertTypeExtension extends Extension implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 1856407688086284397L; -+ -+ // The object identifiers -+ private static final int CertType_data[] = { 2, 16, 840, 1, 113730, 1, 1 }; -+ -+ /** -+ * Identifies the particular public key used to sign the certificate. -+ */ -+ public static final ObjectIdentifier CertType_Id = new -+ ObjectIdentifier(CertType_data); -+ -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "NSCertType"; -+ public static final String SSL_CLIENT = "ssl_client"; -+ public static final String SSL_SERVER = "ssl_server"; -+ public static final String EMAIL = "email"; -+ public static final String OBJECT_SIGNING = "object_signing"; -+ public static final String SSL_CA = "ssl_ca"; -+ public static final String EMAIL_CA = "email_ca"; -+ public static final String OBJECT_SIGNING_CA = "object_signing_ca"; -+ -+ /** -+ * Attribute names. -+ */ -+ public static final int SSL_CLIENT_BIT = 0; -+ public static final int SSL_SERVER_BIT = 1; -+ public static final int EMAIL_BIT = 2; -+ public static final int OBJECT_SIGNING_BIT = 3; -+ // 4 is reserved. -+ public static final int SSL_CA_BIT = 5; -+ public static final int EMAIL_CA_BIT = 6; -+ public static final int OBJECT_SIGNING_CA_BIT = 7; -+ -+ public static final int NBITS = 8; -+ -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions.NSCertType"; -+ -+ // Private data members -+ private byte[] mBitString; -+ -+ private static class MapEntry { -+ String mName; -+ int mPosition; -+ -+ MapEntry(String name, int position) { -+ mName = name; -+ mPosition = position; -+ } -+ } -+ -+ private static MapEntry[] mMapData = -+ { -+ new MapEntry(SSL_CLIENT, 0), -+ new MapEntry(SSL_SERVER, 1), -+ new MapEntry(EMAIL, 2), -+ new MapEntry(OBJECT_SIGNING, 3), -+ // note that bit 4 is reserved -+ new MapEntry(SSL_CA, 5), -+ new MapEntry(EMAIL_CA, 6), -+ new MapEntry(OBJECT_SIGNING_CA, 7), -+ }; -+ -+ private static Vector mAttributeNames = new Vector(); -+ -+ static { -+ for (int i = 0; i < mMapData.length; ++i) { -+ mAttributeNames.addElement(mMapData[i].mName); -+ } -+ } -+ -+ private static int getPosition(String name) throws CertificateException { -+ for (int i = 0; i < mMapData.length; ++i) { -+ if (name.equalsIgnoreCase(mMapData[i].mName)) -+ return mMapData[i].mPosition; -+ } -+ throw new CertificateException("Attribute name [" + name -+ + "] not recognized by" -+ + " CertAttrSet:NSCertType."); -+ } -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ try (DerOutputStream os = new DerOutputStream()) { -+ -+ os.putUnalignedBitString(mBitString); -+ this.extensionValue = os.toByteArray(); -+ } -+ } -+ -+ /** -+ * Check if bit is set. -+ * -+ * @param position the position in the bit string to check. -+ */ -+ public boolean isSet(int position) { -+ int index = position / 8; -+ byte pos = (byte) (1 << (7 - (position % 8))); -+ -+ if (mBitString.length <= index) -+ return false; -+ return ((mBitString[index] & pos) != 0); -+ } -+ -+ /** -+ * Set the bit at the specified position. -+ */ -+ public void set(int position, boolean val) { -+ int index = position / 8; -+ byte pos = (byte) (1 << (7 - (position % 8))); -+ -+ if (index >= mBitString.length) { -+ byte[] tmp = new byte[index + 1]; -+ -+ System.arraycopy(mBitString, 0, tmp, 0, mBitString.length); -+ mBitString = tmp; -+ } -+ if (val) { -+ mBitString[index] |= pos; -+ } else { -+ mBitString[index] &= ~pos; -+ } -+ } -+ -+ /** -+ * Create NSCertTypeExtension from boolean array. -+ * The criticality is set to false. -+ */ -+ public NSCertTypeExtension(boolean critical, boolean[] bits) { -+ this.extensionId = CertType_Id; -+ this.critical = critical; -+ this.mBitString = new byte[0]; -+ -+ for (int i = 0; i < bits.length && i < 8; i++) { -+ set(i, bits[i]); -+ } -+ } -+ -+ public NSCertTypeExtension(boolean[] bits) { -+ this.extensionId = CertType_Id; -+ this.critical = false; -+ this.mBitString = new byte[0]; -+ -+ for (int i = 0; i < bits.length && i < 8; i++) { -+ set(i, bits[i]); -+ } -+ } -+ -+ /** -+ * Create a NSCertTypeExtension with the passed bit settings. -+ * The criticality is set to false. -+ * -+ * @param bitString the bits to be set for the extension. -+ */ -+ public NSCertTypeExtension(boolean critical, byte[] bitString) throws IOException { -+ this.mBitString = bitString; -+ this.extensionId = CertType_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ public NSCertTypeExtension(byte[] bitString) throws IOException { -+ this.mBitString = bitString; -+ this.extensionId = CertType_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public NSCertTypeExtension(Boolean critical, Object value) -+ throws IOException { -+ -+ /** -+ * Debug.trace("NSCertTypeExtension"); -+ * this.mBitString = new byte[1]; -+ * this.mBitString[0] = (byte)0x00; -+ * return; -+ **/ -+ -+ this.extensionId = CertType_Id; -+ this.critical = critical.booleanValue(); -+ byte[] extValue = ((byte[]) value).clone(); -+ -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ BitArray bitArray = val.getUnalignedBitString(); -+ if (bitArray == null) { -+ throw new IOException("Invalid Encoded DER Value"); -+ } -+ this.mBitString = bitArray.toByteArray(); -+ } -+ -+ /** -+ * Create a default key usage. -+ */ -+ public NSCertTypeExtension() { -+ this.extensionId = CertType_Id; -+ this.critical = false; -+ this.mBitString = new byte[0]; -+ try { -+ encodeThis(); -+ } catch (Exception e) { -+ } -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws CertificateException { -+ if (!(obj instanceof Boolean)) { -+ throw new CertificateException("Attribute must be of type Boolean."); -+ } -+ boolean val = ((Boolean) obj).booleanValue(); -+ -+ set(getPosition(name), val); -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws CertificateException { -+ return Boolean.valueOf(isSet(getPosition(name))); -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws CertificateException { -+ set(getPosition(name), false); -+ } -+ -+ /** -+ * Returns a printable representation of the NSCertType. -+ */ -+ public String toString() { -+ String s = super.toString() + "NSCertType [\n"; -+ -+ try { -+ -+ if (isSet(getPosition(SSL_CLIENT))) { -+ s += " SSL client"; -+ } -+ if (isSet(getPosition(SSL_SERVER))) { -+ s += " SSL server"; -+ } -+ -+ if (isSet(getPosition(EMAIL))) { -+ s += " Email"; -+ } -+ -+ if (isSet(getPosition(OBJECT_SIGNING))) { -+ s += " Object Signing"; -+ } -+ -+ if (isSet(getPosition(SSL_CA))) { -+ s += " SSL CA"; -+ } -+ -+ if (isSet(getPosition(EMAIL_CA))) { -+ s += " Email CA"; -+ } -+ -+ if (isSet(getPosition(OBJECT_SIGNING_CA))) { -+ s += " Object Signing CA"; -+ } -+ -+ } catch (Exception e) { -+ // this is reached only if there is a bug -+ throw new IllegalArgumentException(e.getMessage()); -+ } -+ -+ s += "]\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ encodeThis(); -+ if (this.extensionValue == null) { -+ this.extensionId = CertType_Id; -+ this.critical = true; -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ return mAttributeNames.elements(); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ public static void main(String[] argv) { -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/OCSPNoCheckExtension.java b/org/mozilla/jss/netscape/security/extensions/OCSPNoCheckExtension.java -new file mode 100644 -index 00000000..1829f5d1 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/OCSPNoCheckExtension.java -@@ -0,0 +1,155 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.OIDMap; -+ -+/** -+ * This represents the OCSPNoCheck extension. -+ */ -+public class OCSPNoCheckExtension extends Extension implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -4692759557964594790L; -+ public static final String OID = "1.3.6.1.5.5.7.48.1.5"; -+ public static final String NAME = "OCSPNoCheckExtension"; -+ -+ private byte mCached[] = null; -+ -+ static { -+ try { -+ OIDMap.addAttribute(OCSPNoCheckExtension.class.getName(), -+ OID, NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ public OCSPNoCheckExtension() throws IOException { -+ this(Boolean.FALSE); -+ } -+ -+ public OCSPNoCheckExtension(Boolean crit) throws IOException { -+ try { -+ extensionId = ObjectIdentifier.getObjectIdentifier(OCSPNoCheckExtension.OID); -+ } catch (IOException e) { -+ // never here -+ } -+ critical = crit.booleanValue(); -+ DerOutputStream tmpD = new DerOutputStream(); -+ -+ try { -+ tmpD.putNull(); -+ } catch (IOException ex) { -+ } finally { -+ tmpD.close(); -+ } -+ extensionValue = tmpD.toByteArray(); -+ } -+ -+ public OCSPNoCheckExtension(Boolean crit, Object byteVal) { -+ try { -+ extensionId = ObjectIdentifier.getObjectIdentifier(OCSPNoCheckExtension.OID); -+ } catch (IOException e) { -+ // never here -+ } -+ critical = crit.booleanValue(); -+ extensionValue = ((byte[]) byteVal).clone(); -+ } -+ -+ public void setCritical(boolean newValue) { -+ if (critical != newValue) { -+ critical = newValue; -+ mCached = null; -+ } -+ } -+ -+ public void encode(DerOutputStream out) throws IOException { -+ if (mCached == null) { -+ super.encode(out); -+ mCached = out.toByteArray(); -+ } -+ } -+ -+ @Override -+ public String toString() { -+ String presentation = "oid=" + OID + " "; -+ -+ if (critical) { -+ presentation += "critical=true"; -+ } -+ if (extensionValue != null) { -+ StringBuffer extByteValue = new StringBuffer(" val="); -+ for (int i = 0; i < extensionValue.length; i++) { -+ extByteValue.append(extensionValue[i] + " "); -+ } -+ presentation += extByteValue.toString(); -+ } -+ return presentation; -+ } -+ -+ public void decode(InputStream in) -+ throws CertificateException, IOException { -+ // NOT USED -+ } -+ -+ public void encode(OutputStream out) -+ throws CertificateException, IOException { -+ if (mCached == null) { -+ DerOutputStream temp = new DerOutputStream(); -+ -+ encode(temp); -+ } -+ out.write(mCached); -+ } -+ -+ public void set(String name, Object obj) -+ throws CertificateException, IOException { -+ // NOT USED -+ } -+ -+ public Object get(String name) throws CertificateException, IOException { -+ // NOT USED -+ return null; -+ } -+ -+ public Enumeration getAttributeNames() { -+ // NOT USED -+ return null; -+ } -+ -+ public String getName() { -+ return NAME; -+ } -+ -+ public void delete(String name) -+ throws CertificateException, IOException { -+ // NOT USED -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/PresenceServerExtension.java b/org/mozilla/jss/netscape/security/extensions/PresenceServerExtension.java -new file mode 100644 -index 00000000..b4e9f698 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/PresenceServerExtension.java -@@ -0,0 +1,341 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.ByteArrayOutputStream; -+import java.io.FileOutputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+ -+public class PresenceServerExtension extends Extension implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -6333109673043357921L; -+ private boolean mCritical; -+ private int mVersion = 0; -+ private String mStreetAddress = null; -+ private String mTelephoneNumber = null; -+ private String mRFC822Name = null; -+ private String mID = null; -+ private String mHostName = null; -+ private int mPortNumber = 0; -+ private int mMaxUsers = 0; -+ private int mServiceLevel = 0; -+ -+ public static final String OID = "2.16.840.1.113730.1.18"; -+ -+ /* -+ public PresenceServerExtension() -+ { -+ } -+ */ -+ -+ public PresenceServerExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = new ObjectIdentifier(OID); -+ this.critical = critical.booleanValue(); -+ this.extensionValue = ((byte[]) value).clone(); -+ decodeThis(); -+ } -+ -+ public PresenceServerExtension( -+ boolean critical, -+ int version, -+ String streetAddress, -+ String telephoneNumber, -+ String rfc822Name, -+ String ID, -+ String hostName, -+ int portNumber, -+ int maxUsers, -+ int serviceLevel) -+ throws IOException { -+ mCritical = critical; -+ mVersion = version; -+ mStreetAddress = streetAddress; -+ mTelephoneNumber = telephoneNumber; -+ mRFC822Name = rfc822Name; -+ mID = ID; -+ mHostName = hostName; -+ mPortNumber = portNumber; -+ mMaxUsers = maxUsers; -+ mServiceLevel = serviceLevel; -+ -+ this.extensionId = new ObjectIdentifier(OID); -+ this.critical = mCritical; -+ encodeThis(); -+ } -+ -+ public int getVersion() { -+ return mVersion; -+ } -+ -+ public String getStreetAddress() { -+ return mStreetAddress; -+ } -+ -+ public String getTelephoneNumber() { -+ return mTelephoneNumber; -+ } -+ -+ public String getRFC822() { -+ return mRFC822Name; -+ } -+ -+ public String getID() { -+ return mID; -+ } -+ -+ public String getHostName() { -+ return mHostName; -+ } -+ -+ public int getPortNumber() { -+ return mPortNumber; -+ } -+ -+ public int getMaxUsers() { -+ return mMaxUsers; -+ } -+ -+ public int getServiceLevel() { -+ return mServiceLevel; -+ } -+ -+ public void encodeThis() throws IOException { -+ try (DerOutputStream out = new DerOutputStream()) { -+ DerOutputStream temp = new DerOutputStream(); -+ temp.putInteger(new BigInt(mVersion)); -+ temp.putOctetString(mStreetAddress.getBytes()); -+ temp.putOctetString(mTelephoneNumber.getBytes()); -+ temp.putOctetString(mRFC822Name.getBytes()); -+ temp.putOctetString(mID.getBytes()); -+ temp.putOctetString(mHostName.getBytes()); -+ temp.putInteger(new BigInt(mPortNumber)); -+ temp.putInteger(new BigInt(mMaxUsers)); -+ temp.putInteger(new BigInt(mServiceLevel)); -+ out.write(DerValue.tag_Sequence, temp); -+ this.extensionValue = out.toByteArray(); -+ } -+ } -+ -+ public void decodeThis() throws IOException { -+ DerInputStream val = new DerInputStream(this.extensionValue); -+ byte data[] = null; -+ DerValue seq[] = val.getSequence(0); -+ -+ mVersion = seq[0].getInteger().toInt(); -+ data = null; -+ if (seq[1].length() > 0) { -+ data = seq[1].getOctetString(); -+ } -+ if (data == null) { -+ mStreetAddress = ""; -+ } else { -+ mStreetAddress = new String(data); -+ } -+ data = null; -+ if (seq[2].length() > 0) -+ data = seq[2].getOctetString(); -+ if (data == null) { -+ mTelephoneNumber = ""; -+ } else { -+ mTelephoneNumber = new String(data); -+ } -+ data = null; -+ if (seq[3].length() > 0) -+ data = seq[3].getOctetString(); -+ if (data == null) { -+ mRFC822Name = ""; -+ } else { -+ mRFC822Name = new String(data); -+ } -+ data = null; -+ if (seq[4].length() > 0) -+ data = seq[4].getOctetString(); -+ if (data == null) { -+ mID = ""; -+ } else { -+ mID = new String(data); -+ } -+ data = null; -+ if (seq[5].length() > 0) -+ data = seq[5].getOctetString(); -+ if (data == null) { -+ mHostName = ""; -+ } else { -+ mHostName = new String(data); -+ } -+ mPortNumber = seq[6].getInteger().toInt(); -+ mMaxUsers = seq[7].getInteger().toInt(); -+ mServiceLevel = seq[8].getInteger().toInt(); -+ } -+ -+ public void decode(InputStream in) -+ throws CertificateException, IOException { -+ } -+ -+ public void encode(OutputStream out) -+ throws CertificateException, IOException { -+ DerOutputStream dos = new DerOutputStream(); -+ super.encode(dos); -+ out.write(dos.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ return null; -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ public Enumeration getAttributeNames() { -+ return null; -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return "PresenceServerExtension"; -+ } -+ -+ /** -+ * Set the name of this attribute. -+ */ -+ public void setName(String name) { -+ } -+ -+ /** -+ * Return the OID of this attribute. -+ */ -+ public String getOID() { -+ return OID; -+ } -+ -+ /** -+ * Set the OID of this attribute. -+ */ -+ public void setOID(String oid) { -+ } -+ -+ public static void main(String args[]) { -+ /* -+ 0 30 115: SEQUENCE { -+ 2 06 9: OBJECT IDENTIFIER '2 16 840 1 113730 1 100' -+ 13 04 102: OCTET STRING, encapsulates { -+ 15 30 100: SEQUENCE { -+ 17 02 1: INTEGER 0 -+ 20 04 31: OCTET STRING -+ : 34 30 31 45 20 4D 69 64 64 6C 65 66 69 65 6C 64 -+ : 20 52 64 2E 2C 4D 56 2C 43 41 39 34 30 34 31 -+ 53 04 12: OCTET STRING -+ : 36 35 30 2D 31 31 31 2D 31 31 31 31 -+ 67 04 18: OCTET STRING -+ : 61 64 6D 69 6E 40 6E 65 74 73 63 61 70 65 2E 63 -+ : 6F 6D -+ 87 04 10: OCTET STRING -+ : 70 73 2D 63 61 70 69 74 6F 6C -+ 99 04 7: OCTET STRING -+ : 63 61 70 69 74 6F 6C -+ 108 02 1: INTEGER 80 -+ 111 02 1: INTEGER 10 -+ 114 02 1: INTEGER 1 -+ : } -+ : } -+ : } -+ */ -+ ByteArrayOutputStream dos = null; -+ FileOutputStream fos = null; -+ try { -+ boolean critical = false; -+ int version = 1; -+ String streetAddress = "401E Middlefield Rd.,MV,CA94041"; -+ String telephoneNumber = "650-111-1111"; -+ String rfc822Name = "admin@netscape.com"; -+ String ID = "ps-capitol"; -+ String hostName = "capitol"; -+ int portNumber = 80; -+ int maxUsers = 10; -+ int serviceLevel = 1; -+ -+ PresenceServerExtension ext = new PresenceServerExtension( -+ critical, -+ version, streetAddress, telephoneNumber, -+ rfc822Name, ID, hostName, portNumber, -+ maxUsers, serviceLevel); -+ -+ // encode -+ -+ dos = new ByteArrayOutputStream(); -+ ext.encode(dos); -+ fos = new FileOutputStream("pse.der"); -+ fos.write(dos.toByteArray()); -+ Extension ext1 = new Extension(new DerValue(dos.toByteArray())); -+ -+ @SuppressWarnings("unused") -+ PresenceServerExtension ext2 = new PresenceServerExtension( -+ Boolean.valueOf(false), ext1.getExtensionValue()); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } catch (CertificateException e) { -+ e.printStackTrace(); -+ } finally { -+ if (dos != null) { -+ try { -+ dos.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ if (fos != null) { -+ try { -+ fos.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/SubjectInfoAccessExtension.java b/org/mozilla/jss/netscape/security/extensions/SubjectInfoAccessExtension.java -new file mode 100644 -index 00000000..e6d9dee1 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/SubjectInfoAccessExtension.java -@@ -0,0 +1,255 @@ -+// --- 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 org.mozilla.jss.netscape.security.extensions; -+ -+import java.io.ByteArrayInputStream; -+import java.io.ByteArrayOutputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.GeneralName; -+import org.mozilla.jss.netscape.security.x509.URIName; -+ -+import org.mozilla.jss.netscape.security.util.Cert; -+import org.mozilla.jss.netscape.security.util.Utils; -+ -+/** -+ * This represents the subject information access extension -+ * as defined in RFC3280. -+ * -+ * @author thomask -+ * @version $Revision$, $Date$ -+ */ -+public class SubjectInfoAccessExtension extends Extension implements CertAttrSet { -+ private static final long serialVersionUID = 7237321566602583325L; -+ -+ public static final String NAME = "SubjectInfoAccessExtension"; -+ -+ public static final int OID_OCSP[] = { 1, 3, 6, 1, 5, 5, 7, 48, 1 }; -+ public static final ObjectIdentifier METHOD_OCSP = new -+ ObjectIdentifier(OID_OCSP); -+ -+ public static final int OID_CA_ISSUERS[] = { 1, 3, 6, 1, 5, 5, 7, 48, 2 }; -+ public static final ObjectIdentifier METHOD_CA_ISSUERS = new -+ ObjectIdentifier(OID_CA_ISSUERS); -+ -+ public static final int OID[] = { 1, 3, 6, 1, 5, 5, 7, 1, 11 }; -+ public static final ObjectIdentifier ID = new ObjectIdentifier(OID); -+ -+ private Vector mDesc = new Vector(); -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public SubjectInfoAccessExtension(boolean critical) { -+ this.extensionId = ID; -+ this.critical = critical; -+ this.extensionValue = null; // build this when encodeThis() is called -+ } -+ -+ public SubjectInfoAccessExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = ID; -+ this.critical = critical.booleanValue(); -+ this.extensionValue = ((byte[]) value).clone(); -+ decodeThis(); -+ } -+ -+ /** -+ * Sets extension attribute. -+ */ -+ public void set(String name, Object obj) throws CertificateException { -+ // NOT USED -+ } -+ -+ /** -+ * Retrieves extension attribute. -+ */ -+ public Object get(String name) throws CertificateException { -+ // NOT USED -+ return null; -+ } -+ -+ /** -+ * Deletes attribute. -+ */ -+ public void delete(String name) throws CertificateException { -+ // NOT USED -+ } -+ -+ /** -+ * Decodes this extension. -+ */ -+ public void decode(InputStream in) throws IOException { -+ // NOT USED -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ // NOT USED -+ return null; -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return NAME; -+ } -+ -+ /** -+ * Adds Access Description. -+ */ -+ public void addAccessDescription( -+ ObjectIdentifier method, -+ GeneralName gn) { -+ clearValue(); -+ mDesc.addElement(new AccessDescription(method, gn)); -+ } -+ -+ public AccessDescription getAccessDescription(int pos) { -+ return mDesc.elementAt(pos); -+ } -+ -+ /** -+ * Returns the number of access description. -+ */ -+ public int numberOfAccessDescription() { -+ return mDesc.size(); -+ } -+ -+ private void decodeThis() throws IOException { -+ DerValue val = new DerValue(this.extensionValue); -+ -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding of AuthInfoAccess extension"); -+ } -+ while (val.data.available() != 0) { -+ DerValue seq = val.data.getDerValue(); -+ ObjectIdentifier method = seq.data.getDerValue().getOID(); -+ GeneralName gn = new GeneralName(seq.data.getDerValue()); -+ -+ addAccessDescription(method, gn); -+ } -+ } -+ -+ private void encodeThis() throws IOException { -+ try (DerOutputStream seq = new DerOutputStream(); -+ DerOutputStream tmp = new DerOutputStream()) { -+ -+ for (int i = 0; i < mDesc.size(); i++) { -+ DerOutputStream tmp0 = new DerOutputStream(); -+ AccessDescription ad = mDesc.elementAt(i); -+ -+ tmp0.putOID(ad.getMethod()); -+ ad.getLocation().encode(tmp0); -+ tmp.write(DerValue.tag_Sequence, tmp0); -+ } -+ seq.write(DerValue.tag_Sequence, tmp); -+ this.extensionValue = seq.toByteArray(); -+ } -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Returns a printable representation of the AuthInfoAccess. -+ */ -+ public String toString() { -+ StringBuffer s=new StringBuffer(super.toString() + "AuthInfoAccess [\n"); -+ -+ for (int i = 0; i < mDesc.size(); i++) { -+ AccessDescription ad = mDesc.elementAt(i); -+ s.append( "(" + i + ")"); -+ s.append(" "); -+ s.append(ad.getMethod().toString() + " " + ad.getLocation().toString()); -+ } -+ return (s.toString() + "]\n"); -+ } -+ -+ public static void main(String[] argv) { -+ AuthInfoAccessExtension aia = new AuthInfoAccessExtension(false); -+ GeneralName ocspName = new GeneralName(new -+ URIName("http://ocsp.netscape.com")); -+ -+ aia.addAccessDescription(METHOD_OCSP, ocspName); -+ GeneralName caIssuersName = new GeneralName(new -+ URIName("http://ocsp.netscape.com")); -+ -+ aia.addAccessDescription(METHOD_CA_ISSUERS, caIssuersName); -+ ByteArrayOutputStream os = new ByteArrayOutputStream(); -+ -+ try { -+ aia.encode(os); -+ -+ System.out.println(Utils.base64encode(os.toByteArray(), true)); -+ } catch (IOException e) { -+ System.out.println(e.toString()); -+ } -+ -+ try { -+ // test serialization -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ ObjectOutputStream oos = new ObjectOutputStream(bos); -+ -+ oos.writeObject(aia); -+ -+ ByteArrayInputStream bis = new ByteArrayInputStream( -+ bos.toByteArray()); -+ ObjectInputStream ois = new ObjectInputStream(bis); -+ AuthInfoAccessExtension clone = (AuthInfoAccessExtension) -+ ois.readObject(); -+ -+ System.out.println(clone); -+ } catch (Exception e) { -+ System.out.println(e.toString()); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/extensions/manifest.mn b/org/mozilla/jss/netscape/security/extensions/manifest.mn -new file mode 100644 -index 00000000..c9ba7382 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/extensions/manifest.mn -@@ -0,0 +1,8 @@ -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+CORE_DEPTH = ../../../../../.. -+PACKAGE = org/mozilla/jss/netscape/security/extensions -+MODULE = jss -diff --git a/org/mozilla/jss/netscape/security/manifest.mn b/org/mozilla/jss/netscape/security/manifest.mn -new file mode 100644 -index 00000000..a6f16ad4 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/manifest.mn -@@ -0,0 +1,12 @@ -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+CORE_DEPTH = ../../../../.. -+ -+MODULE = jss -+ -+DIRS = extensions \ -+ x509 \ -+ $(NULL) -diff --git a/org/mozilla/jss/netscape/security/pkcs/ContentInfo.java b/org/mozilla/jss/netscape/security/pkcs/ContentInfo.java -new file mode 100644 -index 00000000..a5effa66 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/ContentInfo.java -@@ -0,0 +1,155 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * A ContentInfo type, as defined in PKCS#7. -+ * -+ * @version 1.12 -+ * @author Benjamin Renaud -+ */ -+ -+public class ContentInfo { -+ -+ // pkcs7 pre-defined content types -+ private static int[] pkcs7 = { 1, 2, 840, 113549, 1, 7 }; -+ private static int[] data = { 1, 2, 840, 113549, 1, 7, 1 }; -+ private static int[] sdata = { 1, 2, 840, 113549, 1, 7, 2 }; -+ private static int[] edata = { 1, 2, 840, 113549, 1, 7, 3 }; -+ private static int[] sedata = { 1, 2, 840, 113549, 1, 7, 4 }; -+ private static int[] ddata = { 1, 2, 840, 113549, 1, 7, 5 }; -+ private static int[] crdata = { 1, 2, 840, 113549, 1, 7, 6 }; -+ -+ public static final ObjectIdentifier PKCS7_OID = -+ new ObjectIdentifier(pkcs7); -+ -+ public static final ObjectIdentifier DATA_OID = -+ new ObjectIdentifier(data); -+ -+ public static final ObjectIdentifier SIGNED_DATA_OID = -+ new ObjectIdentifier(sdata); -+ -+ public static final ObjectIdentifier ENVELOPED_DATA_OID = -+ new ObjectIdentifier(edata); -+ -+ public static final ObjectIdentifier SIGNED_AND_ENVELOPED_DATA_OID = -+ new ObjectIdentifier(sedata); -+ -+ public static final ObjectIdentifier DIGESTED_DATA_OID = -+ new ObjectIdentifier(ddata); -+ -+ public static final ObjectIdentifier ENCRYPTED_DATA_OID = -+ new ObjectIdentifier(crdata); -+ -+ ObjectIdentifier contentType; -+ DerValue content; // OPTIONAL -+ -+ public ContentInfo(ObjectIdentifier contentType, DerValue content) { -+ this.contentType = contentType; -+ this.content = content; -+ } -+ -+ /** -+ * Make a contentInfo of type data. -+ */ -+ public ContentInfo(byte[] bytes) { -+ DerValue octetString = new DerValue(DerValue.tag_OctetString, bytes); -+ this.contentType = DATA_OID; -+ this.content = octetString; -+ } -+ -+ public ContentInfo(DerInputStream derin) -+ throws IOException, ParsingException { -+ DerInputStream disType; -+ DerInputStream disTaggedContent; -+ DerValue type; -+ DerValue taggedContent; -+ DerValue[] typeAndContent; -+ DerValue[] contents; -+ -+ typeAndContent = derin.getSequence(2); -+ -+ // Parse the content type -+ type = typeAndContent[0]; -+ disType = new DerInputStream(type.toByteArray()); -+ contentType = disType.getOID(); -+ -+ // Parse the content (OPTIONAL field). -+ // Skip the [0] EXPLICIT tag by pretending that the content is the one -+ // and only element in an implicitly tagged set -+ if (typeAndContent.length > 1) { // content is OPTIONAL -+ taggedContent = typeAndContent[1]; -+ disTaggedContent = new DerInputStream(taggedContent.toByteArray()); -+ contents = disTaggedContent.getSet(1, true); -+ content = contents[0]; -+ } -+ } -+ -+ public DerValue getContent() { -+ return content; -+ } -+ -+ public byte[] getData() throws IOException { -+ if (contentType.equals(DATA_OID)) { -+ return content.getOctetString(); -+ } -+ throw new IOException("content type is not DATA: " + contentType); -+ } -+ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream contentDerCode; -+ DerOutputStream seq; -+ DerValue taggedContent; -+ -+ contentDerCode = new DerOutputStream(); -+ content.encode(contentDerCode); -+ // Add the [0] EXPLICIT tag in front of the content encoding -+ taggedContent = new DerValue((byte) 0xA0, -+ contentDerCode.toByteArray()); -+ -+ seq = new DerOutputStream(); -+ seq.putOID(contentType); -+ seq.putDerValue(taggedContent); -+ -+ out.write(DerValue.tag_Sequence, seq); -+ } -+ -+ /** -+ * Returns a byte array representation of the data held in -+ * the content field. -+ */ -+ public byte[] getContentBytes() throws IOException { -+ DerInputStream dis = new DerInputStream(content.toByteArray()); -+ return dis.getOctetString(); -+ } -+ -+ public String toString() { -+ String out = ""; -+ -+ out += "Content Info Sequence\n\tContent type: " + contentType + "\n"; -+ out += "\tContent: " + content; -+ return out; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/EncodingException.java b/org/mozilla/jss/netscape/security/pkcs/EncodingException.java -new file mode 100644 -index 00000000..27874a44 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/EncodingException.java -@@ -0,0 +1,33 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+public class EncodingException extends Exception { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -6126764125859196917L; -+ -+ public EncodingException() { -+ super(); -+ } -+ -+ public EncodingException(String s) { -+ super(s); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/Makefile b/org/mozilla/jss/netscape/security/pkcs/Makefile -new file mode 100644 -index 00000000..8fd7054b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/Makefile -@@ -0,0 +1,45 @@ -+#! gmake -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+####################################################################### -+# (1) Include initial platform-independent assignments (MANDATORY). # -+####################################################################### -+ -+include manifest.mn -+ -+####################################################################### -+# (2) Include "global" configuration information. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/config.mk -+ -+####################################################################### -+# (3) Include "component" configuration information. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (4) Include "local" platform-dependent assignments (OPTIONAL). # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (5) Execute "global" rules. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/rules.mk -+ -+####################################################################### -+# (6) Execute "component" rules. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS10.java b/org/mozilla/jss/netscape/security/pkcs/PKCS10.java -new file mode 100644 -index 00000000..1993037d ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS10.java -@@ -0,0 +1,368 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.IOException; -+import java.io.PrintStream; -+import java.security.InvalidKeyException; -+import java.security.NoSuchAlgorithmException; -+import java.security.PublicKey; -+import java.security.Signature; -+import java.security.SignatureException; -+import java.security.cert.CertificateException; -+ -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.x509.AlgorithmId; -+import org.mozilla.jss.netscape.security.x509.X500Name; -+import org.mozilla.jss.netscape.security.x509.X500Signer; -+import org.mozilla.jss.netscape.security.x509.X509Key; -+import org.mozilla.jss.netscape.security.util.Utils; -+/** -+ * PKCS #10 certificate requests are created and sent to Certificate -+ * Authorities, which then create X.509 certificates and return them to -+ * the entity which created the certificate request. These cert requests -+ * basically consist of the subject's X.500 name and public key, signed -+ * using the corresponding private key. -+ * -+ * The ASN.1 syntax for a Certification Request is: -+ * -+ *

-+ * CertificationRequest ::= SEQUENCE {
-+ *    certificationRequestInfo CertificationRequestInfo,
-+ *    signatureAlgorithm       SignatureAlgorithmIdentifier,
-+ *    signature                Signature
-+ *  }
-+ *
-+ * SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
-+ * Signature ::= BIT STRING
-+ *
-+ * CertificationRequestInfo ::= SEQUENCE {
-+ *    version                 Version,
-+ *    subject                 Name,
-+ *    subjectPublicKeyInfo    SubjectPublicKeyInfo,
-+ *    attributes [0] IMPLICIT Attributes
-+ * }
-+ * Attributes ::= SET OF Attribute
-+ * 
-+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.28 -+ */ -+public class PKCS10 { -+ /** -+ * Constructs an unsigned PKCS #10 certificate request. Before this -+ * request may be used, it must be encoded and signed. Then it -+ * must be retrieved in some conventional format (e.g. string). -+ * -+ * @param publicKey the public key that should be placed -+ * into the certificate generated by the CA. -+ */ -+ public PKCS10(X509Key publicKey) { -+ subjectPublicKeyInfo = publicKey; -+ attributeSet = new PKCS10Attributes(); -+ } -+ -+ /** -+ * Constructs an unsigned PKCS #10 certificate request. Before this -+ * request may be used, it must be encoded and signed. Then it -+ * must be retrieved in some conventional format (e.g. string). -+ * -+ * @param publicKey the public key that should be placed -+ * into the certificate generated by the CA. -+ * @param attributes additonal set of PKCS10 attributes requested -+ * for in the certificate. -+ */ -+ public PKCS10(X509Key publicKey, PKCS10Attributes attributes) { -+ subjectPublicKeyInfo = publicKey; -+ if (attributes != null) -+ attributeSet = attributes; -+ else -+ attributeSet = new PKCS10Attributes(); -+ } -+ -+ /** -+ * Parses an encoded, signed PKCS #10 certificate request, verifying -+ * the request's signature as it does so. This constructor would -+ * typically be used by a Certificate Authority, from which a new -+ * certificate would then be constructed. -+ * -+ * @param data the DER-encoded PKCS #10 request. -+ * @param sigver boolean specifies signature verification enabled or not -+ * @exception IOException for low level errors reading the data -+ * @exception SignatureException when the signature is invalid -+ * @exception NoSuchAlgorithmException when the signature -+ * algorithm is not supported in this environment -+ */ -+ public PKCS10(byte data[], boolean sigver) -+ throws IOException, SignatureException, NoSuchAlgorithmException, java.security.NoSuchProviderException { -+ DerInputStream in; -+ DerValue seq[]; -+ AlgorithmId id; -+ byte sigData[]; -+ Signature sig; -+ -+ String method = "PKCS10: PKCS10: "; -+ String msg = ""; -+ -+ System.out.println(method + "begins"); -+ if (data == null) { -+ throw new IllegalArgumentException(method + "param data cann't be null"); -+ } -+ certificateRequest = data; -+ -+ // -+ // Outer sequence: request, signature algorithm, signature. -+ // Parse, and prepare to verify later. -+ // -+ in = new DerInputStream(data); -+ seq = in.getSequence(3); -+ if (seq == null) { -+ throw new IllegalArgumentException(method + "in.getSequence null"); -+ } -+ -+ if (seq.length != 3) -+ throw new IllegalArgumentException(method + "not a PKCS #10 request"); -+ -+ data = seq[0].toByteArray(); // reusing this variable -+ certRequestInfo = seq[0].toByteArray(); // make a copy -+ id = AlgorithmId.parse(seq[1]); -+ sigData = seq[2].getBitString(); -+ -+ // -+ // Inner sequence: version, name, key, attributes -+ // -+ @SuppressWarnings("unused") -+ BigInt serial = seq[0].data.getInteger(); // consume serial -+ -+ /* -+ if (serial.toInt () != 0) -+ throw new IllegalArgumentException ("not PKCS #10 v1"); -+ */ -+ -+ subject = new X500Name(seq[0].data); -+ msg = "Request Subject: " + subject + ": "; -+ -+ byte val1[] = seq[0].data.getDerValue().toByteArray(); -+ subjectPublicKeyInfo = X509Key.parse(new DerValue(val1)); -+ PublicKey publicKey = X509Key.parsePublicKey(new DerValue(val1)); -+ if (publicKey == null) { -+ System.out.println(method + msg + "publicKey null"); -+ throw new SignatureException (method + msg + "publicKey null"); -+ } -+ -+ // Cope with a somewhat common illegal PKCS #10 format -+ if (seq[0].data.available() != 0) { -+ attributeSet = new PKCS10Attributes(seq[0].data); -+ } else { -+ attributeSet = new PKCS10Attributes(); -+ } -+ -+ // -+ // OK, we parsed it all ... validate the signature using the -+ // key and signature algorithm we found. -+ // temporary commented out -+ try { -+ String idName = id.getName(); -+ if (idName.equals("MD5withRSA")) -+ idName = "MD5/RSA"; -+ else if (idName.equals("MD2withRSA")) -+ idName = "MD2/RSA"; -+ else if (idName.equals("SHA1withRSA")) -+ idName = "SHA1/RSA"; -+ else if (idName.equals("SHA1withDSA")) -+ idName = "SHA1/DSA"; -+ else if (idName.equals("SHA256withRSA")) -+ idName = "SHA256/RSA"; -+ else if (idName.equals("SHA384withRSA")) -+ idName = "SHA384/RSA"; -+ else if (idName.equals("SHA512withRSA")) -+ idName = "SHA512/RSA"; -+ else if (idName.equals("SHA1withEC")) -+ idName = "SHA1/EC"; -+ else if (idName.equals("SHA256withEC")) -+ idName = "SHA256/EC"; -+ else if (idName.equals("SHA384withEC")) -+ idName = "SHA384/EC"; -+ else if (idName.equals("SHA512withEC")) -+ idName = "SHA512/EC"; -+ -+ if (sigver) { -+ sig = Signature.getInstance(idName, "Mozilla-JSS"); -+ -+ sig.initVerify(publicKey); -+ sig.update(data); -+ if (!sig.verify(sigData)) { -+ System.out.println(method + msg + "sig.verify() failed"); -+ throw new SignatureException(method + msg + "Invalid PKCS #10 signature"); -+ } -+ } -+ } catch (InvalidKeyException e) { -+ System.out.println(method + msg + e.toString()); -+ throw new SignatureException(method + msg + "invalid key"); -+ } -+ System.out.println(method + "ends"); -+ } -+ -+ public PKCS10(byte data[]) -+ throws IOException, SignatureException, NoSuchAlgorithmException, java.security.NoSuchProviderException { -+ this(data, true); -+ } -+ -+ /** -+ * Create the signed certificate request. This will later be -+ * retrieved in either string or binary format. -+ * -+ * @param requester identifies the signer (by X.500 name) -+ * and provides the private key used to sign. -+ * @exception IOException on errors. -+ * @exception CertificateException on certificate handling errors. -+ * @exception SignatureException on signature handling errors. -+ */ -+ public void encodeAndSign(X500Signer requester) -+ throws CertificateException, IOException, SignatureException { -+ DerOutputStream out, scratch; -+ byte certificateRequestInfo[]; -+ byte sig[]; -+ -+ if (certificateRequest != null) -+ throw new SignatureException("request is already signed"); -+ -+ subject = requester.getSigner(); -+ -+ /* -+ * Encode cert request info, wrap in a sequence for signing -+ */ -+ scratch = new DerOutputStream(); -+ scratch.putInteger(new BigInt(0)); // version zero -+ subject.encode(scratch); // X.500 name -+ subjectPublicKeyInfo.encode(scratch); // public key -+ attributeSet.encode(scratch); -+ -+ out = new DerOutputStream(); -+ out.write(DerValue.tag_Sequence, scratch); // wrap it! -+ certificateRequestInfo = out.toByteArray(); -+ scratch = out; -+ -+ /* -+ * Sign it ... -+ */ -+ requester.update(certificateRequestInfo, 0, -+ certificateRequestInfo.length); -+ sig = requester.sign(); -+ -+ /* -+ * Build guts of SIGNED macro -+ */ -+ requester.getAlgorithmId().encode(scratch); // sig algorithm -+ scratch.putBitString(sig); // sig -+ -+ /* -+ * Wrap those guts in a sequence -+ */ -+ out = new DerOutputStream(); -+ out.write(DerValue.tag_Sequence, scratch); -+ certificateRequest = out.toByteArray(); -+ } -+ -+ /** -+ * Returns the subject's name. -+ */ -+ public X500Name getSubjectName() { -+ return subject; -+ } -+ -+ /** -+ * Returns the subject's public key. -+ */ -+ public X509Key getSubjectPublicKeyInfo() { -+ return subjectPublicKeyInfo; -+ } -+ -+ /** -+ * Returns the additional attributes requested. -+ */ -+ public PKCS10Attributes getAttributes() { -+ return attributeSet; -+ } -+ -+ /** -+ * Returns the encoded and signed certificate request as a -+ * DER-encoded byte array. -+ * -+ * @return the certificate request, or null if encodeAndSign() -+ * has not yet been called. -+ */ -+ public byte[] toByteArray() { -+ return certificateRequest; -+ } -+ -+ /** -+ * Prints an E-Mailable version of the certificate request on the print -+ * stream passed. The format is a common base64 encoded one, supported -+ * by most Certificate Authorities because Netscape web servers have -+ * used this for some time. Some certificate authorities expect some -+ * more information, in particular contact information for the web -+ * server administrator. -+ * -+ * @param out the print stream where the certificate request -+ * will be printed. -+ * @exception IOException when an output operation failed -+ * @exception SignatureException when the certificate request was -+ * not yet signed. -+ */ -+ public void print(PrintStream out) -+ throws IOException, SignatureException { -+ if (certificateRequest == null) -+ throw new SignatureException("Cert request was not signed"); -+ -+ out.println("-----BEGIN NEW CERTIFICATE REQUEST-----"); -+ out.println(Utils.base64encode(certificateRequest, true)); -+ out.println("-----END NEW CERTIFICATE REQUEST-----"); -+ } -+ -+ /** -+ * Provides a short description of this request. -+ */ -+ public String toString() { -+ return "[PKCS #10 certificate request:\n" -+ + subjectPublicKeyInfo.toString() -+ + " subject: <" + subject + ">" + "\n" -+ + " attributes: " + attributeSet.toString() -+ + "\n]"; -+ } -+ -+ /** -+ * Retrieve the PKCS10 CertificateRequestInfo as a byte array -+ */ -+ public byte[] getCertRequestInfo() { -+ return certRequestInfo; -+ } -+ -+ private X500Name subject; -+ private X509Key subjectPublicKeyInfo; -+ private PKCS10Attributes attributeSet; -+ -+ private byte certificateRequest[]; // signed -+ private byte certRequestInfo[]; // inner content signed -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS10Attribute.java b/org/mozilla/jss/netscape/security/pkcs/PKCS10Attribute.java -new file mode 100644 -index 00000000..1447926e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS10Attribute.java -@@ -0,0 +1,235 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.IOException; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.lang.reflect.Array; -+import java.lang.reflect.Constructor; -+import java.lang.reflect.InvocationTargetException; -+import java.security.cert.CertificateException; -+ -+import org.mozilla.jss.netscape.security.util.DerEncoder; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.ACertAttrSet; -+import org.mozilla.jss.netscape.security.x509.CertAttrSet; -+import org.mozilla.jss.netscape.security.x509.Extensions; -+import org.mozilla.jss.netscape.security.x509.OIDMap; -+ -+/** -+ * Represent a PKCS Attribute. -+ * -+ *

-+ * Attributes are addiitonal attributes which can be inserted in a PKCS certificate request. For example a -+ * "Driving License Certificate" could have the driving license number as a attribute. -+ * -+ *

-+ * Attributes are represented as a sequence of the attribute identifier (Object Identifier) and a set of DER encoded -+ * attribute values. The current implementation only supports one value per attribute. -+ * -+ * ASN.1 definition of Attribute: -+ * -+ *

-+ * Attribute :: SEQUENCE {
-+ *    type    AttributeValue,
-+ *    values  SET OF AttributeValue
-+ * }
-+ * AttributeValue ::= ANY
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.13 -+ */ -+public class PKCS10Attribute implements DerEncoder, Serializable { -+ private static final long serialVersionUID = 2002480042340316170L; -+ protected ObjectIdentifier attributeId = null; -+ protected CertAttrSet attributeValue = null; -+ -+ /** -+ * Default constructor. Used only by sub-classes. -+ */ -+ public PKCS10Attribute() { -+ } -+ -+ /** -+ * Constructs an attribute from a DER encoded array of bytes. -+ */ -+ public PKCS10Attribute(DerValue derVal) throws IOException { -+ if (derVal.tag != DerValue.tag_Sequence) { -+ throw new IOException("Sequence tag missing for PKCS10Attribute."); -+ } -+ -+ DerInputStream in = derVal.toDerInputStream(); -+ // Object identifier -+ attributeId = in.getOID(); -+ // System.out.println("attribute ID in pkcs10 "+attributeId.toString()); -+ -+ // Rest of the stuff is attribute value(s), wrapped in a SET. -+ // For now, assume there is only one attribute value present. -+ DerValue[] inAttrValues = in.getSet(1); -+ int attrValueNum = inAttrValues.length; -+ if (attrValueNum > 1) { -+ throw new IOException("More than one value per attribute not supported"); -+ } -+ -+ // Read the first attribute value -+ DerValue inAttrValue = inAttrValues[0]; -+ -+ if (attributeId.equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) { -+ //pkcs9 extensionAttr -+ try { -+ // remove the tag -+ //DerValue dv = inAttrValue.data.getDerValue(); -+ // hack. toDerInputStream only gives one extension. -+ DerInputStream fi = new DerInputStream(inAttrValue.toByteArray()); -+ attributeValue = new Extensions(fi); -+ //CertificateExtensions(fi); -+ return; -+ } catch (Exception e) { -+ throw new IOException(e.toString()); -+ } -+ } -+ byte[] val = inAttrValue.toByteArray(); -+ Class[] params = { Object.class }; -+ try { -+ @SuppressWarnings("unchecked") -+ Class extClass = (Class) OIDMap.getClass(attributeId); -+ if (extClass != null) { -+ Constructor cons = extClass.getConstructor(params); -+ Object value = Array.newInstance(byte.class, val.length); -+ for (int i = 0; i < val.length; i++) { -+ Array.setByte(value, i, val[i]); -+ } -+ Object[] passed = new Object[] { value }; -+ attributeValue = cons.newInstance(passed); -+ } else { -+ // attribute classes are usable for PKCS10 attributes. -+ // this is used where the attributes are not actual -+ // implemented extensions. -+ attributeValue = new ACertAttrSet(inAttrValue); -+ } -+ } catch (InvocationTargetException invk) { -+ throw new IOException(invk.getTargetException().getMessage(), invk); -+ } catch (Exception e) { -+ throw new IOException(e.toString()); -+ } -+ } -+ -+ /** -+ * Constructs an attribute from individual components of ObjectIdentifier -+ * and the DER encoded value. -+ * -+ * @param attributeId the ObjectIdentifier of the attribute. -+ * @param attributeValue the CertAttrSet. -+ */ -+ public PKCS10Attribute(ObjectIdentifier attributeId, -+ CertAttrSet attributeValue) { -+ this.attributeId = attributeId; -+ this.attributeValue = attributeValue; -+ } -+ -+ /** -+ * Constructs an attribute from another attribute. To be used for -+ * creating decoded subclasses. -+ * -+ * @param attr the attribute to create from. -+ */ -+ public PKCS10Attribute(PKCS10Attribute attr) { -+ this.attributeId = attr.attributeId; -+ this.attributeValue = attr.attributeValue; -+ } -+ -+ /** -+ * Write the output to the DerOutputStream. -+ * -+ * @param out the OutputStream to write the attribute to. -+ * @exception CertificateException on certificate encoding errors. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) -+ throws CertificateException, IOException { -+ try (DerOutputStream tmp = new DerOutputStream()) { -+ // Encode the attribute value -+ DerOutputStream outAttrValue = new DerOutputStream(); -+ attributeValue.encode(outAttrValue); -+ -+ // Wrap the encoded attribute value into a SET -+ DerValue outAttrValueSet = new DerValue(DerValue.tag_Set, -+ outAttrValue.toByteArray()); -+ -+ // Create the attribute -+ DerOutputStream outAttr = new DerOutputStream(); -+ outAttr.putOID(attributeId); -+ outAttr.putDerValue(outAttrValueSet); -+ -+ // Wrap the OID and the set of attribute values into a SEQUENCE -+ tmp.write(DerValue.tag_Sequence, outAttr); -+ -+ // write the results to out -+ out.write(tmp.toByteArray()); -+ } -+ } -+ -+ /** -+ * DER encode this object onto an output stream. -+ * Implements the DerEncoder interface. -+ * -+ * @param out -+ * the OutputStream on which to write the DER encoding. -+ * -+ * @exception IOException on encoding errors. -+ */ -+ public void derEncode(OutputStream out) throws IOException { -+ try { -+ encode(out); -+ } catch (CertificateException ce) { -+ IOException ioe = new IOException(ce.toString()); -+ ioe.fillInStackTrace(); -+ throw ioe; -+ } -+ } -+ -+ /** -+ * Returns the ObjectIdentifier of the attribute. -+ */ -+ public ObjectIdentifier getAttributeId() { -+ return (attributeId); -+ } -+ -+ /** -+ * Returns the attribute value as an byte array for further processing. -+ */ -+ public CertAttrSet getAttributeValue() { -+ return (attributeValue); -+ } -+ -+ /** -+ * Returns the attribute in user readable form. -+ */ -+ public String toString() { -+ String s = "AttributeId: " + attributeId.toString() + "\n"; -+ s += "AttributeValue: " + attributeValue.toString(); -+ -+ return (s); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS10Attributes.java b/org/mozilla/jss/netscape/security/pkcs/PKCS10Attributes.java -new file mode 100644 -index 00000000..5d9209ea ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS10Attributes.java -@@ -0,0 +1,177 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.IOException; -+import java.io.OutputStream; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerEncoder; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the PKCS10 attributes for the request. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.10 -+ */ -+public class PKCS10Attributes extends Vector implements DerEncoder { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 1362260612357629542L; -+ private Hashtable map; -+ -+ /** -+ * Default constructor for the certificate attribute. -+ */ -+ public PKCS10Attributes() { -+ map = new Hashtable(); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the attributes from. -+ * @exception IOException on decoding errors. -+ */ -+ public PKCS10Attributes(DerInputStream in) -+ throws IOException { -+ -+ map = new Hashtable(); -+ DerValue[] attrs = in.getSet(5, true); -+ -+ if (attrs != null) { -+ for (int i = 0; i < attrs.length; i++) { -+ PKCS10Attribute attr = new PKCS10Attribute(attrs[i]); -+ addElement(attr); -+ System.out.println("PKCS10Attributes: adding attribute: " + -+ attr.getAttributeValue().getName()); -+ map.put(attr.getAttributeValue().getName(), attr); -+ } -+ } -+ } -+ -+ /** -+ * Encode the attributes in DER form to the stream. -+ * -+ * @param out the OutputStream to marshal the contents to. -+ * -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) -+ throws IOException { -+ derEncode(out); -+ } -+ -+ /** -+ * Encode the attributes in DER form to the stream. -+ * Implements the DerEncoder interface. -+ * -+ * @param out the OutputStream to marshal the contents to. -+ * @exception IOException on encoding errors. -+ */ -+ public void derEncode(OutputStream out) -+ throws IOException { -+ try (DerOutputStream attrOut = new DerOutputStream()) { -+ // first copy the elements into an array -+ PKCS10Attribute[] attribs = new PKCS10Attribute[size()]; -+ copyInto(attribs); -+ -+ attrOut.putOrderedSetOf(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0), -+ attribs); -+ -+ out.write(attrOut.toByteArray()); -+ } catch (IOException e) { -+ throw e; -+ } -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void setAttribute(String name, PKCS10Attribute attr) throws IOException { -+ map.put(name, attr); -+ addElement(attr); -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public PKCS10Attribute getAttribute(String name) throws IOException { -+ PKCS10Attribute attr = map.get(name); -+ /* -+ if (attr == null) { -+ throw new IOException("No attribute found with name " + name); -+ } -+ */ -+ return (attr); -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void deleteAttribute(String name) throws IOException { -+ PKCS10Attribute attr = map.get(name); -+ if (attr == null) { -+ throw new IOException("No attribute found with name " + name); -+ } -+ map.remove(name); -+ removeElement(attr); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getElements() { -+ return map.elements(); -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = super.hashCode(); -+ result = prime * result + ((map == null) ? 0 : map.hashCode()); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (!super.equals(obj)) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ PKCS10Attributes other = (PKCS10Attributes) obj; -+ if (map == null) { -+ if (other.map != null) -+ return false; -+ } else if (!map.equals(other.map)) -+ return false; -+ return true; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS12.java b/org/mozilla/jss/netscape/security/pkcs/PKCS12.java -new file mode 100644 -index 00000000..64f7bfc2 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS12.java -@@ -0,0 +1,209 @@ -+// --- 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) 2016 Red Hat, Inc. -+// All rights reserved. -+// --- END COPYRIGHT BLOCK --- -+package org.mozilla.jss.netscape.security.pkcs; -+ -+import java.math.BigInteger; -+import java.util.ArrayList; -+import java.util.Collection; -+import java.util.LinkedHashMap; -+import java.util.Map; -+ -+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER; -+ -+public class PKCS12 { -+ -+ // PKI OID: 2.16.840.1.113730.5 -+ public final static OBJECT_IDENTIFIER PKI_OID = new OBJECT_IDENTIFIER("2.16.840.1.113730.5"); -+ -+ // PKCS #12 OID: 2.16.840.1.113730.5.1 -+ public final static OBJECT_IDENTIFIER PKCS12_OID = PKI_OID.subBranch(1); -+ -+ // PKCS #12 attributes OID: 2.16.840.1.113730.5.1.1 -+ public final static OBJECT_IDENTIFIER PKCS12_ATTRIBUTES_OID = PKCS12_OID.subBranch(1); -+ -+ // Certificate trust flags OID: 2.16.840.1.113730.5.1.1.1 -+ public final static OBJECT_IDENTIFIER CERT_TRUST_FLAGS_OID = PKCS12_ATTRIBUTES_OID.subBranch(1); -+ -+ // based on certdb.h in NSS -+ public final static int TERMINAL_RECORD = 1 << 0; -+ public final static int TRUSTED = 1 << 1; -+ public final static int SEND_WARN = 1 << 2; -+ public final static int VALID_CA = 1 << 3; -+ public final static int TRUSTED_CA = 1 << 4; -+ public final static int NS_TRUSTED_CA = 1 << 5; -+ public final static int USER = 1 << 6; -+ public final static int TRUSTED_CLIENT_CA = 1 << 7; -+ public final static int INVISIBLE_CA = 1 << 8; -+ public final static int GOVT_APPROVED_CA = 1 << 9; -+ -+ public static boolean isFlagEnabled(int flag, int flags) { -+ return (flag & flags) > 0; -+ } -+ -+ // based on printflags() in secutil.c in NSS -+ public static String encodeFlags(int flags) { -+ -+ StringBuffer sb = new StringBuffer(); -+ -+ if (isFlagEnabled(VALID_CA, flags) && !isFlagEnabled(TRUSTED_CA, flags) && !isFlagEnabled(TRUSTED_CLIENT_CA, flags)) -+ sb.append("c"); -+ -+ if (isFlagEnabled(TERMINAL_RECORD, flags) && !isFlagEnabled(TRUSTED, flags)) -+ sb.append("p"); -+ -+ if (isFlagEnabled(TRUSTED_CA, flags)) -+ sb.append("C"); -+ -+ if (isFlagEnabled(TRUSTED_CLIENT_CA, flags)) -+ sb.append("T"); -+ -+ if (isFlagEnabled(TRUSTED, flags)) -+ sb.append("P"); -+ -+ if (isFlagEnabled(USER, flags)) -+ sb.append("u"); -+ -+ if (isFlagEnabled(SEND_WARN, flags)) -+ sb.append("w"); -+ -+ if (isFlagEnabled(INVISIBLE_CA, flags)) -+ sb.append("I"); -+ -+ if (isFlagEnabled(GOVT_APPROVED_CA, flags)) -+ sb.append("G"); -+ -+ return sb.toString(); -+ } -+ -+ // based on CERT_DecodeTrustString() in certdb.c in NSS -+ public static int decodeFlags(String flags) throws Exception { -+ -+ int value = 0; -+ -+ for (char c : flags.toCharArray()) { -+ switch (c) { -+ case 'p': -+ value = value | TERMINAL_RECORD; -+ break; -+ -+ case 'P': -+ value = value | TRUSTED | TERMINAL_RECORD; -+ break; -+ -+ case 'w': -+ value = value | SEND_WARN; -+ break; -+ -+ case 'c': -+ value = value | VALID_CA; -+ break; -+ -+ case 'T': -+ value = value | TRUSTED_CLIENT_CA | VALID_CA; -+ break; -+ -+ case 'C' : -+ value = value | TRUSTED_CA | VALID_CA; -+ break; -+ -+ case 'u': -+ value = value | USER; -+ break; -+ -+ case 'i': -+ value = value | INVISIBLE_CA; -+ break; -+ case 'g': -+ value = value | GOVT_APPROVED_CA; -+ break; -+ -+ default: -+ throw new Exception("Invalid trust flag: " + c); -+ } -+ } -+ -+ return value; -+ } -+ -+ Map keyInfosByID = new LinkedHashMap(); -+ -+ Map certInfosByID = new LinkedHashMap(); -+ -+ public PKCS12() { -+ } -+ -+ public Collection getKeyInfos() { -+ return keyInfosByID.values(); -+ } -+ -+ public void addKeyInfo(PKCS12KeyInfo keyInfo) { -+ keyInfosByID.put(keyInfo.id, keyInfo); -+ } -+ -+ public PKCS12KeyInfo getKeyInfoByID(BigInteger id) { -+ return keyInfosByID.get(id); -+ } -+ -+ public PKCS12KeyInfo removeKeyInfoByID(BigInteger id) { -+ return keyInfosByID.remove(id); -+ } -+ -+ public Collection getCertInfos() { -+ return certInfosByID.values(); -+ } -+ -+ public void addCertInfo(PKCS12CertInfo certInfo, boolean replace) { -+ BigInteger id = certInfo.getID(); -+ -+ if (!replace && certInfosByID.containsKey(id)) -+ return; -+ -+ certInfosByID.put(id, certInfo); -+ } -+ -+ public PKCS12CertInfo getCertInfoByID(BigInteger id) { -+ return certInfosByID.get(id); -+ } -+ -+ public Collection getCertInfosByNickname(String nickname) { -+ -+ Collection result = new ArrayList(); -+ -+ for (PKCS12CertInfo certInfo : certInfosByID.values()) { -+ if (!nickname.equals(certInfo.getNickname())) continue; -+ result.add(certInfo); -+ } -+ -+ return result; -+ } -+ -+ public void removeCertInfoByNickname(String nickname) throws Exception { -+ -+ Collection result = getCertInfosByNickname(nickname); -+ -+ if (result.isEmpty()) { -+ throw new Exception("Certificate not found: " + nickname); -+ } -+ -+ for (PKCS12CertInfo certInfo : result) { -+ // remove cert and key -+ certInfosByID.remove(certInfo.getID()); -+ keyInfosByID.remove(certInfo.getID()); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS12CertInfo.java b/org/mozilla/jss/netscape/security/pkcs/PKCS12CertInfo.java -new file mode 100644 -index 00000000..ac52ece6 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS12CertInfo.java -@@ -0,0 +1,65 @@ -+// --- 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) 2016 Red Hat, Inc. -+// All rights reserved. -+// --- END COPYRIGHT BLOCK --- -+package org.mozilla.jss.netscape.security.pkcs; -+ -+import java.math.BigInteger; -+ -+import org.mozilla.jss.netscape.security.x509.X509CertImpl; -+ -+public class PKCS12CertInfo { -+ -+ BigInteger id; -+ X509CertImpl cert; -+ String nickname; -+ String trustFlags; -+ -+ public PKCS12CertInfo() { -+ } -+ -+ public BigInteger getID() { -+ return id; -+ } -+ -+ public void setID(BigInteger id) { -+ this.id = id; -+ } -+ -+ public X509CertImpl getCert() { -+ return cert; -+ } -+ -+ public void setCert(X509CertImpl cert) { -+ this.cert = cert; -+ } -+ -+ public String getNickname() { -+ return nickname; -+ } -+ -+ public void setNickname(String nickname) { -+ this.nickname = nickname; -+ } -+ -+ public String getTrustFlags() { -+ return trustFlags; -+ } -+ -+ public void setTrustFlags(String trustFlags) { -+ this.trustFlags = trustFlags; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS12KeyInfo.java b/org/mozilla/jss/netscape/security/pkcs/PKCS12KeyInfo.java -new file mode 100644 -index 00000000..8bb9968c ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS12KeyInfo.java -@@ -0,0 +1,84 @@ -+// --- 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) 2016 Red Hat, Inc. -+// All rights reserved. -+// --- END COPYRIGHT BLOCK --- -+package org.mozilla.jss.netscape.security.pkcs; -+ -+import java.math.BigInteger; -+ -+import org.mozilla.jss.crypto.PrivateKey; -+ -+/** -+ * This object is used for carrying key info around. -+ * -+ * It does not handle raw key material (but it used to). -+ * -+ * FIXME: A clear refactoring opportunity exists. The 'privateKey' -+ * field (and associated constructor) is only used during export, -+ * and the 'epkiBytes' field (and associated constructor) is only -+ * used during import. Therefore this should be two different -+ * types. -+ */ -+public class PKCS12KeyInfo { -+ -+ private PrivateKey privateKey; -+ private byte[] epkiBytes; -+ BigInteger id; -+ String subjectDN; -+ -+ public PKCS12KeyInfo() { -+ } -+ -+ /** -+ * Construct with a PrivateKey. This constructor is used -+ * for moving the PrivateKey handle around during export. -+ */ -+ public PKCS12KeyInfo(PrivateKey k) { -+ this.privateKey = k; -+ } -+ -+ /** Construct with a (serialised) EncrypedPrivateKeyInfo. This -+ * constructor is used for moving the EPKI data around during -+ * import. -+ */ -+ public PKCS12KeyInfo(byte[] epkiBytes) { -+ this.epkiBytes = epkiBytes; -+ } -+ -+ public PrivateKey getPrivateKey() { -+ return this.privateKey; -+ } -+ -+ public byte[] getEncryptedPrivateKeyInfoBytes() { -+ return epkiBytes; -+ } -+ -+ public BigInteger getID() { -+ return id; -+ } -+ -+ public void setID(BigInteger id) { -+ this.id = id; -+ } -+ -+ public String getSubjectDN() { -+ return subjectDN; -+ } -+ -+ public void setSubjectDN(String subjectDN) { -+ this.subjectDN = subjectDN; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS12Util.java b/org/mozilla/jss/netscape/security/pkcs/PKCS12Util.java -new file mode 100644 -index 00000000..e0fbe7fe ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS12Util.java -@@ -0,0 +1,667 @@ -+// --- 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) 2016 Red Hat, Inc. -+// All rights reserved. -+// --- END COPYRIGHT BLOCK --- -+package org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.ByteArrayInputStream; -+import java.io.ByteArrayOutputStream; -+import java.io.FileOutputStream; -+import java.math.BigInteger; -+import java.nio.file.Files; -+import java.nio.file.Path; -+import java.nio.file.Paths; -+import java.security.MessageDigest; -+import java.security.Principal; -+import java.security.PublicKey; -+import java.security.cert.CertificateException; -+import java.util.Collection; -+ -+import org.apache.commons.lang.StringUtils; -+import org.mozilla.jss.CryptoManager; -+import org.mozilla.jss.asn1.ANY; -+import org.mozilla.jss.asn1.ASN1Value; -+import org.mozilla.jss.asn1.BMPString; -+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER; -+import org.mozilla.jss.asn1.OCTET_STRING; -+import org.mozilla.jss.asn1.SEQUENCE; -+import org.mozilla.jss.asn1.SET; -+import org.mozilla.jss.crypto.CryptoStore; -+import org.mozilla.jss.crypto.CryptoToken; -+import org.mozilla.jss.crypto.EncryptionAlgorithm; -+import org.mozilla.jss.crypto.InternalCertificate; -+import org.mozilla.jss.crypto.NoSuchItemOnTokenException; -+import org.mozilla.jss.crypto.ObjectNotFoundException; -+import org.mozilla.jss.crypto.PrivateKey; -+import org.mozilla.jss.crypto.X509Certificate; -+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.Attribute; -+import org.mozilla.jss.util.Password; -+ -+import netscape.ldap.LDAPDN; -+import netscape.ldap.util.DN; -+import org.mozilla.jss.netscape.security.x509.X509CertImpl; -+ -+public class PKCS12Util { -+ -+ -+ boolean trustFlagsEnabled = true; -+ -+ public boolean isTrustFlagsEnabled() { -+ return trustFlagsEnabled; -+ } -+ -+ public void setTrustFlagsEnabled(boolean trustFlagsEnabled) { -+ this.trustFlagsEnabled = trustFlagsEnabled; -+ } -+ -+ public String getTrustFlags(X509Certificate cert) { -+ -+ InternalCertificate icert = (InternalCertificate) cert; -+ -+ StringBuilder sb = new StringBuilder(); -+ -+ sb.append(PKCS12.encodeFlags(icert.getSSLTrust())); -+ sb.append(","); -+ sb.append(PKCS12.encodeFlags(icert.getEmailTrust())); -+ sb.append(","); -+ sb.append(PKCS12.encodeFlags(icert.getObjectSigningTrust())); -+ -+ return sb.toString(); -+ } -+ -+ public void setTrustFlags(X509Certificate cert, String trustFlags) throws Exception { -+ -+ InternalCertificate icert = (InternalCertificate) cert; -+ -+ String[] flags = trustFlags.split(",", -1); // don't remove empty string -+ if (flags.length < 3) throw new Exception("Invalid trust flags: " + trustFlags); -+ -+ icert.setSSLTrust(PKCS12.decodeFlags(flags[0])); -+ icert.setEmailTrust(PKCS12.decodeFlags(flags[1])); -+ icert.setObjectSigningTrust(PKCS12.decodeFlags(flags[2])); -+ } -+ -+ /** Add a private key to the PKCS #12 object. -+ * -+ * The PKCS12KeyInfo object received comes about in two -+ * different scenarios: -+ * -+ * - The private key could be in encrypted byte[] form (e.g. -+ * when we have merely loaded a PKCS #12 file for inspection -+ * or e.g. to delete a certificate and its associated key). -+ * In this case we simply re-use this encrypted private key -+ * info byte[]. -+ * -+ * - The private key could be a be an NSS PrivateKey handle. In -+ * this case we must export the PrivateKey from the token to -+ * obtain the EncryptedPrivateKeyInfo. -+ * -+ * The common final step is to add the encrypted private key -+ * data to a "Shrouded Key Bag" to the PKCS #12 object. -+ * Unencrypted key material is never seen. -+ */ -+ public void addKeyBag(PKCS12KeyInfo keyInfo, Password password, -+ SEQUENCE encSafeContents) throws Exception { -+ -+ byte[] epkiBytes = keyInfo.getEncryptedPrivateKeyInfoBytes(); -+ if (epkiBytes == null) { -+ PrivateKey k = keyInfo.getPrivateKey(); -+ if (k == null) { -+ return; -+ } -+ -+ epkiBytes = CryptoManager.getInstance() -+ .getInternalKeyStorageToken() -+ .getCryptoStore() -+ .getEncryptedPrivateKeyInfo( -+ /* For compatibility with OpenSSL and NSS >= 3.31, -+ * do not BMPString-encode the passphrase when using -+ * non-PKCS #12 PBE scheme such as PKCS #5 PBES2. -+ * -+ * The resulting PKCS #12 is not compatible with -+ * NSS < 3.31. -+ */ -+ null /* passConverter */, -+ password, -+ /* NSS has a bug that causes any AES CBC encryption -+ * to use AES-256, but AlgorithmID contains chosen -+ * alg. To avoid mismatch, use AES_256_CBC. */ -+ EncryptionAlgorithm.AES_256_CBC, -+ 0 /* iterations (default) */, -+ k); -+ } -+ -+ SET keyAttrs = createKeyBagAttrs(keyInfo); -+ -+ SafeBag safeBag = new SafeBag( -+ SafeBag.PKCS8_SHROUDED_KEY_BAG, new ANY(epkiBytes), keyAttrs); -+ encSafeContents.addElement(safeBag); -+ } -+ -+ public void addCertBag(PKCS12CertInfo certInfo, -+ SEQUENCE safeContents) throws Exception { -+ -+ -+ ASN1Value cert = new OCTET_STRING(certInfo.cert.getEncoded()); -+ CertBag certBag = new CertBag(CertBag.X509_CERT_TYPE, cert); -+ -+ SET certAttrs = createCertBagAttrs(certInfo); -+ -+ SafeBag safeBag = new SafeBag(SafeBag.CERT_BAG, certBag, certAttrs); -+ safeContents.addElement(safeBag); -+ } -+ -+ BigInteger createLocalID(X509Certificate cert) throws Exception { -+ // SHA1 hash of the X509Cert DER encoding -+ return createLocalID(cert.getEncoded()); -+ } -+ -+ BigInteger createLocalID(byte[] bytes) throws Exception { -+ -+ MessageDigest md = MessageDigest.getInstance("SHA"); -+ md.update(bytes); -+ return new BigInteger(1, md.digest()); -+ } -+ -+ SET createKeyBagAttrs(PKCS12KeyInfo keyInfo) throws Exception { -+ -+ SET attrs = new SET(); -+ -+ SEQUENCE subjectAttr = new SEQUENCE(); -+ subjectAttr.addElement(SafeBag.FRIENDLY_NAME); -+ -+ SET subjectSet = new SET(); -+ subjectSet.addElement(new BMPString(keyInfo.subjectDN)); -+ subjectAttr.addElement(subjectSet); -+ -+ attrs.addElement(subjectAttr); -+ -+ SEQUENCE localKeyAttr = new SEQUENCE(); -+ localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID); -+ -+ SET localKeySet = new SET(); -+ localKeySet.addElement(new OCTET_STRING(keyInfo.id.toByteArray())); -+ localKeyAttr.addElement(localKeySet); -+ -+ attrs.addElement(localKeyAttr); -+ -+ return attrs; -+ } -+ -+ SET createCertBagAttrs(PKCS12CertInfo certInfo) throws Exception { -+ -+ SET attrs = new SET(); -+ -+ SEQUENCE nicknameAttr = new SEQUENCE(); -+ nicknameAttr.addElement(SafeBag.FRIENDLY_NAME); -+ -+ SET nicknameSet = new SET(); -+ nicknameSet.addElement(new BMPString(certInfo.nickname)); -+ nicknameAttr.addElement(nicknameSet); -+ -+ attrs.addElement(nicknameAttr); -+ -+ if (certInfo.getID() != null) { -+ SEQUENCE localKeyAttr = new SEQUENCE(); -+ localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID); -+ -+ SET localKeySet = new SET(); -+ localKeySet.addElement(new OCTET_STRING(certInfo.id.toByteArray())); -+ localKeyAttr.addElement(localKeySet); -+ -+ attrs.addElement(localKeyAttr); -+ } -+ -+ if (certInfo.trustFlags != null && trustFlagsEnabled) { -+ SEQUENCE trustFlagsAttr = new SEQUENCE(); -+ trustFlagsAttr.addElement(PKCS12.CERT_TRUST_FLAGS_OID); -+ -+ SET trustFlagsSet = new SET(); -+ trustFlagsSet.addElement(new BMPString(certInfo.trustFlags)); -+ trustFlagsAttr.addElement(trustFlagsSet); -+ -+ attrs.addElement(trustFlagsAttr); -+ } -+ -+ return attrs; -+ } -+ -+ public void loadFromNSS(PKCS12 pkcs12) throws Exception { -+ loadFromNSS(pkcs12, true, true); -+ } -+ -+ public void loadFromNSS(PKCS12 pkcs12, boolean includeKey, boolean includeChain) throws Exception { -+ -+ -+ CryptoManager cm = CryptoManager.getInstance(); -+ CryptoToken token = cm.getInternalKeyStorageToken(); -+ CryptoStore store = token.getCryptoStore(); -+ -+ for (X509Certificate cert : store.getCertificates()) { -+ loadCertFromNSS(pkcs12, cert, includeKey, includeChain); -+ } -+ } -+ -+ public void loadCertFromNSS(PKCS12 pkcs12, String nickname, boolean includeKey, boolean includeChain) throws Exception { -+ -+ CryptoManager cm = CryptoManager.getInstance(); -+ -+ X509Certificate[] certs = cm.findCertsByNickname(nickname); -+ for (X509Certificate cert : certs) { -+ loadCertFromNSS(pkcs12, cert, includeKey, includeChain); -+ } -+ } -+ -+ public void loadCertFromNSS(PKCS12 pkcs12, X509Certificate cert, boolean includeKey, boolean includeChain) throws Exception { -+ -+ CryptoManager cm = CryptoManager.getInstance(); -+ -+ BigInteger id = createLocalID(cert); -+ -+ // load cert info -+ loadCertInfoFromNSS(pkcs12, cert, id, true); -+ -+ if (includeKey) { -+ // load key info if exists -+ loadKeyInfoFromNSS(pkcs12, cert, id); -+ } -+ -+ if (includeChain) { -+ // load cert chain -+ X509Certificate[] certChain = cm.buildCertificateChain(cert); -+ for (int i = 1; i < certChain.length; i++) { -+ X509Certificate c = certChain[i]; -+ BigInteger cid = createLocalID(c); -+ loadCertInfoFromNSS(pkcs12, c, cid, false); -+ } -+ } -+ } -+ -+ public void loadCertInfoFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger id, boolean replace) throws Exception { -+ -+ String nickname = cert.getNickname(); -+ -+ PKCS12CertInfo certInfo = new PKCS12CertInfo(); -+ certInfo.id = id; -+ certInfo.nickname = nickname; -+ certInfo.cert = new X509CertImpl(cert.getEncoded()); -+ certInfo.trustFlags = getTrustFlags(cert); -+ -+ pkcs12.addCertInfo(certInfo, replace); -+ } -+ -+ public void loadKeyInfoFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger id) throws Exception { -+ -+ String nickname = cert.getNickname(); -+ -+ CryptoManager cm = CryptoManager.getInstance(); -+ -+ try { -+ PrivateKey privateKey = cm.findPrivKeyByCert(cert); -+ -+ PKCS12KeyInfo keyInfo = new PKCS12KeyInfo(privateKey); -+ keyInfo.id = id; -+ keyInfo.subjectDN = cert.getSubjectDN().toString(); -+ -+ pkcs12.addKeyInfo(keyInfo); -+ -+ } catch (ObjectNotFoundException e) { -+ } -+ } -+ -+ public PFX generatePFX(PKCS12 pkcs12, Password password) throws Exception { -+ -+ -+ SEQUENCE safeContents = new SEQUENCE(); -+ -+ for (PKCS12CertInfo certInfo : pkcs12.getCertInfos()) { -+ addCertBag(certInfo, safeContents); -+ } -+ -+ SEQUENCE encSafeContents = new SEQUENCE(); -+ -+ for (PKCS12KeyInfo keyInfo : pkcs12.getKeyInfos()) { -+ addKeyBag(keyInfo, password, encSafeContents); -+ } -+ -+ AuthenticatedSafes authSafes = new AuthenticatedSafes(); -+ authSafes.addSafeContents(safeContents); -+ authSafes.addSafeContents(encSafeContents); -+ -+ PFX pfx = new PFX(authSafes); -+ pfx.computeMacData(password, null, 5); -+ -+ return pfx; -+ } -+ -+ public void storeIntoFile(PKCS12 pkcs12, String filename, Password password) throws Exception { -+ -+ PFX pfx = generatePFX(pkcs12, password); -+ -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ pfx.encode(bos); -+ byte[] data = bos.toByteArray(); -+ -+ try (FileOutputStream fos = new FileOutputStream(filename)) { -+ fos.write(data); -+ } -+ } -+ -+ /** -+ * Loads key bags (for IMPORT and other operations on existing -+ * PKCS #12 files). Does not decrypt EncryptedPrivateKeyInfo -+ * values, but stores them in PKCS12KeyInfo objects for possible -+ * later use. -+ */ -+ public PKCS12KeyInfo getKeyInfo(SafeBag bag, Password password) throws Exception { -+ -+ PKCS12KeyInfo keyInfo = new PKCS12KeyInfo(bag.getBagContent().getEncoded()); -+ -+ // get key attributes -+ SET bagAttrs = bag.getBagAttributes(); -+ -+ for (int i = 0; bagAttrs != null && i < bagAttrs.size(); i++) { -+ -+ Attribute attr = (Attribute) bagAttrs.elementAt(i); -+ OBJECT_IDENTIFIER oid = attr.getType(); -+ -+ if (oid.equals(SafeBag.FRIENDLY_NAME)) { -+ -+ SET values = attr.getValues(); -+ ANY value = (ANY) values.elementAt(0); -+ -+ ByteArrayInputStream bis = new ByteArrayInputStream(value.getEncoded()); -+ BMPString subjectDN = (BMPString) new BMPString.Template().decode(bis); -+ -+ keyInfo.subjectDN = subjectDN.toString(); -+ -+ } else if (oid.equals(SafeBag.LOCAL_KEY_ID)) { -+ -+ SET values = attr.getValues(); -+ ANY value = (ANY) values.elementAt(0); -+ -+ ByteArrayInputStream bis = new ByteArrayInputStream(value.getEncoded()); -+ OCTET_STRING keyID = (OCTET_STRING) new OCTET_STRING.Template().decode(bis); -+ -+ keyInfo.id = new BigInteger(1, keyID.toByteArray()); -+ } -+ } -+ -+ return keyInfo; -+ } -+ -+ public PKCS12CertInfo getCertInfo(SafeBag bag) throws Exception { -+ -+ PKCS12CertInfo certInfo = new PKCS12CertInfo(); -+ -+ CertBag certBag = (CertBag) bag.getInterpretedBagContent(); -+ -+ OCTET_STRING certStr = (OCTET_STRING) certBag.getInterpretedCert(); -+ byte[] x509cert = certStr.toByteArray(); -+ -+ certInfo.cert = new X509CertImpl(x509cert); -+ Principal subjectDN = certInfo.cert.getSubjectDN(); -+ -+ SET bagAttrs = bag.getBagAttributes(); -+ -+ for (int i = 0; bagAttrs != null && i < bagAttrs.size(); i++) { -+ -+ Attribute attr = (Attribute) bagAttrs.elementAt(i); -+ OBJECT_IDENTIFIER oid = attr.getType(); -+ -+ if (oid.equals(SafeBag.FRIENDLY_NAME)) { -+ -+ SET values = attr.getValues(); -+ ANY value = (ANY) values.elementAt(0); -+ -+ ByteArrayInputStream bis = new ByteArrayInputStream(value.getEncoded()); -+ BMPString nickname = (BMPString) (new BMPString.Template()).decode(bis); -+ -+ certInfo.nickname = nickname.toString(); -+ -+ -+ } else if (oid.equals(SafeBag.LOCAL_KEY_ID)) { -+ -+ SET values = attr.getValues(); -+ ANY value = (ANY) values.elementAt(0); -+ -+ ByteArrayInputStream bis = new ByteArrayInputStream(value.getEncoded()); -+ OCTET_STRING keyID = (OCTET_STRING) new OCTET_STRING.Template().decode(bis); -+ -+ certInfo.id = new BigInteger(1, keyID.toByteArray()); -+ -+ } else if (oid.equals(PKCS12.CERT_TRUST_FLAGS_OID) && trustFlagsEnabled) { -+ -+ SET values = attr.getValues(); -+ ANY value = (ANY) values.elementAt(0); -+ -+ ByteArrayInputStream is = new ByteArrayInputStream(value.getEncoded()); -+ BMPString trustFlags = (BMPString) (new BMPString.Template()).decode(is); -+ -+ certInfo.trustFlags = trustFlags.toString(); -+ } -+ } -+ -+ if (certInfo.id == null) { -+ certInfo.id = createLocalID(x509cert); -+ } -+ -+ if (certInfo.nickname == null) { -+ DN dn = new DN(subjectDN.getName()); -+ String[] values = dn.explodeDN(true); -+ certInfo.nickname = StringUtils.join(values, " - "); -+ } -+ -+ return certInfo; -+ } -+ -+ public void getKeyInfos(PKCS12 pkcs12, PFX pfx, Password password) throws Exception { -+ -+ -+ AuthenticatedSafes safes = pfx.getAuthSafes(); -+ -+ for (int i = 0; i < safes.getSize(); i++) { -+ -+ SEQUENCE contents = safes.getSafeContentsAt(password, i); -+ -+ for (int j = 0; j < contents.size(); j++) { -+ -+ SafeBag bag = (SafeBag) contents.elementAt(j); -+ OBJECT_IDENTIFIER oid = bag.getBagType(); -+ -+ if (!oid.equals(SafeBag.PKCS8_SHROUDED_KEY_BAG)) continue; -+ -+ PKCS12KeyInfo keyInfo = getKeyInfo(bag, password); -+ pkcs12.addKeyInfo(keyInfo); -+ } -+ } -+ } -+ -+ public void getCertInfos(PKCS12 pkcs12, PFX pfx, Password password) throws Exception { -+ -+ -+ AuthenticatedSafes safes = pfx.getAuthSafes(); -+ -+ for (int i = 0; i < safes.getSize(); i++) { -+ -+ SEQUENCE contents = safes.getSafeContentsAt(password, i); -+ -+ for (int j = 0; j < contents.size(); j++) { -+ -+ SafeBag bag = (SafeBag) contents.elementAt(j); -+ OBJECT_IDENTIFIER oid = bag.getBagType(); -+ -+ if (!oid.equals(SafeBag.CERT_BAG)) continue; -+ -+ PKCS12CertInfo certInfo = getCertInfo(bag); -+ pkcs12.addCertInfo(certInfo, true); -+ } -+ } -+ } -+ -+ public PKCS12 loadFromFile(String filename, Password password) throws Exception { -+ -+ -+ Path path = Paths.get(filename); -+ byte[] b = Files.readAllBytes(path); -+ return loadFromByteArray(b, password); -+ } -+ -+ public PKCS12 loadFromByteArray(byte[] b, Password password) throws Exception { -+ ByteArrayInputStream bis = new ByteArrayInputStream(b); -+ -+ PFX pfx = (PFX) (new PFX.Template()).decode(bis); -+ -+ PKCS12 pkcs12 = new PKCS12(); -+ -+ StringBuffer reason = new StringBuffer(); -+ boolean valid = pfx.verifyAuthSafes(password, reason); -+ -+ if (!valid) { -+ throw new Exception("Unable to validate PKCS #12 file: " + reason); -+ } -+ -+ getKeyInfos(pkcs12, pfx, password); -+ getCertInfos(pkcs12, pfx, password); -+ -+ return pkcs12; -+ } -+ -+ public PKCS12 loadFromFile(String filename) throws Exception { -+ return loadFromFile(filename, null); -+ } -+ -+ public PrivateKey.Type getPrivateKeyType(PublicKey publicKey) { -+ if (publicKey.getAlgorithm().equals("EC")) { -+ return PrivateKey.Type.EC; -+ } -+ return PrivateKey.Type.RSA; -+ } -+ -+ public PKCS12CertInfo getCertBySubjectDN(PKCS12 pkcs12, String subjectDN) -+ throws CertificateException { -+ -+ for (PKCS12CertInfo certInfo : pkcs12.getCertInfos()) { -+ Principal certSubjectDN = certInfo.cert.getSubjectDN(); -+ if (LDAPDN.equals(certSubjectDN.toString(), subjectDN)) return certInfo; -+ } -+ -+ return null; -+ } -+ -+ public void importKey( -+ PKCS12 pkcs12, -+ Password password, -+ String nickname, -+ PKCS12KeyInfo keyInfo) throws Exception { -+ -+ -+ PKCS12CertInfo certInfo = pkcs12.getCertInfoByID(keyInfo.getID()); -+ if (certInfo == null) { -+ return; -+ } -+ -+ CryptoManager cm = CryptoManager.getInstance(); -+ CryptoToken token = cm.getInternalKeyStorageToken(); -+ CryptoStore store = token.getCryptoStore(); -+ -+ X509Certificate cert = cm.importCACertPackage(certInfo.cert.getEncoded()); -+ -+ // get public key -+ PublicKey publicKey = cert.getPublicKey(); -+ -+ byte[] epkiBytes = keyInfo.getEncryptedPrivateKeyInfoBytes(); -+ try { -+ // first true without BMPString-encoding the passphrase. -+ store.importEncryptedPrivateKeyInfo( -+ null, password, nickname, publicKey, epkiBytes); -+ } catch (Exception e) { -+ // if that failed, try again with BMPString-encoded -+ // passphrase. This is required for PKCS #12 PBE -+ // schemes and for PKCS #12 files using PBES2 generated -+ // by NSS < 3.31 -+ store.importEncryptedPrivateKeyInfo( -+ new PasswordConverter(), password, nickname, publicKey, epkiBytes); -+ } -+ -+ // delete the cert again (it will be imported again later -+ // with the correct nickname) -+ try { -+ store.deleteCert(cert); -+ } catch (NoSuchItemOnTokenException e) { -+ // this is OK -+ } -+ } -+ -+ /** -+ * Store a certificate (and key, if present) in NSSDB. -+ */ -+ public void storeCertIntoNSS( -+ PKCS12 pkcs12, Password password, -+ PKCS12CertInfo certInfo, boolean overwrite) -+ throws Exception -+ { -+ CryptoManager cm = CryptoManager.getInstance(); -+ CryptoToken ct = cm.getInternalKeyStorageToken(); -+ CryptoStore store = ct.getCryptoStore(); -+ -+ BigInteger id = certInfo.getID(); -+ PKCS12KeyInfo keyInfo = pkcs12.getKeyInfoByID(id); -+ -+ for (X509Certificate cert : cm.findCertsByNickname(certInfo.nickname)) { -+ if (!overwrite) { -+ return; -+ } -+ store.deleteCert(cert); -+ } -+ -+ X509Certificate cert; -+ if (keyInfo != null) { // cert has key -+ importKey(pkcs12, password, certInfo.nickname, keyInfo); -+ -+ cert = cm.importUserCACertPackage(certInfo.cert.getEncoded(), certInfo.nickname); -+ -+ } else { // cert has no key -+ // Note: JSS does not preserve CA certificate nickname -+ cert = cm.importCACertPackage(certInfo.cert.getEncoded()); -+ } -+ -+ if (certInfo.trustFlags != null && trustFlagsEnabled) -+ setTrustFlags(cert, certInfo.trustFlags); -+ } -+ -+ public void storeCertIntoNSS(PKCS12 pkcs12, Password password, String nickname, boolean overwrite) throws Exception { -+ Collection certInfos = pkcs12.getCertInfosByNickname(nickname); -+ for (PKCS12CertInfo certInfo : certInfos) { -+ storeCertIntoNSS(pkcs12, password, certInfo, overwrite); -+ } -+ } -+ -+ public void storeIntoNSS( -+ PKCS12 pkcs12, Password password, boolean overwrite) -+ throws Exception -+ { -+ -+ for (PKCS12CertInfo certInfo : pkcs12.getCertInfos()) { -+ storeCertIntoNSS(pkcs12, password, certInfo, overwrite); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS7.java b/org/mozilla/jss/netscape/security/pkcs/PKCS7.java -new file mode 100644 -index 00000000..dbba6265 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS7.java -@@ -0,0 +1,518 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.BufferedReader; -+import java.io.ByteArrayOutputStream; -+import java.io.DataInputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.io.PrintWriter; -+import java.io.StringReader; -+import java.io.StringWriter; -+import java.math.BigInteger; -+import java.security.NoSuchAlgorithmException; -+import java.security.SignatureException; -+import java.security.cert.CertificateException; -+import java.security.cert.X509Certificate; -+import java.util.Vector; -+ -+import org.apache.commons.codec.binary.Base64; -+ -+import org.mozilla.jss.netscape.security.util.Utils; -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.AlgorithmId; -+import org.mozilla.jss.netscape.security.x509.X500Name; -+import org.mozilla.jss.netscape.security.x509.X509CertImpl; -+ -+/** -+ * PKCS7 as defined in RSA Laboratories PKCS7 Technical Note. Profile -+ * Supports only SignedData ContentInfo -+ * type, where to the type of data signed is plain Data. -+ * For signedData, crls, attributes and -+ * PKCS#6 Extended Certificates are not supported. -+ * -+ * @version 1.33 97/12/10 -+ * @author Benjamin Renaud -+ */ -+public class PKCS7 { -+ -+ public final static String HEADER = "-----BEGIN PKCS7-----"; -+ public final static String FOOTER = "-----END PKCS7-----"; -+ -+ private ObjectIdentifier contentType; -+ -+ // the ASN.1 members for a signedData (and other) contentTypes -+ private BigInt version; -+ private AlgorithmId[] digestAlgorithmIds; -+ private ContentInfo contentInfo; -+ private X509Certificate[] certificates; -+ private SignerInfo[] signerInfos; -+ -+ /** -+ * Unmarshals a PKCS7 block from its encoded form, parsing the -+ * encoded bytes from the InputStream. -+ * -+ * @param in an input stream holding at least one PKCS7 block. -+ * @exception ParsingException on parsing errors. -+ * @exception IOException on other errors. -+ */ -+ public PKCS7(InputStream in) throws ParsingException, IOException { -+ DataInputStream dis = new DataInputStream(in); -+ -+ int len = 0; -+ byte[] newbuf = new byte[len]; -+ byte[] oldbuf = new byte[len]; -+ byte[] data = new byte[len]; -+ -+ do { -+ newbuf = new byte[dis.available()]; -+ len += dis.available(); -+ dis.readFully(newbuf); -+ data = new byte[len]; -+ -+ System.arraycopy(oldbuf, 0, data, 0, oldbuf.length); -+ System.arraycopy(newbuf, 0, data, oldbuf.length, newbuf.length); -+ oldbuf = new byte[len]; -+ System.arraycopy(data, 0, oldbuf, 0, data.length); -+ -+ } while (dis.available() > 0); -+ -+ parse(new DerInputStream(data)); -+ } -+ -+ /** -+ * Unmarshals a PKCS7 block from its encoded form, parsing the -+ * encoded bytes from the DerInputStream. -+ * -+ * @param derin a DerInputStream holding at least one PKCS7 block. -+ * @exception ParsingException on parsing errors. -+ */ -+ public PKCS7(DerInputStream derin) throws ParsingException { -+ parse(derin); -+ } -+ -+ /** -+ * Unmarshals a PKCS7 block from its encoded form, parsing the -+ * encoded bytes. -+ * -+ * @param bytes the encoded bytes. -+ * @exception ParsingException on parsing errors. -+ */ -+ public PKCS7(byte[] bytes) throws ParsingException { -+ DerInputStream derin = new DerInputStream(bytes); -+ parse(derin); -+ } -+ -+ /** -+ * Unmarshals a PKCS7 block from PEM format. -+ * -+ * @param input the PKCS7 block in PEM format. -+ * @exception ParsingException on parsing errors. -+ */ -+ public PKCS7(String input) throws ParsingException, IOException { -+ -+ StringBuilder sb = new StringBuilder(); -+ -+ try (StringReader sr = new StringReader(input.trim()); -+ BufferedReader in = new BufferedReader(sr)) { -+ -+ String line; -+ -+ // skip everything up to header -+ String header = null; -+ while ((line = in.readLine()) != null) { -+ if (HEADER.equals(line)) { -+ header = line; -+ break; -+ } -+ } -+ -+ if (header == null) { -+ throw new ParsingException("Missing PKCS #7 header"); -+ } -+ -+ // store everything up to footer -+ String footer = null; -+ while ((line = in.readLine()) != null) { -+ if (FOOTER.equals(line)) { -+ footer = line; -+ break; -+ } -+ sb.append(line); -+ } -+ -+ if (footer == null) { -+ throw new ParsingException("Missing PKCS #7 footer"); -+ } -+ } -+ -+ byte[] bytes = Base64.decodeBase64(sb.toString()); -+ parse(new DerInputStream(bytes)); -+ } -+ -+ private void parse(DerInputStream derin) throws ParsingException { -+ try { -+ ContentInfo contentInfo = new ContentInfo(derin); -+ contentType = contentInfo.contentType; -+ if (contentType.equals(ContentInfo.SIGNED_DATA_OID)) { -+ parseSignedData(contentInfo.getContent()); -+ } else { -+ throw new ParsingException("content type " + contentType + -+ " not supported."); -+ } -+ } catch (IOException e) { -+ ParsingException pe = -+ new ParsingException("IOException: " + e.getMessage()); -+ pe.fillInStackTrace(); -+ throw pe; -+ } -+ } -+ -+ /** -+ * Construct an initialized PKCS7 block. -+ * -+ * @param digestAlgorithmIds the message digest algorithm identifiers. -+ * @param contentInfo the content information. -+ * @param certificates an array of X.509 certificates. -+ * @param signerInfos an array of signer information. -+ */ -+ public PKCS7(AlgorithmId[] digestAlgorithmIds, -+ ContentInfo contentInfo, -+ X509Certificate[] certificates, -+ SignerInfo[] signerInfos) { -+ -+ version = new BigInt(1); -+ this.digestAlgorithmIds = digestAlgorithmIds; -+ this.contentInfo = contentInfo; -+ this.certificates = certificates; -+ this.signerInfos = signerInfos; -+ } -+ -+ private void parseSignedData(DerValue val) -+ throws ParsingException, IOException { -+ -+ DerInputStream dis = val.toDerInputStream(); -+ -+ // Version -+ version = dis.getInteger(); -+ -+ // digestAlgorithmIds -+ DerValue[] digestAlgorithmIdVals = dis.getSet(1); -+ int len = digestAlgorithmIdVals.length; -+ digestAlgorithmIds = new AlgorithmId[len]; -+ try { -+ for (int i = 0; i < len; i++) { -+ DerValue oid = digestAlgorithmIdVals[i]; -+ digestAlgorithmIds[i] = AlgorithmId.parse(oid); -+ } -+ -+ } catch (IOException e) { -+ ParsingException pe = -+ new ParsingException("Error parsing digest AlgorithmId IDs: " + -+ e.getMessage()); -+ pe.fillInStackTrace(); -+ throw pe; -+ } -+ // contentInfo -+ contentInfo = new ContentInfo(dis); -+ -+ /* -+ * check if certificates (implicit tag) are provided -+ * (certificates are OPTIONAL) -+ */ -+ if ((byte) (dis.peekByte()) == (byte) 0xA0) { -+ DerValue[] certificateVals = dis.getSet(2, true); -+ -+ len = certificateVals.length; -+ certificates = new X509Certificate[len]; -+ -+ for (int i = 0; i < len; i++) { -+ try { -+ X509Certificate cert = new -+ X509CertImpl(certificateVals[i]); -+ certificates[i] = cert; -+ } catch (CertificateException e) { -+ ParsingException pe = -+ new ParsingException("CertificateException: " + -+ e.getMessage()); -+ pe.fillInStackTrace(); -+ throw pe; -+ } -+ } -+ } -+ -+ // check if crls (implicit tag) are provided (crls are OPTIONAL) -+ if ((byte) (dis.peekByte()) == (byte) 0xA1) { -+ dis.getSet(0, true); -+ } -+ -+ // signerInfos -+ DerValue[] signerInfoVals = dis.getSet(1); -+ -+ len = signerInfoVals.length; -+ signerInfos = new SignerInfo[len]; -+ -+ for (int i = 0; i < len; i++) { -+ DerInputStream in = signerInfoVals[i].toDerInputStream(); -+ signerInfos[i] = new SignerInfo(in); -+ } -+ -+ } -+ -+ /** -+ * Encodes the signed data to an output stream. -+ * -+ * @param out the output stream to write the encoded data to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encodeSignedData(OutputStream out) throws IOException { -+ DerOutputStream derout = new DerOutputStream(); -+ encodeSignedData(derout, true); -+ out.write(derout.toByteArray()); -+ } -+ -+ /** -+ * Like method above but not sorted. -+ */ -+ public void encodeSignedData(OutputStream out, boolean sort) -+ throws IOException { -+ DerOutputStream derout = new DerOutputStream(); -+ encodeSignedData(derout, sort); -+ out.write(derout.toByteArray()); -+ } -+ -+ /** -+ * encode signed data, sort certs by default. -+ */ -+ public void encodeSignedData(DerOutputStream out) -+ throws IOException { -+ encodeSignedData(out, true); -+ } -+ -+ /** -+ * Encodes the signed data to a DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the encoded data to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encodeSignedData(DerOutputStream out, boolean sort) -+ throws IOException { -+ -+ DerOutputStream signedData = new DerOutputStream(); -+ -+ // version -+ signedData.putInteger(version); -+ -+ // digestAlgorithmIds -+ signedData.putOrderedSetOf(DerValue.tag_Set, digestAlgorithmIds); -+ -+ // contentInfo -+ contentInfo.encode(signedData); -+ -+ // cast to X509CertImpl[] since X509CertImpl implements DerEncoder -+ X509CertImpl implCerts[] = new X509CertImpl[certificates.length]; -+ try { -+ for (int i = 0; i < certificates.length; i++) { -+ implCerts[i] = (X509CertImpl) certificates[i]; -+ } -+ } catch (ClassCastException e) { -+ IOException ioe = -+ new IOException("Certificates in PKCS7 " + -+ "must be of class " + -+ "org.mozilla.jss.netscape.security.X509CertImpl"); -+ ioe.fillInStackTrace(); -+ } -+ -+ // Add the certificate set (tagged with [0] IMPLICIT) -+ // to the signed data -+ if (sort) { -+ signedData.putOrderedSetOf((byte) 0xA0, implCerts); -+ } else { -+ signedData.putSet((byte) 0xA0, implCerts); -+ } -+ -+ // no crls (OPTIONAL field) -+ -+ // signerInfos -+ signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos); -+ -+ // making it a signed data block -+ DerValue signedDataSeq = new DerValue(DerValue.tag_Sequence, -+ signedData.toByteArray()); -+ -+ // making it a content info sequence -+ ContentInfo block = new ContentInfo(ContentInfo.SIGNED_DATA_OID, -+ signedDataSeq); -+ -+ // writing out the contentInfo sequence -+ block.encode(out); -+ } -+ -+ /** -+ * This verifies a given SignerInfo. -+ * -+ * @param info the signer information. -+ * @param bytes the DER encoded content information. -+ * -+ * @exception NoSuchAlgorithmException on unrecognized algorithms. -+ * @exception SignatureException on signature handling errors. -+ */ -+ public SignerInfo verify(SignerInfo info, byte[] bytes) -+ throws NoSuchAlgorithmException, SignatureException { -+ return info.verify(this, bytes); -+ } -+ -+ /** -+ * Returns all signerInfos which self-verify. -+ * -+ * @param bytes the DER encoded content information. -+ * -+ * @exception NoSuchAlgorithmException on unrecognized algorithms. -+ * @exception SignatureException on signature handling errors. -+ */ -+ public SignerInfo[] verify(byte[] bytes) -+ throws NoSuchAlgorithmException, SignatureException { -+ -+ Vector intResult = new Vector(); -+ for (int i = 0; i < signerInfos.length; i++) { -+ -+ SignerInfo signerInfo = verify(signerInfos[i], bytes); -+ if (signerInfo != null) { -+ intResult.addElement(signerInfo); -+ } -+ } -+ if (intResult.size() != 0) { -+ -+ SignerInfo[] result = new SignerInfo[intResult.size()]; -+ intResult.copyInto(result); -+ return result; -+ } -+ return null; -+ } -+ -+ /** -+ * Returns all signerInfos which self-verify. -+ * -+ * @exception NoSuchAlgorithmException on unrecognized algorithms. -+ * @exception SignatureException on signature handling errors. -+ */ -+ public SignerInfo[] verify() -+ throws NoSuchAlgorithmException, SignatureException { -+ return verify(null); -+ } -+ -+ /** -+ * Returns the version number of this PKCS7 block. -+ */ -+ public BigInt getVersion() { -+ return version; -+ } -+ -+ /** -+ * Returns the message digest algorithms specified in this PKCS7 block. -+ */ -+ public AlgorithmId[] getDigestAlgorithmIds() { -+ return digestAlgorithmIds; -+ } -+ -+ /** -+ * Returns the content information specified in this PKCS7 block. -+ */ -+ public ContentInfo getContentInfo() { -+ return contentInfo; -+ } -+ -+ /** -+ * Returns the X.509 certificates listed in this PKCS7 block. -+ */ -+ public X509Certificate[] getCertificates() { -+ return certificates; -+ } -+ -+ /** -+ * Returns the signer's information specified in this PKCS7 block. -+ */ -+ public SignerInfo[] getSignerInfos() { -+ return signerInfos; -+ } -+ -+ /** -+ * Returns the X.509 certificate listed in this PKCS7 block -+ * which has a matching serial number and Issuer name, or -+ * null if one is not found. -+ * -+ * @param serial the serial number of the certificate to retrieve. -+ * @param name the Distinguished Name of the Issuer. -+ */ -+ public X509Certificate getCertificate(BigInt serial, X500Name name) { -+ -+ for (int i = 0; i < certificates.length; i++) { -+ X509Certificate cert = certificates[i]; -+ X500Name thisName = (X500Name) cert.getIssuerDN(); -+ BigInteger tmpSerial = cert.getSerialNumber(); -+ BigInt thisSerial = new BigInt(tmpSerial); -+ if (serial.equals(thisSerial) && name.equals(thisName)) { -+ return cert; -+ } -+ } -+ return null; -+ } -+ -+ public byte[] getBytes() throws IOException { -+ ByteArrayOutputStream out = new ByteArrayOutputStream(); -+ encodeSignedData(out); -+ return out.toByteArray(); -+ } -+ -+ public String toPEMString() throws IOException { -+ StringWriter sw = new StringWriter(); -+ PrintWriter pw = new PrintWriter(sw, true); -+ pw.println(HEADER); -+ pw.print(Utils.base64encode(getBytes(), true)); -+ pw.println(FOOTER); -+ return sw.toString(); -+ } -+ -+ /** -+ * Returns the PKCS7 block in a printable string form. -+ */ -+ public String toString() { -+ StringBuffer out = new StringBuffer("PKCS7 :: version: " + version + "\n"); -+ -+ out.append("PKCS7 :: digest AlgorithmIds: " + "\n"); -+ for (int i = 0; i < digestAlgorithmIds.length; i++) { -+ out.append("\t" + digestAlgorithmIds[i] + "\n"); -+ } -+ out.append(contentInfo + "\n"); -+ out.append("PKCS7 :: certificates: " + "\n"); -+ for (int i = 0; i < certificates.length; i++) { -+ out.append("\t" + i + ". " + certificates[i] + "\n"); -+ } -+ out.append("PKCS7 :: signer infos: " + "\n"); -+ for (int i = 0; i < signerInfos.length; i++) { -+ out.append("\t" + i + ". " + signerInfos[i] + "\n"); -+ } -+ return out.toString(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS8Key.java b/org/mozilla/jss/netscape/security/pkcs/PKCS8Key.java -new file mode 100644 -index 00000000..ec46df84 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS8Key.java -@@ -0,0 +1,430 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.ByteArrayInputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.math.BigInteger; -+import java.security.InvalidKeyException; -+import java.security.Key; -+import java.security.KeyFactory; -+import java.security.NoSuchAlgorithmException; -+import java.security.PrivateKey; -+import java.security.Provider; -+import java.security.Security; -+import java.security.spec.InvalidKeySpecException; -+import java.security.spec.PKCS8EncodedKeySpec; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.x509.AlgorithmId; -+ -+/** -+ * Holds a PKCS#8 key, for example a private key -+ * -+ * @version 1.30, 97/12/10 -+ * @author Dave Brownell -+ * @author Benjamin Renaud -+ */ -+public class PKCS8Key implements PrivateKey { -+ -+ /** use serialVersionUID from JDK 1.1. for interoperability */ -+ private static final long serialVersionUID = -3836890099307167124L; -+ -+ /* The algorithm information (name, parameters, etc). */ -+ protected AlgorithmId algid; -+ -+ /* The key bytes, without the algorithm information */ -+ protected byte[] key; -+ -+ /* The encoded for the key. */ -+ protected byte[] encodedKey; -+ -+ /* The version for this key */ -+ public static final BigInteger VERSION = BigInteger.valueOf(0); -+ -+ /** -+ * Default constructor. The key constructed must have its key -+ * and algorithm initialized before it may be used, for example -+ * by using decode. -+ */ -+ public PKCS8Key() { -+ } -+ -+ /** -+ * Construct PKCS#8 subject public key from a DER value. If -+ * the runtime environment is configured with a specific class for -+ * this kind of key, a subclass is returned. Otherwise, a generic -+ * PKCS8Key object is returned. -+ * -+ *

-+ * This mechanism gurantees that keys (and algorithms) may be freely manipulated and transferred, without risk of -+ * losing information. Also, when a key (or algorithm) needs some special handling, that specific need can be -+ * accomodated. -+ * -+ * @param in the DER-encoded SubjectPublicKeyInfo value -+ * @exception IOException on data format errors -+ */ -+ public static PKCS8Key parse(DerValue in) throws IOException { -+ AlgorithmId algorithm; -+ PKCS8Key subjectKey; -+ -+ if (in.tag != DerValue.tag_Sequence) -+ throw new IOException("corrupt private key"); -+ -+ BigInteger parsedVersion = in.data.getInteger().toBigInteger(); -+ if (!VERSION.equals(parsedVersion)) { -+ throw new IOException("version mismatch: (supported: " + -+ VERSION + ", parsed: " + -+ parsedVersion); -+ } -+ -+ algorithm = AlgorithmId.parse(in.data.getDerValue()); -+ -+ try { -+ subjectKey = buildPKCS8Key(algorithm, in.data.getOctetString()); -+ -+ } catch (InvalidKeyException e) { -+ throw new IOException("corrupt private key"); -+ } -+ -+ if (in.data.available() != 0) -+ throw new IOException("excess private key"); -+ return subjectKey; -+ } -+ -+ /** -+ * Parse the key bits. This may be redefined by subclasses to take -+ * advantage of structure within the key. For example, RSA public -+ * keys encapsulate two unsigned integers (modulus and exponent) as -+ * DER values within the key bits; Diffie-Hellman and -+ * DSS/DSA keys encapsulate a single unsigned integer. -+ * -+ *

-+ * This function is called when creating PKCS#8 SubjectPublicKeyInfo values using the PKCS8Key member functions, -+ * such as parse and decode. -+ * -+ * @exception IOException if a parsing error occurs. -+ * @exception InvalidKeyException if the key encoding is invalid. -+ */ -+ protected void parseKeyBits() throws IOException, InvalidKeyException { -+ encode(); -+ } -+ -+ /* -+ * Factory interface, building the kind of key associated with this -+ * specific algorithm ID or else returning this generic base class. -+ * See the description above. -+ */ -+ public static PKCS8Key buildPKCS8Key(AlgorithmId algid, byte[] key) -+ throws IOException, InvalidKeyException { -+ /* -+ * Use the algid and key parameters to produce the ASN.1 encoding -+ * of the key, which will then be used as the input to the -+ * key factory. -+ */ -+ DerOutputStream pkcs8EncodedKeyStream = new DerOutputStream(); -+ encode(pkcs8EncodedKeyStream, algid, key); -+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(pkcs8EncodedKeyStream.toByteArray()); -+ -+ try { -+ // Instantiate the key factory of the appropriate algorithm -+ KeyFactory keyFac = KeyFactory.getInstance(algid.getName()); -+ -+ // Generate the private key -+ PrivateKey privKey = keyFac.generatePrivate(pkcs8KeySpec); -+ -+ if (privKey instanceof PKCS8Key) { -+ /* -+ * Return specialized PKCS8Key, where the structure within the -+ * key has been parsed -+ */ -+ return (PKCS8Key) privKey; -+ } -+ } catch (NoSuchAlgorithmException e) { -+ // Return generic PKCS8Key with opaque key data (see below) -+ } catch (InvalidKeySpecException e) { -+ // Return generic PKCS8Key with opaque key data (see below) -+ } -+ -+ /* -+ * Try again using JDK1.1-style for backwards compatibility. -+ */ -+ String classname = ""; -+ try { -+ Provider sunProvider; -+ -+ sunProvider = Security.getProvider("SUN"); -+ if (sunProvider == null) -+ throw new InstantiationException(); -+ classname = sunProvider.getProperty("PrivateKey.PKCS#8." + -+ algid.getName()); -+ if (classname == null) { -+ throw new InstantiationException(); -+ } -+ -+ Class keyClass = Class.forName(classname); -+ Object inst; -+ PKCS8Key result; -+ -+ inst = keyClass.newInstance(); -+ if (inst instanceof PKCS8Key) { -+ result = (PKCS8Key) inst; -+ result.algid = algid; -+ result.key = key; -+ result.parseKeyBits(); -+ return result; -+ } -+ } catch (ClassNotFoundException e) { -+ } catch (InstantiationException e) { -+ } catch (IllegalAccessException e) { -+ // this should not happen. -+ throw new IOException(classname + " [internal error]"); -+ } -+ -+ PKCS8Key result = new PKCS8Key(); -+ result.algid = algid; -+ result.key = key; -+ return result; -+ } -+ -+ /** -+ * Returns the algorithm to be used with this key. -+ */ -+ public String getAlgorithm() { -+ return algid.getName(); -+ } -+ -+ /** -+ * Returns the algorithm ID to be used with this key. -+ */ -+ public AlgorithmId getAlgorithmId() { -+ return algid; -+ } -+ -+ /** -+ * PKCS#8 sequence on the DER output stream. -+ */ -+ public final void encode(DerOutputStream out) throws IOException { -+ encode(out, this.algid, this.key); -+ } -+ -+ /** -+ * Returns the DER-encoded form of the key as a byte array. -+ */ -+ public synchronized byte[] getEncoded() { -+ byte[] result = null; -+ try { -+ result = encode(); -+ } catch (InvalidKeyException e) { -+ } -+ return result; -+ } -+ -+ /** -+ * Returns the format for this key: "PKCS#8" -+ */ -+ public String getFormat() { -+ return "PKCS#8"; -+ } -+ -+ /** -+ * Returns the DER-encoded form of the key as a byte array. -+ * -+ * @exception InvalidKeyException if an encoding error occurs. -+ */ -+ public byte[] encode() throws InvalidKeyException { -+ if (encodedKey == null) { -+ try { -+ DerOutputStream out; -+ -+ out = new DerOutputStream(); -+ encode(out); -+ encodedKey = out.toByteArray(); -+ -+ } catch (IOException e) { -+ throw new InvalidKeyException("IOException : " + -+ e.getMessage()); -+ } -+ } -+ return copyEncodedKey(encodedKey); -+ } -+ -+ /* -+ * Returns a printable representation of the key -+ */ -+ public String toString() { -+ org.mozilla.jss.netscape.security.util.PrettyPrintFormat pp = -+ new org.mozilla.jss.netscape.security.util.PrettyPrintFormat(" ", 20); -+ String keybits = pp.toHexString(key); -+ -+ return "algorithm = " + algid.toString() -+ + ", unparsed keybits = \n" + keybits; -+ } -+ -+ /** -+ * Initialize an PKCS8Key object from an input stream. The data -+ * on that input stream must be encoded using DER, obeying the -+ * PKCS#8 format: a sequence consisting of a version, an algorithm -+ * ID and a bit string which holds the key. (That bit string is -+ * often used to encapsulate another DER encoded sequence.) -+ * -+ *

-+ * Subclasses should not normally redefine this method; they should instead provide a parseKeyBits -+ * method to parse any fields inside the key member. -+ * -+ * @param in an input stream with a DER-encoded PKCS#8 -+ * SubjectPublicKeyInfo value -+ * -+ * @exception InvalidKeyException if a parsing error occurs. -+ */ -+ public void decode(InputStream in) throws InvalidKeyException { -+ DerValue val; -+ -+ try { -+ val = new DerValue(in); -+ if (val.tag != DerValue.tag_Sequence) -+ throw new InvalidKeyException("invalid key format"); -+ -+ BigInteger version = val.data.getInteger().toBigInteger(); -+ if (!version.equals(PKCS8Key.VERSION)) { -+ throw new IOException("version mismatch: (supported: " + -+ PKCS8Key.VERSION + ", parsed: " + -+ version); -+ } -+ algid = AlgorithmId.parse(val.data.getDerValue()); -+ key = val.data.getOctetString(); -+ parseKeyBits(); -+ if (val.data.available() != 0) -+ throw new InvalidKeyException("excess key data"); -+ -+ } catch (IOException e) { -+ // e.printStackTrace (); -+ throw new InvalidKeyException("IOException : " + -+ e.getMessage()); -+ } -+ } -+ -+ public void decode(byte[] encodedKey) throws InvalidKeyException { -+ decode(new ByteArrayInputStream(encodedKey)); -+ } -+ -+ /** -+ * Serialization write ... PKCS#8 keys serialize as -+ * themselves, and they're parsed when they get read back. -+ */ -+ private void writeObject(java.io.ObjectOutputStream stream) throws IOException { -+ stream.write(getEncoded()); -+ } -+ -+ /** -+ * Serialization read ... PKCS#8 keys serialize as -+ * themselves, and they're parsed when they get read back. -+ */ -+ private void readObject(ObjectInputStream stream) throws IOException { -+ try { -+ decode(stream); -+ } catch (InvalidKeyException e) { -+ e.printStackTrace(); -+ throw new IOException("deserialized key is invalid: " + -+ e.getMessage()); -+ } -+ } -+ -+ /* -+ * Make a copy of the encoded key. -+ */ -+ private byte[] copyEncodedKey(byte[] encodedKey) { -+ int len = encodedKey.length; -+ byte[] copy = new byte[len]; -+ System.arraycopy(encodedKey, 0, copy, 0, len); -+ return copy; -+ } -+ -+ /* -+ * Produce PKCS#8 encoding from algorithm id and key material. -+ */ -+ static void encode(DerOutputStream out, AlgorithmId algid, byte[] key) -+ throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putInteger(new BigInt(VERSION.toByteArray())); -+ algid.encode(tmp); -+ tmp.putOctetString(key); -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+ -+ /** -+ * Compares two private keys. This returns false if the object with which -+ * to compare is not of type Key. -+ * Otherwise, the encoding of this key object is compared with the -+ * encoding of the given key object. -+ * -+ * @param object the object with which to compare -+ * @return true if this key has the same encoding as the -+ * object argument; false otherwise. -+ */ -+ public boolean equals(Object object) { -+ if (this == object) { -+ return true; -+ } -+ -+ if (object instanceof Key) { -+ -+ // this encoding -+ byte[] b1; -+ if (encodedKey != null) { -+ b1 = encodedKey; -+ } else { -+ b1 = getEncoded(); -+ } -+ -+ // that encoding -+ byte[] b2 = ((Key) object).getEncoded(); -+ -+ // do the comparison -+ int i; -+ if (b1.length != b2.length) -+ return false; -+ for (i = 0; i < b1.length; i++) { -+ if (b1[i] != b2[i]) { -+ return false; -+ } -+ } -+ return true; -+ } -+ -+ return false; -+ } -+ -+ /** -+ * Calculates a hash code value for this object. Objects -+ * which are equal will also have the same hashcode. -+ */ -+ public int hashCode() { -+ int retval = 0; -+ byte[] b1 = getEncoded(); -+ -+ for (int i = 1; i < b1.length; i++) { -+ retval += b1[i] * i; -+ } -+ return (retval); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS9Attribute.java b/org/mozilla/jss/netscape/security/pkcs/PKCS9Attribute.java -new file mode 100644 -index 00000000..41e08122 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS9Attribute.java -@@ -0,0 +1,1119 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.IOException; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Date; -+import java.util.Hashtable; -+ -+import org.mozilla.jss.netscape.security.util.DerEncoder; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.CertificateExtensions; -+ -+/** -+ * Class supporting any PKCS9 attribute except -+ * ExtendedCertificateAttribute. Supports DER decoding and access to -+ * attribute values, but not DER encoding or setting of values. -+ * -+ * @version 1.2 97/12/10 -+ * @author Douglas Hoover -+ */ -+public class PKCS9Attribute implements DerEncoder { -+ -+ /* -+ * OIDs of PKCS #9 attribute types. -+ */ -+ private static final String RSADSI_str = "1.2.840.113549"; -+ private static final String PKCS_str = RSADSI_str + ".1"; -+ private static final String PKCS9_str = PKCS_str + ".9"; -+ -+ /** -+ * Array of attribute OIDs defined in PKCS9, by number. -+ */ -+ static final ObjectIdentifier[] PKCS9_OIDS = -+ //new ObjectIdentifier[10]; -+ // There are some Obsolete(?) attribute identifiers. -+ // This is mainly for extensionRequest (14) in pkcs10. -+ // We just add the other 4 as by products. -+ new ObjectIdentifier[15]; -+ -+ static { // static initializer for PKCS9_OIDS -+ for (int i = 1; i < PKCS9_OIDS.length; i++) { -+ PKCS9_OIDS[i] = new ObjectIdentifier(PKCS9_str + "." + i); -+ } -+ } -+ -+ public static final ObjectIdentifier EMAIL_ADDRESS_OID = PKCS9_OIDS[1]; -+ public static final ObjectIdentifier UNSTRUCTURED_NAME_OID = PKCS9_OIDS[2]; -+ public static final ObjectIdentifier CONTENT_TYPE_OID = PKCS9_OIDS[3]; -+ public static final ObjectIdentifier MESSAGE_DIGEST_OID = PKCS9_OIDS[4]; -+ public static final ObjectIdentifier SIGNING_TIME_OID = PKCS9_OIDS[5]; -+ public static final ObjectIdentifier COUNTERSIGNATURE_OID = PKCS9_OIDS[6]; -+ public static final ObjectIdentifier CHALLENGE_PASSWORD_OID = PKCS9_OIDS[7]; -+ public static final ObjectIdentifier UNSTRUCTURED_ADDRESS_OID = PKCS9_OIDS[8]; -+ public static final ObjectIdentifier EXTENDED_CERTIFICATE_ATTRIBUTES_OID = PKCS9_OIDS[9]; -+ -+ public static final ObjectIdentifier ISSUER_AND_SERIALNUMBER_OID = PKCS9_OIDS[10]; -+ public static final ObjectIdentifier PASSWORD_CHECK_OID = PKCS9_OIDS[11]; -+ public static final ObjectIdentifier PUBLIC_KEY_OID = PKCS9_OIDS[12]; -+ public static final ObjectIdentifier SIGNING_DESCRIPTION_OID = PKCS9_OIDS[13]; -+ public static final ObjectIdentifier EXTENSION_REQUEST_OID = PKCS9_OIDS[14]; -+ -+ public static final String EMAIL_ADDRESS_STR = "EmailAddress"; -+ public static final String UNSTRUCTURED_NAME_STR = "UnstructuredName"; -+ public static final String CONTENT_TYPE_STR = "ContentType"; -+ public static final String MESSAGE_DIGEST_STR = "MessageDigest"; -+ public static final String SIGNING_TIME_STR = "SigningTime"; -+ public static final String COUNTERSIGNATURE_STR = "Countersignature"; -+ public static final String CHALLENGE_PASSWORD_STR = "ChallengePassword"; -+ public static final String UNSTRUCTURED_ADDRESS_STR = "UnstructuredAddress"; -+ public static final String EXTENDED_CERTIFICATE_ATTRIBUTES_STR = "ExtendedCertificateAttributes"; -+ -+ public static final String ISSUER_AND_SERIALNUMBER_STR = "IssuerAndSerialNumber"; -+ public static final String PASSWORD_CHECK_STR = "PasswordCheck"; -+ public static final String PUBLIC_KEY_STR = "PublicKey"; -+ public static final String SIGNING_DESCRIPTION_STR = "SigningDescription"; -+ public static final String EXTENSION_REQUEST_STR = "ExtensionRequest"; -+ -+ /** -+ * Hashtable mapping names and variant names of supported -+ * attributes to their OIDs. This table contains all name forms -+ * that occur in PKCS9, in lower case. -+ */ -+ private static final Hashtable NAME_OID_TABLE = new Hashtable( -+ 28); -+ -+ static { // static initializer for PCKS9_NAMES -+ NAME_OID_TABLE.put("emailaddress", PKCS9_OIDS[1]); -+ NAME_OID_TABLE.put("unstructuredname", PKCS9_OIDS[2]); -+ NAME_OID_TABLE.put("contenttype", PKCS9_OIDS[3]); -+ NAME_OID_TABLE.put("messagedigest", PKCS9_OIDS[4]); -+ NAME_OID_TABLE.put("signingtime", PKCS9_OIDS[5]); -+ NAME_OID_TABLE.put("countersignature", PKCS9_OIDS[6]); -+ NAME_OID_TABLE.put("challengepassword", PKCS9_OIDS[7]); -+ NAME_OID_TABLE.put("unstructuredaddress", PKCS9_OIDS[8]); -+ NAME_OID_TABLE.put("extendedcertificateattributes", PKCS9_OIDS[9]); -+ -+ NAME_OID_TABLE.put("issuerandserialNumber", PKCS9_OIDS[10]); -+ NAME_OID_TABLE.put("passwordcheck", PKCS9_OIDS[11]); -+ NAME_OID_TABLE.put("publickey", PKCS9_OIDS[12]); -+ NAME_OID_TABLE.put("signingdescription", PKCS9_OIDS[13]); -+ NAME_OID_TABLE.put("extensionrequest", PKCS9_OIDS[14]); -+ }; -+ -+ /** -+ * Hashtable mapping attribute OIDs defined in PKCS9 to the -+ * corresponding attribute value type. -+ */ -+ private static final Hashtable OID_NAME_TABLE = new Hashtable( -+ 14); -+ static { -+ OID_NAME_TABLE.put(PKCS9_OIDS[1], EMAIL_ADDRESS_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[2], UNSTRUCTURED_NAME_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[3], CONTENT_TYPE_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[4], MESSAGE_DIGEST_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[5], SIGNING_TIME_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[6], COUNTERSIGNATURE_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[7], CHALLENGE_PASSWORD_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[8], UNSTRUCTURED_ADDRESS_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[9], EXTENDED_CERTIFICATE_ATTRIBUTES_STR); -+ -+ OID_NAME_TABLE.put(PKCS9_OIDS[10], ISSUER_AND_SERIALNUMBER_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[11], PASSWORD_CHECK_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[12], PUBLIC_KEY_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[13], SIGNING_DESCRIPTION_STR); -+ OID_NAME_TABLE.put(PKCS9_OIDS[14], EXTENSION_REQUEST_STR); -+ } -+ -+ /** -+ * Acceptable ASN.1 tags for DER encodings of values of PKCS9 -+ * attributes, by index in PKCS9_OIDS. -+ * Sets of acceptable tags are represented as arrays. -+ */ -+ private static final Byte[][] PKCS9_VALUE_TAGS = { -+ null, -+ { Byte.valueOf(DerValue.tag_IA5String) }, // EMailAddress -+ { Byte.valueOf(DerValue.tag_IA5String) }, // UnstructuredName -+ { Byte.valueOf(DerValue.tag_ObjectId) }, // ContentType -+ { Byte.valueOf(DerValue.tag_OctetString) }, // MessageDigest -+ { Byte.valueOf(DerValue.tag_UtcTime) }, // SigningTime -+ { Byte.valueOf(DerValue.tag_Sequence) }, // Countersignature -+ { Byte.valueOf(DerValue.tag_PrintableString), -+ Byte.valueOf(DerValue.tag_T61String) }, // ChallengePassword -+ { Byte.valueOf(DerValue.tag_PrintableString), -+ Byte.valueOf(DerValue.tag_T61String) }, // UnstructuredAddress -+ { Byte.valueOf(DerValue.tag_SetOf) }, // ExtendedCertificateAttributes -+ -+ null, //IssuerAndSerialNumber -+ null, //PasswordCheck -+ null, //PublicKey -+ null, //SigningDescription -+ { Byte.valueOf(DerValue.tag_Sequence) } //ExtensionRequest -+ }; -+ -+ /** -+ * Class types required for values for a given PKCS9 -+ * attribute type. -+ * -+ *

-+ * The following table shows the correspondence between attribute types and value component classes. -+ * -+ *

-+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ *
OIDAttribute Type NameKindValue Class
1.2.840.113549.1.9.1EmailAddressMultiple-valuedString[]
1.2.840.113549.1.9.2UnstructuredNameMultiple-valuedString
1.2.840.113549.1.9.3ContentTypeSingle-valuedObjectIdentifier
1.2.840.113549.1.9.4MessageDigestSingle-valuedbyte[]
1.2.840.113549.1.9.5SigningTimeSingle-valuedDate
1.2.840.113549.1.9.6CountersignatureMultiple-valuedSignerInfo
1.2.840.113549.1.9.7ChallengePasswordSingle-valuedString
1.2.840.113549.1.9.8UnstructuredAddressSingle-valuedString
1.2.840.113549.1.9.9ExtendedCertificateAttributesMultiple-valued(not supported)
1.2.840.113549.1.9.10IssuerAndSerialNumberSingle-valued(not supported)
1.2.840.113549.1.9.11PasswordCheckSingle-valued(not supported)
1.2.840.113549.1.9.12PublicKeySingle-valued(not supported)
1.2.840.113549.1.9.13SigningDescriptionSingle-valued(not supported)
1.2.840.113549.1.9.14ExtensionRequestSingle-valuedSequence
-+ */ -+ private static final Class[] VALUE_CLASSES = new Class[15]; -+ -+ static { -+ VALUE_CLASSES[0] = null; // not used -+ VALUE_CLASSES[1] = String[].class; // EMailAddress -+ VALUE_CLASSES[2] = String[].class; // UnstructuredName -+ VALUE_CLASSES[3] = ObjectIdentifier.class; // ContentType -+ VALUE_CLASSES[4] = byte[].class; // MessageDigest (byte[]) -+ VALUE_CLASSES[5] = Date.class; // SigningTime -+ VALUE_CLASSES[6] = SignerInfo[].class; // Countersignature -+ VALUE_CLASSES[7] = String.class; // ChallengePassword -+ VALUE_CLASSES[8] = String[].class; // UnstructuredAddress -+ VALUE_CLASSES[9] = null; // ExtendedCertificateAttributes -+ -+ VALUE_CLASSES[10] = null; // IssuerAndSerialNumber -+ VALUE_CLASSES[11] = null; // PasswordCheck -+ VALUE_CLASSES[12] = null; // PublicKey -+ VALUE_CLASSES[13] = null; // SigningDescription -+ VALUE_CLASSES[14] = CertificateExtensions.class; // ExtensionRequest -+ } -+ -+ /** -+ * Array indicating which PKCS9 attributes are single-valued, -+ * by index in PKCS9_OIDS. -+ */ -+ private static final boolean[] SINGLE_VALUED = -+ { false, -+ false, // EMailAddress -+ false, // UnstructuredName -+ true, // ContentType -+ true, // MessageDigest -+ true, // SigningTime -+ false, // Countersignature -+ true, // ChallengePassword -+ false, // UnstructuredAddress -+ false, // ExtendedCertificateAttributes -+ -+ true, // IssuerAndSerialNumber -+ true, // PasswordCheck -+ true, // PublicKey -+ true, // SigningDescription -+ true // ExtensionRequest -+ }; -+ -+ /** -+ * The OID of this attribute is PKCS9_OIDS[index]. -+ */ -+ private int index; -+ -+ /** -+ * Value set of this attribute. Its class is given by VALUE_CLASSES[index]. -+ */ -+ private Object value; -+ -+ /** -+ * Construct an attribute object from the attribute's OID and -+ * value. If the attribute is single-valued, provide only one -+ * value. If the attribute is -+ * multiple-valued, provide an array containing all the values. -+ * Arrays of length zero are accepted, though probably useless. -+ * -+ *

-+ * The following table gives the class that value must have for a given attribute. -+ * -+ *

-+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ *
OIDAttribute Type NameKindValue Class
1.2.840.113549.1.9.1EmailAddressMultiple-valuedString[]
1.2.840.113549.1.9.2UnstructuredNameMultiple-valuedString[]
1.2.840.113549.1.9.3ContentTypeSingle-valuedObjectIdentifier
1.2.840.113549.1.9.4MessageDigestSingle-valuedbyte[]
1.2.840.113549.1.9.5SigningTimeSingle-valuedDate
1.2.840.113549.1.9.6CountersignatureMultiple-valuedSignerInfo[]
1.2.840.113549.1.9.7ChallengePasswordSingle-valuedString
1.2.840.113549.1.9.8UnstructuredAddressSingle-valuedString[]
1.2.840.113549.1.9.9ExtendedCertificateAttributesMultiple-valued(not supported)
1.2.840.113549.1.9.10IssuerAndSerialNumberSingle-valued(not supported)
1.2.840.113549.1.9.11PasswordCheckSingle-valued(not supported)
1.2.840.113549.1.9.12PublicKeySingle-valued(not supported)
1.2.840.113549.1.9.13SigningDescriptionSingle-valued(not supported)
1.2.840.113549.1.9.14ExtensionRequestSingle-valuedSequence
-+ */ -+ public PKCS9Attribute(ObjectIdentifier oid, Object value) -+ throws IllegalArgumentException { -+ -+ init(oid, value); -+ } -+ -+ /** -+ * Construct an attribute object from the attribute's name and -+ * value. If the attribute is single-valued, provide only one -+ * value. If the attribute is -+ * multiple-valued, provide an array containing all the values. -+ * Arrays of length zero are accepted, though probably useless. -+ * -+ *

-+ * The following table gives the class that value must have for a given attribute. Reasonable variants -+ * of these attributes are accepted; in particular, case does not matter. -+ * -+ *

-+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ *
OIDAttribute Type NameKindValue Class
1.2.840.113549.1.9.1EmailAddressMultiple-valuedString[]
1.2.840.113549.1.9.2UnstructuredNameMultiple-valuedString[]
1.2.840.113549.1.9.3ContentTypeSingle-valuedObjectIdentifier
1.2.840.113549.1.9.4MessageDigestSingle-valuedbyte[]
1.2.840.113549.1.9.5SigningTimeSingle-valuedDate
1.2.840.113549.1.9.6CountersignatureMultiple-valuedSignerInfo[]
1.2.840.113549.1.9.7ChallengePasswordSingle-valuedString
1.2.840.113549.1.9.8UnstructuredAddressSingle-valuedString[]
1.2.840.113549.1.9.9ExtendedCertificateAttributesMultiple-valued(not supported)
1.2.840.113549.1.9.10IssuerAndSerialNumberSingle-valued(not supported)
1.2.840.113549.1.9.11PasswordCheckSingle-valued(not supported)
1.2.840.113549.1.9.12PublicKeySingle-valued(not supported)
1.2.840.113549.1.9.13SigningDescriptionSingle-valued(not supported)
1.2.840.113549.1.9.14ExtensionRequestSingle-valuedSequence
-+ * -+ * @exception IllegalArgumentException -+ * if the name is not recognized of the value has the wrong type. -+ */ -+ public PKCS9Attribute(String name, Object value) -+ throws IllegalArgumentException { -+ ObjectIdentifier oid = getOID(name); -+ -+ if (oid == null) -+ throw new IllegalArgumentException( -+ "Unrecognized attribute name " + name + -+ " constructing PKCS9Attribute."); -+ -+ init(oid, value); -+ } -+ -+ private void init(ObjectIdentifier oid, Object value) -+ throws IllegalArgumentException { -+ -+ index = indexOf(oid, PKCS9_OIDS, 1); -+ -+ if (index == -1) -+ throw new IllegalArgumentException( -+ "Unsupported OID " + oid + -+ " constructing PKCS9Attribute."); -+ -+ if (!VALUE_CLASSES[index].isInstance(value)) -+ throw new IllegalArgumentException( -+ "Wrong value class " + -+ " for attribute " + oid + -+ " constructing PKCS9Attribute; was " + -+ value.getClass().toString() + ", should be " + -+ VALUE_CLASSES[index].toString()); -+ -+ this.value = value; -+ } -+ -+ /** -+ * Construct a PKCS9Attribute from its encoding on an input -+ * stream. -+ * -+ * @exception IOException on parsing error. -+ */ -+ public PKCS9Attribute(DerValue derVal) throws IOException { -+ -+ decode(derVal); -+ } -+ -+ /** -+ * Decode a PKCS9 attribute. -+ * -+ * @param val -+ * the DerValue representing the DER encoding of the attribute. -+ */ -+ private void decode(DerValue derVal) throws IOException { -+ DerInputStream derIn = new DerInputStream(derVal.toByteArray()); -+ DerValue[] val = derIn.getSequence(2); -+ -+ if (derIn.available() != 0) -+ throw new IOException("Excess data parsing PKCS9Attribute"); -+ -+ if (val.length != 2) -+ throw new IOException("PKCS9Attribute doesn't have two components"); -+ -+ DerValue[] elems; -+ -+ // get the oid -+ ObjectIdentifier oid = val[0].getOID(); -+ -+ index = indexOf(oid, PKCS9_OIDS, 1); -+ Byte tag; -+ -+ if (index == -1) -+ throw new IOException("Invalid OID for PKCS9 attribute: " + -+ oid); -+ -+ elems = new DerInputStream(val[1].toByteArray()).getSet(1); -+ -+ // check single valued have only one value -+ if (SINGLE_VALUED[index] && elems.length > 1) -+ throwSingleValuedException(); -+ -+ // check for illegal element tags -+ for (int i = 0; i < elems.length; i++) { -+ tag = Byte.valueOf(elems[i].tag); -+ -+ if (indexOf(tag, PKCS9_VALUE_TAGS[index], 0) == -1) -+ throwTagException(tag); -+ } -+ -+ switch (index) { -+ case 1: // email address -+ case 2: // unstructured name -+ case 8: // unstructured address -+ { // open scope -+ String[] values = new String[elems.length]; -+ -+ for (int i = 0; i < elems.length; i++) -+ values[i] = elems[i].getAsString(); -+ value = values; -+ } // close scope -+ break; -+ -+ case 3: // content type -+ value = elems[0].getOID(); -+ break; -+ -+ case 4: // message digest -+ value = elems[0].getOctetString(); -+ break; -+ -+ case 5: // signing time -+ value = (new DerInputStream(elems[0].toByteArray())).getUTCTime(); -+ break; -+ -+ case 6: // countersignature -+ { // open scope -+ SignerInfo[] values = new SignerInfo[elems.length]; -+ for (int i = 0; i < elems.length; i++) -+ values[i] = -+ new SignerInfo(elems[i].toDerInputStream()); -+ value = values; -+ } // close scope -+ break; -+ -+ case 7: // challenge password -+ value = elems[0].getAsString(); -+ break; -+ -+ case 9: // extended-certificate attribute -- not -+ // supported -+ throw new IOException("PKCS9 extended-certificate " + -+ "attribute not supported."); -+ -+ case 10: // IssuerAndSerialNumber attribute -- not -+ // supported -+ throw new IOException("PKCS9 IssuerAndSerialNumber " + -+ "attribute not supported."); -+ -+ case 11: // passwordCheck attribute -- not -+ // supported -+ throw new IOException("PKCS9 passwordCheck " + -+ "attribute not supported."); -+ case 12: // PublicKey attribute -- not -+ // supported -+ throw new IOException("PKCS9 PublicKey " + -+ "attribute not supported."); -+ case 13: // SigningDescription attribute -- not -+ // supported -+ throw new IOException("PKCS9 SigningDescription " + -+ "attribute not supported."); -+ case 14: // ExtensionRequest attribute -+ value = -+ new CertificateExtensions(elems[0].toDerInputStream()); -+ -+ // break unnecessary -+ -+ default: // can't happen -+ } -+ -+ } -+ -+ /** -+ * Write the DER encoding of this attribute to an output stream. -+ * -+ *

-+ * N.B.: This method always encodes values of ChallengePassword and UnstructuredAddress attributes as ASN.1 -+ * PrintableStrings, without checking whether they should be encoded as T61Strings. -+ */ -+ public void derEncode(OutputStream out) throws IOException { -+ try (DerOutputStream temp = new DerOutputStream(); -+ DerOutputStream temp2 = new DerOutputStream(); -+ DerOutputStream derOut = new DerOutputStream()) { -+ temp.putOID(getOID()); -+ switch (index) { -+ case 1: // email address -+ case 2: // unstructured name -+ { // open scope -+ String[] values = (String[]) value; -+ DerOutputStream[] temps = new -+ DerOutputStream[values.length]; -+ -+ for (int i = 0; i < values.length; i++) { -+ temps[i] = new DerOutputStream(); -+ -+ temps[i].putIA5String(values[i]); -+ } -+ temp.putOrderedSetOf(DerValue.tag_Set, temps); -+ } // close scope -+ break; -+ -+ case 3: // content type -+ { -+ temp2.putOID((ObjectIdentifier) value); -+ temp.write(DerValue.tag_Set, temp2.toByteArray()); -+ } -+ break; -+ -+ case 4: // message digest -+ { -+ temp2.putOctetString((byte[]) value); -+ temp.write(DerValue.tag_Set, temp2.toByteArray()); -+ } -+ break; -+ -+ case 5: // signing time -+ { -+ temp2.putUTCTime((Date) value); -+ temp.write(DerValue.tag_Set, temp2.toByteArray()); -+ } -+ break; -+ -+ case 6: // countersignature -+ temp.putOrderedSetOf(DerValue.tag_Set, (DerEncoder[]) value); -+ break; -+ -+ case 7: // challenge password -+ { -+ temp2.putPrintableString((String) value); -+ temp.write(DerValue.tag_Set, temp2.toByteArray()); -+ } -+ break; -+ -+ case 8: // unstructured address -+ { // open scope -+ String[] values = (String[]) value; -+ DerOutputStream[] temps = new -+ DerOutputStream[values.length]; -+ -+ for (int i = 0; i < values.length; i++) { -+ temps[i] = new DerOutputStream(); -+ -+ temps[i].putPrintableString(values[i]); -+ } -+ temp.putOrderedSetOf(DerValue.tag_Set, temps); -+ } // close scope -+ break; -+ -+ case 9: // extended-certificate attribute -- not -+ // supported -+ throw new IOException("PKCS9 extended-certificate " + -+ "attribute not supported."); -+ -+ case 10: // IssuerAndSerialNumber attribute -- not -+ // supported -+ throw new IOException("PKCS9 IssuerAndSerialNumber " + -+ "attribute not supported."); -+ -+ case 11: // passwordCheck attribute -- not -+ // supported -+ throw new IOException("PKCS9 passwordCheck " + -+ "attribute not supported."); -+ case 12: // PublicKey attribute -- not -+ // supported -+ throw new IOException("PKCS9 PublicKey " + -+ "attribute not supported."); -+ case 13: // SigningDescription attribute -- not -+ // supported -+ throw new IOException("PKCS9 SigningDescription " + -+ "attribute not supported."); -+ case 14: // ExtensionRequest attribute -+ try { -+ //temp2.putSequence((CertificateExtensions) value); -+ ((CertificateExtensions) value).encode(temp2); -+ temp.write(DerValue.tag_Sequence, temp2.toByteArray()); -+ } catch (CertificateException e) { -+ throw new IOException("PKCS9 extension attributes not encoded"); -+ } -+ -+ // break unnecessary -+ default: // can't happen -+ } -+ -+ derOut.write(DerValue.tag_Sequence, temp.toByteArray()); -+ -+ out.write(derOut.toByteArray()); -+ } -+ } -+ -+ /** -+ * Get the value of this attribute. If the attribute is -+ * single-valued, return just the one value. If the attribute is -+ * multiple-valued, return an array containing all the values. -+ * It is possible for this array to be of length 0. -+ * -+ *

-+ * The following table gives the class of the value returned, depending on the type of this attribute. -+ * -+ *

-+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ *
OIDAttribute Type NameKindValue Class
1.2.840.113549.1.9.1EmailAddressMultiple-valuedString[]
1.2.840.113549.1.9.2UnstructuredNameMultiple-valuedString[]
1.2.840.113549.1.9.3ContentTypeSingle-valuedObjectIdentifier
1.2.840.113549.1.9.4MessageDigestSingle-valuedbyte[]
1.2.840.113549.1.9.5SigningTimeSingle-valuedDate
1.2.840.113549.1.9.6CountersignatureMultiple-valuedSignerInfo[]
1.2.840.113549.1.9.7ChallengePasswordSingle-valuedString
1.2.840.113549.1.9.8UnstructuredAddressSingle-valuedString[]
1.2.840.113549.1.9.9ExtendedCertificateAttributesMultiple-valued(not supported)
1.2.840.113549.1.9.10IssuerAndSerialNumberSingle-valued(not supported)
1.2.840.113549.1.9.11PasswordCheckSingle-valued(not supported)
1.2.840.113549.1.9.12PublicKeySingle-valued(not supported)
1.2.840.113549.1.9.13SigningDescriptionSingle-valued(not supported)
1.2.840.113549.1.9.14ExtensionRequestSingle-valuedSequence
-+ * -+ */ -+ public Object getValue() { -+ return value; -+ } -+ -+ /** -+ * Show whether this attribute is single-valued. -+ */ -+ public boolean isSingleValued() { -+ return SINGLE_VALUED[index]; -+ } -+ -+ /** -+ * Return the OID of this attribute. -+ */ -+ public ObjectIdentifier getOID() { -+ return PKCS9_OIDS[index]; -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return OID_NAME_TABLE.get(PKCS9_OIDS[index]); -+ } -+ -+ /** -+ * Return the OID for a given attribute name or null if we don't recognize -+ * the name. -+ */ -+ public static ObjectIdentifier getOID(String name) { -+ return NAME_OID_TABLE.get(name.toLowerCase()); -+ } -+ -+ /** -+ * Return the attribute name for a given OID or null if we don't recognize -+ * the oid. -+ */ -+ public static String getName(ObjectIdentifier oid) { -+ return OID_NAME_TABLE.get(oid); -+ } -+ -+ /** -+ * Returns a string representation of this attribute. -+ */ -+ public String toString() { -+ StringBuffer buf = new StringBuffer(100); -+ -+ buf.append("["); -+ -+ buf.append(OID_NAME_TABLE.get(PKCS9_OIDS[index])); -+ buf.append(": "); -+ -+ if (SINGLE_VALUED[index]) { -+ if (value instanceof byte[]) { // special case for octet string -+ org.mozilla.jss.netscape.security.util.PrettyPrintFormat pp = -+ new org.mozilla.jss.netscape.security.util.PrettyPrintFormat(" ", 20); -+ String valuebits = pp.toHexString(((byte[]) value)); -+ buf.append(valuebits); -+ } else { -+ buf.append(value.toString()); -+ } -+ buf.append("]"); -+ return buf.toString(); -+ } else { // multiple-valued -+ boolean first = true; -+ Object[] values = (Object[]) value; -+ -+ for (int j = 0; j < values.length; j++) { -+ if (first) -+ first = false; -+ else -+ buf.append(", "); -+ -+ buf.append(values[j].toString()); -+ } -+ return buf.toString(); -+ } -+ } -+ -+ /** -+ * Beginning the search at start, find the first -+ * index i such that a[i] = obj. -+ * -+ * @return the index, if found, and -1 otherwise. -+ */ -+ static int indexOf(Object obj, Object[] a, int start) { -+ for (int i = start; i < a.length; i++) { -+ if (obj.equals(a[i])) -+ return i; -+ } -+ return -1; -+ } -+ -+ /** -+ * Throw an exception when there are multiple values for -+ * a single-valued attribute. -+ */ -+ private void throwSingleValuedException() throws IOException { -+ throw new IOException("Single-value attribute " + -+ getOID() + " (" + getName() + ")" + -+ " has multiple values."); -+ } -+ -+ /** -+ * Throw an exception when the tag on a value encoding is -+ * wrong for the attribute whose value it is. -+ */ -+ private void throwTagException(Byte tag) -+ throws IOException { -+ Byte[] expectedTags = PKCS9_VALUE_TAGS[index]; -+ StringBuffer msg = new StringBuffer(100); -+ msg.append("Value of attribute "); -+ msg.append(getOID().toString()); -+ msg.append(" ("); -+ msg.append(getName()); -+ msg.append(") has wrong tag: "); -+ msg.append(tag.toString()); -+ msg.append(". Expected tags: "); -+ -+ msg.append(expectedTags[0].toString()); -+ -+ for (int i = 1; i < expectedTags.length; i++) { -+ msg.append(", "); -+ msg.append(expectedTags[i].toString()); -+ } -+ msg.append("."); -+ throw new IOException(msg.toString()); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/PKCS9Attributes.java b/org/mozilla/jss/netscape/security/pkcs/PKCS9Attributes.java -new file mode 100644 -index 00000000..412fece4 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/PKCS9Attributes.java -@@ -0,0 +1,313 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.IOException; -+import java.io.OutputStream; -+import java.util.Hashtable; -+ -+import org.mozilla.jss.netscape.security.util.DerEncoder; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * A set of attributes of class PKCS9Attribute. -+ * -+ * @version 1.2 97/12/10 -+ * @author Douglas Hoover -+ */ -+public class PKCS9Attributes { -+ -+ /** -+ * Attributes in this set indexed by OID. -+ */ -+ private final Hashtable attributes = new Hashtable(3); -+ -+ /** -+ * The keys of this hashtable are the OIDs of permitted attributes. -+ */ -+ private final Hashtable permittedAttributes; -+ -+ /** -+ * The DER encoding of this attribute set. The tag byte must be -+ * DerValue.tag_SetOf. -+ */ -+ private final byte[] derEncoding; -+ -+ /** -+ * Construct a set of PKCS9 Attributes from its -+ * DER encoding on a DerInputStream, accepting only attributes -+ * with OIDs on the given -+ * list. If the array is null, accept all attributes supported by -+ * class PKCS9Attribute. -+ * -+ * @param permittedAttributes -+ * Array of attribute OIDs that will be accepted. -+ * @param buf -+ * the contents of the DER encoding of the attribute set. -+ * -+ * @exception IOException -+ * on i/o error, encoding syntax error, unacceptable or -+ * unsupported attribute, or duplicate attribute. -+ * -+ * @see PKCS9Attribute -+ */ -+ public PKCS9Attributes(ObjectIdentifier[] permittedAttributes, -+ DerInputStream in) throws IOException { -+ if (permittedAttributes != null) { -+ this.permittedAttributes = -+ new Hashtable(permittedAttributes.length); -+ -+ for (int i = 0; i < permittedAttributes.length; i++) -+ this.permittedAttributes.put(permittedAttributes[i], -+ permittedAttributes[i]); -+ } else { -+ this.permittedAttributes = null; -+ } -+ -+ // derEncoding initialized in decode() -+ derEncoding = decode(in); -+ } -+ -+ /** -+ * Construct a set of PKCS9 Attributes from its contents of its -+ * DER encoding on a DerInputStream. Accept all attributes -+ * supported by class PKCS9Attribute. -+ * -+ * @exception IOException -+ * on i/o error, encoding syntax error, or unsupported or -+ * duplicate attribute. -+ * -+ * @see PKCS9Attribute -+ */ -+ public PKCS9Attributes(DerInputStream in) throws IOException { -+ // anything goes -+ // derEncoding initialized in decode() -+ derEncoding = decode(in); -+ permittedAttributes = null; -+ } -+ -+ /** -+ * Construct a set of PKCS9 Attributes from the given array of -+ * PCK9 attributes. -+ * DER encoding on a DerInputStream. All attributes in attribs must be -+ * supported by class PKCS9Attribute. -+ * -+ * @exception IOException -+ * on i/o error, encoding syntax error, or unsupported or -+ * duplicate attribute. -+ * -+ * @see PKCS9Attribute -+ */ -+ public PKCS9Attributes(PKCS9Attribute[] attribs) -+ throws IllegalArgumentException, IOException { -+ ObjectIdentifier oid; -+ for (int i = 0; i < attribs.length; i++) { -+ oid = attribs[i].getOID(); -+ if (attributes.containsKey(oid)) -+ throw new IllegalArgumentException( -+ "PKCSAttribute " + attribs[i].getOID() + -+ " duplicated while constructing " + -+ "PKCS9Attributes."); -+ -+ attributes.put(oid, attribs[i]); -+ } -+ derEncoding = generateDerEncoding(); -+ permittedAttributes = null; -+ } -+ -+ /** -+ * Decode this set of PKCS9 attribute set from the contents of its -+ * DER encoding. -+ * -+ * @param buf -+ * the contents of the DER encoding of the attribute set. -+ * -+ * @exception IOException -+ * on i/o error, encoding syntax error, unacceptable or -+ * unsupported attribute, or duplicate attribute. -+ */ -+ private byte[] decode(DerInputStream in) throws IOException { -+ -+ DerValue val = in.getDerValue(); -+ -+ // save the DER encoding with its proper tag byte. -+ byte[] derEncoding = val.toByteArray(); -+ derEncoding[0] = DerValue.tag_SetOf; -+ -+ DerInputStream derIn = new DerInputStream(derEncoding); -+ DerValue[] derVals = derIn.getSet(3, true); -+ -+ PKCS9Attribute attrib; -+ ObjectIdentifier oid; -+ -+ for (int i = 0; i < derVals.length; i++) { -+ attrib = new PKCS9Attribute(derVals[i]); -+ oid = attrib.getOID(); -+ -+ if (attributes.get(oid) != null) -+ throw new IOException("Duplicate PKCS9 attribute: " + oid); -+ -+ if (permittedAttributes != null && -+ !permittedAttributes.containsKey(oid)) -+ throw new IOException("Attribute " + oid + -+ " not permitted in this attribute set"); -+ -+ attributes.put(oid, attrib); -+ } -+ return derEncoding; -+ -+ } -+ -+ /** -+ * Put the DER encoding of this PKCS9 attribute set on an -+ * DerOutputStream, tagged with the given implicit tag. -+ * -+ * @param tag the implicit tag to use in the DER encoding. -+ * @param out the output stream on which to put the DER encoding. -+ * -+ * @exception IOException on output error. -+ */ -+ public void encode(byte tag, OutputStream out) throws IOException { -+ out.write(tag); -+ out.write(derEncoding, 1, derEncoding.length - 1); -+ } -+ -+ private byte[] generateDerEncoding() throws IOException { -+ try (DerOutputStream out = new DerOutputStream()) { -+ Object[] attribVals = attributes.values().toArray(); -+ -+ out.putOrderedSetOf(DerValue.tag_SetOf, -+ castToDerEncoder(attribVals)); -+ return out.toByteArray(); -+ } -+ } -+ -+ /** -+ * Return the DER encoding of this attribute set, tagged with -+ * DerValue.tag_SetOf. -+ */ -+ public byte[] getDerEncoding() throws IOException { -+ return derEncoding.clone(); -+ -+ } -+ -+ /** -+ * Get an attribute from this set. -+ */ -+ public PKCS9Attribute getAttribute(ObjectIdentifier oid) { -+ return attributes.get(oid); -+ } -+ -+ /** -+ * Get an attribute from this set. -+ */ -+ public PKCS9Attribute getAttribute(String name) { -+ return attributes.get(PKCS9Attribute.getOID(name)); -+ } -+ -+ /** -+ * Get an array of all attributes in this set, in order of OID. -+ */ -+ public PKCS9Attribute[] getAttributes() { -+ PKCS9Attribute[] attribs = new PKCS9Attribute[attributes.size()]; -+ -+ int j = 0; -+ for (int i = 1; i < PKCS9Attribute.PKCS9_OIDS.length && -+ j < attribs.length; i++) { -+ attribs[j] = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]); -+ -+ if (attribs[j] != null) -+ j++; -+ } -+ return attribs; -+ } -+ -+ /** -+ * Get an attribute value by OID. -+ */ -+ public Object getAttributeValue(ObjectIdentifier oid) -+ throws IOException { -+ try { -+ Object value = getAttribute(oid).getValue(); -+ return value; -+ } catch (NullPointerException ex) { -+ throw new IOException("No value found for attribute " + oid); -+ } -+ -+ } -+ -+ /** -+ * Get an attribute value by type name. -+ */ -+ public Object getAttributeValue(String name) throws IOException { -+ ObjectIdentifier oid = PKCS9Attribute.getOID(name); -+ -+ if (oid == null) -+ throw new IOException("Attribute name " + name + -+ " not recognized or not supported."); -+ -+ return getAttributeValue(oid); -+ } -+ -+ /** -+ * Returns the PKCS9 block in a printable string form. -+ */ -+ public String toString() { -+ StringBuffer buf = new StringBuffer(200); -+ buf.append("PKCS9 Attributes: [\n\t"); -+ -+ PKCS9Attribute value; -+ -+ boolean first = true; -+ for (int i = 1; i < PKCS9Attribute.PKCS9_OIDS.length; i++) { -+ value = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]); -+ -+ if (value == null) -+ continue; -+ -+ // we have a value; print it -+ if (first) -+ first = false; -+ else -+ buf.append(";\n\t"); -+ -+ buf.append(value.toString()); -+ } -+ -+ buf.append("\n\t] (end PKCS9 Attributes)"); -+ -+ return buf.toString(); -+ } -+ -+ /** -+ * Cast an object array whose components are DerEncoders to DerEncoder[]. -+ */ -+ static DerEncoder[] castToDerEncoder(Object[] objs) { -+ -+ DerEncoder[] encoders = new DerEncoder[objs.length]; -+ -+ for (int i = 0; i < encoders.length; i++) -+ encoders[i] = (DerEncoder) objs[i]; -+ -+ return encoders; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/ParsingException.java b/org/mozilla/jss/netscape/security/pkcs/ParsingException.java -new file mode 100644 -index 00000000..90676d3c ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/ParsingException.java -@@ -0,0 +1,35 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.IOException; -+ -+public class ParsingException extends IOException { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -8135726194372647410L; -+ -+ public ParsingException() { -+ super(); -+ } -+ -+ public ParsingException(String s) { -+ super(s); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/SignerInfo.java b/org/mozilla/jss/netscape/security/pkcs/SignerInfo.java -new file mode 100644 -index 00000000..436ed35f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/SignerInfo.java -@@ -0,0 +1,348 @@ -+// --- 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 org.mozilla.jss.netscape.security.pkcs; -+ -+import java.io.IOException; -+import java.io.OutputStream; -+import java.security.InvalidKeyException; -+import java.security.MessageDigest; -+import java.security.NoSuchAlgorithmException; -+import java.security.PublicKey; -+import java.security.Signature; -+import java.security.SignatureException; -+import java.security.cert.X509Certificate; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerEncoder; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.AlgorithmId; -+import org.mozilla.jss.netscape.security.x509.X500Name; -+ -+/** -+ * A SignerInfo, as defined in PKCS#7's signedData type. -+ * -+ * @author Benjamin Renaud -+ * @version 1.27 97/12/10 -+ */ -+public class SignerInfo implements DerEncoder { -+ -+ BigInt version; -+ X500Name issuerName; -+ BigInt certificateSerialNumber; -+ AlgorithmId digestAlgorithmId; -+ AlgorithmId digestEncryptionAlgorithmId; -+ byte[] encryptedDigest; -+ -+ PKCS9Attributes authenticatedAttributes; -+ PKCS9Attributes unauthenticatedAttributes; -+ -+ public SignerInfo(X500Name issuerName, -+ BigInt serial, -+ AlgorithmId digestAlgorithmId, -+ AlgorithmId digestEncryptionAlgorithmId, -+ byte[] encryptedDigest) { -+ this.version = new BigInt(1); -+ this.issuerName = issuerName; -+ this.certificateSerialNumber = serial; -+ this.digestAlgorithmId = digestAlgorithmId; -+ this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmId; -+ this.encryptedDigest = encryptedDigest; -+ } -+ -+ public SignerInfo(X500Name issuerName, -+ BigInt serial, -+ AlgorithmId digestAlgorithmId, -+ PKCS9Attributes authenticatedAttributes, -+ AlgorithmId digestEncryptionAlgorithmId, -+ byte[] encryptedDigest, -+ PKCS9Attributes unauthenticatedAttributes) { -+ this.version = new BigInt(1); -+ this.issuerName = issuerName; -+ this.certificateSerialNumber = serial; -+ this.digestAlgorithmId = digestAlgorithmId; -+ this.authenticatedAttributes = authenticatedAttributes; -+ this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmId; -+ this.encryptedDigest = encryptedDigest; -+ this.unauthenticatedAttributes = unauthenticatedAttributes; -+ } -+ -+ public SignerInfo(DerInputStream derin) -+ throws IOException, ParsingException { -+ -+ // version -+ version = derin.getInteger(); -+ -+ // issuerAndSerialNumber -+ DerValue[] issuerAndSerialNumber = derin.getSequence(2); -+ byte[] issuerBytes = issuerAndSerialNumber[0].toByteArray(); -+ issuerName = new X500Name(new DerValue(DerValue.tag_Sequence, -+ issuerBytes)); -+ certificateSerialNumber = issuerAndSerialNumber[1].getInteger(); -+ -+ // digestAlgorithmId -+ DerValue tmp = derin.getDerValue(); -+ -+ digestAlgorithmId = AlgorithmId.parse(tmp); -+ -+ /* -+ * check if set of auth attributes (implicit tag) is provided -+ * (auth attributes are OPTIONAL) -+ */ -+ if ((byte) (derin.peekByte()) == (byte) 0xA0) { -+ authenticatedAttributes = new PKCS9Attributes(derin); -+ } -+ -+ // digestEncryptionAlgorithmId - little RSA naming scheme - -+ // signature == encryption... -+ tmp = derin.getDerValue(); -+ -+ digestEncryptionAlgorithmId = AlgorithmId.parse(tmp); -+ -+ // encryptedDigest -+ encryptedDigest = derin.getOctetString(); -+ -+ /* -+ * check if set of unauth attributes (implicit tag) is provided -+ * (unauth attributes are OPTIONAL) -+ */ -+ if (derin.available() != 0 && (byte) (derin.peekByte()) == (byte) 0xA1) { -+ unauthenticatedAttributes = new PKCS9Attributes(derin); -+ } -+ -+ // all done -+ if (derin.available() != 0) { -+ throw new ParsingException("extra data at the end"); -+ } -+ } -+ -+ public void encode(DerOutputStream out) throws IOException { -+ -+ derEncode(out); -+ } -+ -+ /** -+ * DER encode this object onto an output stream. -+ * Implements the DerEncoder interface. -+ * -+ * @param out -+ * the output stream on which to write the DER encoding. -+ * -+ * @exception IOException on encoding error. -+ */ -+ public void derEncode(OutputStream out) throws IOException { -+ try (DerOutputStream tmp = new DerOutputStream()) { -+ DerOutputStream seq = new DerOutputStream(); -+ seq.putInteger(version); -+ DerOutputStream issuerAndSerialNumber = new DerOutputStream(); -+ issuerName.encode(issuerAndSerialNumber); -+ issuerAndSerialNumber.putInteger(certificateSerialNumber); -+ seq.write(DerValue.tag_Sequence, issuerAndSerialNumber); -+ -+ digestAlgorithmId.encode(seq); -+ -+ // encode authenticated attributes if there are any -+ if (authenticatedAttributes != null) -+ authenticatedAttributes.encode((byte) 0xA0, seq); -+ -+ digestEncryptionAlgorithmId.encode(seq); -+ -+ seq.putOctetString(encryptedDigest); -+ -+ // encode unauthenticated attributes if there are any -+ if (unauthenticatedAttributes != null) -+ unauthenticatedAttributes.encode((byte) 0xA1, seq); -+ -+ tmp.write(DerValue.tag_Sequence, seq); -+ -+ out.write(tmp.toByteArray()); -+ } -+ } -+ -+ public X509Certificate getCertificate(PKCS7 block) -+ throws IOException { -+ return block.getCertificate(certificateSerialNumber, issuerName); -+ } -+ -+ /* Returns null if verify fails, this signerInfo if -+ verify succeeds. */ -+ SignerInfo verify(PKCS7 block, byte[] data) -+ throws NoSuchAlgorithmException, SignatureException { -+ -+ try { -+ -+ ContentInfo content = block.getContentInfo(); -+ if (data == null) { -+ data = content.getContentBytes(); -+ } -+ -+ String digestAlgname = -+ getDigestAlgorithmId().getName(); -+ -+ byte[] dataSigned; -+ -+ // if there are authenticate attributes, get the message -+ // digest and compare it with the digest of data -+ if (authenticatedAttributes == null) { -+ dataSigned = data; -+ } else { -+ -+ // first, check content type -+ ObjectIdentifier contentType = (ObjectIdentifier) -+ authenticatedAttributes.getAttributeValue( -+ PKCS9Attribute.CONTENT_TYPE_OID); -+ if (contentType == null || -+ !contentType.equals(content.contentType)) -+ return null; // contentType does not match, bad SignerInfo -+ -+ // now, check message digest -+ byte[] messageDigest = (byte[]) -+ authenticatedAttributes.getAttributeValue( -+ PKCS9Attribute.MESSAGE_DIGEST_OID); -+ -+ if (messageDigest == null) // fail if there is no message digest -+ return null; -+ -+ MessageDigest md = MessageDigest.getInstance(digestAlgname); -+ byte[] computedMessageDigest = md.digest(data); -+ -+ if (messageDigest.length != computedMessageDigest.length) -+ return null; -+ for (int i = 0; i < messageDigest.length; i++) { -+ if (messageDigest[i] != computedMessageDigest[i]) -+ return null; -+ } -+ -+ // message digest attribute matched -+ // digest of original data -+ -+ // the data actually signed is the DER encoding of -+ // the authenticated attributes (tagged with -+ // the "SET OF" tag, not 0xA0). -+ dataSigned = authenticatedAttributes.getDerEncoding(); -+ } -+ -+ // put together digest algorithm and encryption algorithm -+ // to form signing algorithm -+ String encryptionAlgname = -+ getDigestEncryptionAlgorithmId().getName(); -+ -+ String algname; -+ if (encryptionAlgname.equals("DSA") || -+ encryptionAlgname.equals("SHA1withDSA")) { -+ algname = "DSA"; -+ } else { -+ algname = digestAlgname + "/" + encryptionAlgname; -+ } -+ -+ Signature sig = Signature.getInstance(algname); -+ X509Certificate cert = getCertificate(block); -+ -+ if (cert == null) { -+ return null; -+ } -+ -+ PublicKey key = cert.getPublicKey(); -+ sig.initVerify(key); -+ -+ sig.update(dataSigned); -+ -+ if (sig.verify(encryptedDigest)) { -+ return this; -+ } -+ -+ } catch (IOException e) { -+ throw new SignatureException("IO error verifying signature:\n" + -+ e.getMessage()); -+ -+ } catch (InvalidKeyException e) { -+ throw new SignatureException("InvalidKey: " + e.getMessage()); -+ -+ } -+ return null; -+ } -+ -+ /* Verify the content of the pkcs7 block. */ -+ SignerInfo verify(PKCS7 block) -+ throws NoSuchAlgorithmException, SignatureException { -+ return verify(block, null); -+ } -+ -+ public BigInt getVersion() { -+ return version; -+ } -+ -+ public X500Name getIssuerName() { -+ return issuerName; -+ } -+ -+ public BigInt getCertificateSerialNumber() { -+ return certificateSerialNumber; -+ } -+ -+ public AlgorithmId getDigestAlgorithmId() { -+ return digestAlgorithmId; -+ } -+ -+ public PKCS9Attributes getAuthenticatedAttributes() { -+ return authenticatedAttributes; -+ } -+ -+ public AlgorithmId getDigestEncryptionAlgorithmId() { -+ return digestEncryptionAlgorithmId; -+ } -+ -+ public byte[] getEncryptedDigest() { -+ return encryptedDigest; -+ } -+ -+ public PKCS9Attributes getUnauthenticatedAttributes() { -+ return unauthenticatedAttributes; -+ } -+ -+ public String toString() { -+ org.mozilla.jss.netscape.security.util.PrettyPrintFormat pp = -+ new org.mozilla.jss.netscape.security.util.PrettyPrintFormat(" ", 20); -+ String digestbits = pp.toHexString(encryptedDigest); -+ -+ String out = ""; -+ -+ out += "Signer Info for (issuer): " + issuerName + "\n"; -+ out += "\tversion: " + version + "\n"; -+ out += "\tcertificateSerialNumber: " + certificateSerialNumber + -+ "\n"; -+ out += "\tdigestAlgorithmId: " + digestAlgorithmId + "\n"; -+ if (authenticatedAttributes != null) { -+ out += "\tauthenticatedAttributes: " + authenticatedAttributes + -+ "\n"; -+ } -+ out += "\tdigestEncryptionAlgorithmId: " + digestEncryptionAlgorithmId + -+ "\n"; -+ -+ out += "\tencryptedDigest: " + "\n" + -+ digestbits + "\n"; -+ if (unauthenticatedAttributes != null) { -+ out += "\tunauthenticatedAttributes: " + -+ unauthenticatedAttributes + "\n"; -+ } -+ return out; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/pkcs/manifest.mn b/org/mozilla/jss/netscape/security/pkcs/manifest.mn -new file mode 100644 -index 00000000..38720420 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/pkcs/manifest.mn -@@ -0,0 +1,8 @@ -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+CORE_DEPTH = ../../../../../.. -+PACKAGE = org/mozilla/jss/netscape/security/pkcs -+MODULE = jss -diff --git a/org/mozilla/jss/netscape/security/provider/CMS.java b/org/mozilla/jss/netscape/security/provider/CMS.java -new file mode 100644 -index 00000000..e0a2a8be ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/CMS.java -@@ -0,0 +1,52 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.security.AccessController; -+import java.security.Provider; -+ -+/** -+ * The CMS Security Provider. -+ */ -+ -+public final class CMS extends Provider { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 1065207998900104219L; -+ private static final String INFO = "CMS " + -+ "(DSA key/parameter generation; DSA signing; " + -+ "SHA-1, MD5 digests; SecureRandom; X.509 certificates)"; -+ -+ public CMS() { -+ /* We are the SUN provider */ -+ super("CMS", 1.0, INFO); -+ -+ AccessController.doPrivileged(new java.security.PrivilegedAction() { -+ public Object run() { -+ /* -+ * Certificates -+ */ -+ put("CertificateFactory.X.509", "org.mozilla.jss.netscape.security.provider.X509CertificateFactory"); -+ put("Alg.Alias.CertificateFactory.X.509", "X.509"); -+ return null; -+ } -+ }); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/provider/DSA.java b/org/mozilla/jss/netscape/security/provider/DSA.java -new file mode 100644 -index 00000000..e7f155ea ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/DSA.java -@@ -0,0 +1,661 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.io.IOException; -+import java.io.PrintStream; -+import java.math.BigInteger; -+import java.security.InvalidKeyException; -+import java.security.InvalidParameterException; -+import java.security.MessageDigest; -+import java.security.NoSuchAlgorithmException; -+import java.security.PrivateKey; -+import java.security.PublicKey; -+import java.security.SecureRandom; -+import java.security.Signature; -+import java.security.SignatureException; -+import java.security.interfaces.DSAParams; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * The Digital Signature Standard (using the Digital Signature -+ * Algorithm), as described in fips186 of the National Instute of -+ * Standards and Technology (NIST), using fips180-1 (SHA-1). -+ * -+ * @author Benjamin Renaud -+ * -+ * @version 1.86, 97/09/17 -+ * -+ * @see DSAPublicKey -+ * @see DSAPrivateKey -+ */ -+ -+public final class DSA extends Signature { -+ -+ /* Are we debugging? */ -+ private static boolean debug = false; -+ -+ /* The parameter object */ -+ @SuppressWarnings("unused") -+ private DSAParams params; -+ -+ /* algorithm parameters */ -+ private BigInteger presetP, presetQ, presetG; -+ -+ /* The public key, if any */ -+ private BigInteger presetY; -+ -+ /* The private key, if any */ -+ private BigInteger presetX; -+ -+ /* The SHA hash for the data */ -+ private MessageDigest dataSHA; -+ -+ /* The random seed used to generate k */ -+ private int[] Kseed; -+ -+ /* The random seed used to generate k (specified by application) */ -+ private byte[] KseedAsByteArray; -+ -+ /* -+ * The random seed used to generate k -+ * (prevent the same Kseed from being used twice in a row -+ */ -+ private int[] previousKseed; -+ -+ /* The RNG used to output a seed for generating k */ -+ private SecureRandom signingRandom; -+ -+ /** -+ * Construct a blank DSA object. It can generate keys, but must be -+ * initialized before being usable for signing or verifying. -+ */ -+ public DSA() throws NoSuchAlgorithmException { -+ super("SHA/DSA"); -+ dataSHA = MessageDigest.getInstance("SHA"); -+ } -+ -+ /** -+ * Initialize the DSA object with a DSA private key. -+ * -+ * @param privateKey the DSA private key -+ * -+ * @exception InvalidKeyException if the key is not a valid DSA private -+ * key. -+ */ -+ protected void engineInitSign(PrivateKey privateKey) -+ throws InvalidKeyException { -+ if (!(privateKey instanceof java.security.interfaces.DSAPrivateKey)) { -+ throw new InvalidKeyException("not a DSA private key: " + -+ privateKey); -+ } -+ java.security.interfaces.DSAPrivateKey priv = -+ (java.security.interfaces.DSAPrivateKey) privateKey; -+ -+ this.presetX = priv.getX(); -+ initialize(priv.getParams()); -+ } -+ -+ /** -+ * Initialize the DSA object with a DSA public key. -+ * -+ * @param publicKey the DSA public key. -+ * -+ * @exception InvalidKeyException if the key is not a valid DSA public -+ * key. -+ */ -+ protected void engineInitVerify(PublicKey publicKey) -+ throws InvalidKeyException { -+ if (!(publicKey instanceof java.security.interfaces.DSAPublicKey)) { -+ throw new InvalidKeyException("not a DSA public key: " + -+ publicKey); -+ } -+ java.security.interfaces.DSAPublicKey pub = -+ (java.security.interfaces.DSAPublicKey) publicKey; -+ this.presetY = pub.getY(); -+ initialize(pub.getParams()); -+ } -+ -+ private void initialize(DSAParams params) { -+ dataSHA.reset(); -+ setParams(params); -+ } -+ -+ /** -+ * Sign all the data thus far updated. The signature is formatted -+ * according to the Canonical Encoding Rules, returned as a DER -+ * sequence of Integer, r and s. -+ * -+ * @return a signature block formatted according to the Canonical -+ * Encoding Rules. -+ * -+ * @exception SignatureException if the signature object was not -+ * properly initialized, or if another exception occurs. -+ * -+ * @see org.mozilla.jss.netscape.security.provider.DSA#engineUpdate -+ * @see org.mozilla.jss.netscape.security.provider.DSA#engineVerify -+ */ -+ protected byte[] engineSign() throws SignatureException { -+ BigInteger k = generateK(presetQ); -+ BigInteger r = generateR(presetP, presetQ, presetG, k); -+ BigInteger s = generateS(presetX, presetQ, r, k); -+ -+ // got to convert to BigInt... -+ BigInt rAsBigInt = new BigInt(r.toByteArray()); -+ BigInt sAsBigInt = new BigInt(s.toByteArray()); -+ -+ try (DerOutputStream outseq = new DerOutputStream(100)) { -+ outseq.putInteger(rAsBigInt); -+ outseq.putInteger(sAsBigInt); -+ DerValue result = new DerValue(DerValue.tag_Sequence, -+ outseq.toByteArray()); -+ -+ return result.toByteArray(); -+ -+ } catch (IOException e) { -+ throw new SignatureException("error encoding signature"); -+ } -+ } -+ -+ /** -+ * Verify all the data thus far updated. -+ * -+ * @param signature the alledged signature, encoded using the -+ * Canonical Encoding Rules, as a sequence of integers, r and s. -+ * -+ * @exception SignatureException if the signature object was not -+ * properly initialized, or if another exception occurs. -+ * -+ * @see org.mozilla.jss.netscape.security.provider.DSA#engineUpdate -+ * @see org.mozilla.jss.netscape.security.provider.DSA#engineSign -+ */ -+ protected boolean engineVerify(byte[] signature) -+ throws SignatureException { -+ -+ BigInteger r = null; -+ BigInteger s = null; -+ // first decode the signature. -+ try { -+ DerInputStream in = new DerInputStream(signature); -+ DerValue[] values = in.getSequence(2); -+ -+ r = values[0].getInteger().toBigInteger(); -+ s = values[1].getInteger().toBigInteger(); -+ -+ } catch (IOException e) { -+ throw new SignatureException("invalid encoding for signature"); -+ } -+ BigInteger w = generateW(presetP, presetQ, presetG, s); -+ BigInteger v = generateV(presetY, presetP, presetQ, presetG, w, r); -+ -+ return v.equals(r); -+ } -+ -+ BigInteger generateR(BigInteger p, BigInteger q, BigInteger g, -+ BigInteger k) { -+ BigInteger temp = g.modPow(k, p); -+ return temp.remainder(q); -+ -+ } -+ -+ BigInteger generateS(BigInteger x, BigInteger q, -+ BigInteger r, BigInteger k) { -+ -+ byte[] s2 = dataSHA.digest(); -+ BigInteger temp = new BigInteger(1, s2); -+ BigInteger k1 = k.modInverse(q); -+ -+ BigInteger s = x.multiply(r); -+ s = temp.add(s); -+ s = k1.multiply(s); -+ return s.remainder(q); -+ } -+ -+ BigInteger generateW(BigInteger p, BigInteger q, -+ BigInteger g, BigInteger s) { -+ return s.modInverse(q); -+ } -+ -+ BigInteger generateV(BigInteger y, BigInteger p, -+ BigInteger q, BigInteger g, -+ BigInteger w, BigInteger r) { -+ -+ byte[] s2 = dataSHA.digest(); -+ BigInteger temp = new BigInteger(1, s2); -+ -+ temp = temp.multiply(w); -+ BigInteger u1 = temp.remainder(q); -+ -+ BigInteger u2 = (r.multiply(w)).remainder(q); -+ -+ BigInteger t1 = g.modPow(u1, p); -+ BigInteger t2 = y.modPow(u2, p); -+ BigInteger t3 = t1.multiply(t2); -+ BigInteger t5 = t3.remainder(p); -+ return t5.remainder(q); -+ } -+ -+ /* -+ * Please read bug report 4044247 for an alternative, faster, -+ * NON-FIPS approved method to generate K -+ */ -+ BigInteger generateK(BigInteger q) { -+ -+ BigInteger k = null; -+ -+ // The application specified a Kseed for us to use. -+ // Note that we do not allow usage of the same Kseed twice in a row -+ if (Kseed != null && compareSeeds(Kseed, previousKseed) != 0) { -+ k = generateK(Kseed, q); -+ if (k.signum() > 0 && k.compareTo(q) < 0) { -+ previousKseed = new int[Kseed.length]; -+ System.arraycopy(Kseed, 0, previousKseed, 0, Kseed.length); -+ return k; -+ } -+ } -+ -+ // The application did not specify a Kseed for us to use. -+ // We'll generate a new Kseed by getting random bytes from -+ // a SecureRandom object. -+ SecureRandom random = getSigningRandom(); -+ -+ while (true) { -+ int[] seed = new int[5]; -+ -+ for (int i = 0; i < 5; i++) -+ seed[i] = random.nextInt(); -+ k = generateK(seed, q); -+ if (k.signum() > 0 && k.compareTo(q) < 0) { -+ previousKseed = new int[seed.length]; -+ System.arraycopy(seed, 0, previousKseed, 0, seed.length); -+ return k; -+ } -+ } -+ } -+ -+ // Use the application-specified SecureRandom Object if provided. -+ // Otherwise, use our default SecureRandom Object. -+ private SecureRandom getSigningRandom() { -+ if (signingRandom == null) { -+ if (appRandom != null) -+ signingRandom = appRandom; -+ else -+ signingRandom = new SecureRandom(); -+ } -+ return signingRandom; -+ } -+ -+ /* -+ * return 0 if equal -+ * return 1 if not equal -+ */ -+ private int compareSeeds(int[] seed1, int[] seed2) { -+ -+ if (seed1 == null || seed2 == null) { -+ return 1; -+ } -+ if (seed1.length != seed2.length) { -+ return 1; -+ } -+ -+ for (int i = 0; i < seed1.length; i++) { -+ if (seed1[i] != seed2[i]) -+ return 1; -+ } -+ -+ return 0; -+ -+ } -+ -+ /** -+ * Compute k for a DSA signature. -+ * -+ * @param seed the seed for generating k. This seed should be -+ * secure. This is what is refered to as the KSEED in the DSA -+ * specification. -+ * -+ * @param g the g parameter from the DSA key pair. -+ */ -+ BigInteger generateK(int[] seed, BigInteger q) { -+ -+ // check out t in the spec. -+ int[] t = { 0xEFCDAB89, 0x98BADCFE, 0x10325476, -+ 0xC3D2E1F0, 0x67452301 }; -+ // -+ int[] tmp = DSA.SHA_7(seed, t); -+ byte[] tmpBytes = new byte[tmp.length * 4]; -+ for (int i = 0; i < tmp.length; i++) { -+ int k = tmp[i]; -+ for (int j = 0; j < 4; j++) { -+ tmpBytes[(i * 4) + j] = (byte) (k >>> (24 - (j * 8))); -+ } -+ } -+ BigInteger k = new BigInteger(1, tmpBytes).mod(q); -+ return k; -+ } -+ -+ // Constants for each round -+ private static final int round1_kt = 0x5a827999; -+ private static final int round2_kt = 0x6ed9eba1; -+ private static final int round3_kt = 0x8f1bbcdc; -+ private static final int round4_kt = 0xca62c1d6; -+ -+ /** -+ * Computes set 1 thru 7 of SHA-1 on m1. -+ */ -+ static int[] SHA_7(int[] m1, int[] h) { -+ -+ int[] W = new int[80]; -+ System.arraycopy(m1, 0, W, 0, m1.length); -+ int temp = 0; -+ -+ for (int t = 16; t <= 79; t++) { -+ temp = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; -+ W[t] = ((temp << 1) | (temp >>> (32 - 1))); -+ } -+ -+ int a = h[0], b = h[1], c = h[2], d = h[3], e = h[4]; -+ for (int i = 0; i < 20; i++) { -+ temp = ((a << 5) | (a >>> (32 - 5))) + -+ ((b & c) | ((~b) & d)) + e + W[i] + round1_kt; -+ e = d; -+ d = c; -+ c = ((b << 30) | (b >>> (32 - 30))); -+ b = a; -+ a = temp; -+ } -+ -+ // Round 2 -+ for (int i = 20; i < 40; i++) { -+ temp = ((a << 5) | (a >>> (32 - 5))) + -+ (b ^ c ^ d) + e + W[i] + round2_kt; -+ e = d; -+ d = c; -+ c = ((b << 30) | (b >>> (32 - 30))); -+ b = a; -+ a = temp; -+ } -+ -+ // Round 3 -+ for (int i = 40; i < 60; i++) { -+ temp = ((a << 5) | (a >>> (32 - 5))) + -+ ((b & c) | (b & d) | (c & d)) + e + W[i] + round3_kt; -+ e = d; -+ d = c; -+ c = ((b << 30) | (b >>> (32 - 30))); -+ b = a; -+ a = temp; -+ } -+ -+ // Round 4 -+ for (int i = 60; i < 80; i++) { -+ temp = ((a << 5) | (a >>> (32 - 5))) + -+ (b ^ c ^ d) + e + W[i] + round4_kt; -+ e = d; -+ d = c; -+ c = ((b << 30) | (b >>> (32 - 30))); -+ b = a; -+ a = temp; -+ } -+ int[] md = new int[5]; -+ md[0] = h[0] + a; -+ md[1] = h[1] + b; -+ md[2] = h[2] + c; -+ md[3] = h[3] + d; -+ md[4] = h[4] + e; -+ return md; -+ } -+ -+ /** -+ * This implementation recognizes the following parameter: -+ *
-+ * -+ *
Kseed -+ * -+ *
a byte array. -+ * -+ *
-+ * -+ * @deprecated -+ */ -+ protected void engineSetParameter(String key, Object param) { -+ -+ if (key.equals("KSEED")) { -+ -+ if (param instanceof byte[]) { -+ -+ Kseed = byteArray2IntArray((byte[]) param); -+ KseedAsByteArray = (byte[]) param; -+ -+ } else { -+ debug("unrecognized param: " + key); -+ throw new InvalidParameterException("Kseed not a byte array"); -+ } -+ -+ } else { -+ throw new InvalidParameterException("invalid parameter"); -+ } -+ } -+ -+ /** -+ * Return the value of the requested parameter. Recognized -+ * parameters are: -+ * -+ *
-+ * -+ *
Kseed -+ * -+ *
a byte array. -+ * -+ *
-+ * -+ * @return the value of the requested parameter. -+ * -+ * @deprecated -+ */ -+ protected Object engineGetParameter(String key) { -+ if (key.equals("KSEED")) { -+ return KseedAsByteArray; -+ } else { -+ return null; -+ } -+ } -+ -+ /** -+ * Set the algorithm object. -+ */ -+ private void setParams(DSAParams params) { -+ this.params = params; -+ this.presetP = params.getP(); -+ this.presetQ = params.getQ(); -+ this.presetG = params.getG(); -+ } -+ -+ /** -+ * Update a byte to be signed or verified. -+ * -+ * @param b the byte to updated. -+ */ -+ protected void engineUpdate(byte b) { -+ dataSHA.update(b); -+ } -+ -+ /** -+ * Update an array of bytes to be signed or verified. -+ * -+ * @param data the bytes to be updated. -+ */ -+ protected void engineUpdate(byte[] data, int off, int len) { -+ dataSHA.update(data, off, len); -+ } -+ -+ /** -+ * Return a human readable rendition of the engine. -+ */ -+ public String toString() { -+ String printable = "DSA Signature"; -+ if (presetP != null && presetQ != null && presetG != null) { -+ printable += "\n\tp: " + presetP.toString(16); -+ printable += "\n\tq: " + presetQ.toString(16); -+ printable += "\n\tg: " + presetG.toString(16); -+ } else { -+ printable += "\n\t P, Q or G not initialized."; -+ } -+ if (presetY != null) { -+ printable += "\n\ty: " + presetY.toString(16); -+ } -+ if (presetY == null && presetX == null) { -+ printable += "\n\tUNINIIALIZED"; -+ } -+ return printable; -+ } -+ -+ /* -+ * Utility routine for converting a byte array into an int array -+ */ -+ private int[] byteArray2IntArray(byte[] byteArray) { -+ -+ int j = 0; -+ byte[] newBA; -+ int mod = byteArray.length % 4; -+ -+ // guarantee that the incoming byteArray is a multiple of 4 -+ // (pad with 0's) -+ switch (mod) { -+ case 3: -+ newBA = new byte[byteArray.length + 1]; -+ break; -+ case 2: -+ newBA = new byte[byteArray.length + 2]; -+ break; -+ case 1: -+ newBA = new byte[byteArray.length + 3]; -+ break; -+ default: -+ newBA = new byte[byteArray.length + 0]; -+ break; -+ } -+ System.arraycopy(byteArray, 0, newBA, 0, byteArray.length); -+ -+ // copy each set of 4 bytes in the byte array into an integer -+ int[] newSeed = new int[newBA.length / 4]; -+ for (int i = 0; i < newBA.length; i += 4) { -+ newSeed[j] = newBA[i + 3] & 0xFF; -+ newSeed[j] |= (newBA[i + 2] << 8) & 0xFF00; -+ newSeed[j] |= (newBA[i + 1] << 16) & 0xFF0000; -+ newSeed[j] |= (newBA[i + 0] << 24) & 0xFF000000; -+ j++; -+ } -+ -+ return newSeed; -+ } -+ -+ /* We include the test vectors from the DSA specification, FIPS -+ 186, and the FIPS 186 Change No 1, which updates the test -+ vector using SHA-1 instead of SHA (for both the G function and -+ the message hash. */ -+ -+ static void testDSA() throws Exception { -+ PrintStream p = System.out; -+ -+ DSA dsa = new DSA(); -+ int[] Kseed = { 0x687a66d9, 0x0648f993, 0x867e121f, -+ 0x4ddf9ddb, 0x1205584 }; -+ BigInteger k = dsa.generateK(Kseed, q512); -+ p.println("k: " + k.toString(16)); -+ BigInteger r = dsa.generateR(p512, q512, g512, k); -+ p.println("r: " + r.toString(16)); -+ byte[] abc = { 0x61, 0x62, 0x63 }; -+ dsa.dataSHA.update(abc); -+ BigInteger s = dsa.generateS(x512, q512, r, k); -+ p.println("s: " + s.toString(16)); -+ -+ dsa.dataSHA.update(abc); -+ BigInteger w = dsa.generateW(p512, q512, g512, s); -+ p.println("w: " + w.toString(16)); -+ BigInteger v = dsa.generateV(y512, p512, q512, g512, w, r); -+ p.println("v: " + v.toString(16)); -+ if (v.equals(r)) { -+ p.println("signature verifies."); -+ } else { -+ p.println("signature does not verify."); -+ } -+ } -+ -+ /* Test vector: 512-bit keys generated by our key generator. */ -+ -+ static BigInteger p512 = -+ new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecb" + -+ "cd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e1" + -+ "2ed0899bcd132acd50d99151bdc43ee737592e17", 16); -+ -+ static BigInteger q512 = -+ new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16); -+ -+ static BigInteger g512 = -+ new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a43" + -+ "4d6486931d2d14271b9e35030b71fd73da179069b32e" + -+ "2935630e1c2062354d0da20a6c416e50be794ca4", 16); -+ -+ static BigInteger x512 = -+ new BigInteger("3406c2d71b04b5fc0db62afcad58a6607d3de688", 16); -+ -+ static BigInteger y512 = -+ new BigInteger("2d335d76b8ec9d610aa8f2cbb4b149fd96fdd" + -+ "3a9a6e62bd6c2e01d406be4d1d72718a2fe08bea6d12f5e452474461f70f4" + -+ "dea60508e9fe2eaec23d2ec5d1a866", 16); -+ -+ /* Official NIST 512-bit test keys */ -+ -+ static String pString = "8df2a494492276aa3d25759bb06869cbeac0d83afb8d0" + -+ "cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec" + -+ "0736ee31c80291"; -+ -+ static BigInteger testP = new BigInteger(pString, 16); -+ -+ static String gString = "626d027839ea0a13413163a55b4cb500299d5522956ce" + -+ "fcb3bff10f399ce2c2e71cb9de5fa24babf58e5b79521925c9cc42e9f6f464b088cc5" + -+ "72af53e6d78802"; -+ -+ static BigInteger testG = new BigInteger(gString, 16); -+ -+ static BigInteger testQ = new BigInteger("c773218c737ec8ee993b4f2ded30" + -+ "f48edace915f", 16); -+ -+ static BigInteger testX = new BigInteger("2070b3223dba372fde1c0ffc7b2e" + -+ "3b498b260614", 16); -+ -+ static String yString = "19131871d75b1612a819f29d78d1b0d7346f7aa77" + -+ "bb62a859bfd6c5675da9d212d3a36ef1672ef660b8c7c255cc0ec74858fba33f44c06" + -+ "699630a76b030ee333"; -+ -+ static BigInteger testY = new BigInteger(yString, 16); -+ -+ /* End test vector values */ -+ -+ private static void debug(String s) { -+ if (debug) { -+ System.err.println(s); -+ } -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/provider/DSAKeyFactory.java b/org/mozilla/jss/netscape/security/provider/DSAKeyFactory.java -new file mode 100755 -index 00000000..ec24e8f0 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/DSAKeyFactory.java -@@ -0,0 +1,232 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.security.InvalidKeyException; -+import java.security.Key; -+import java.security.KeyFactorySpi; -+import java.security.PrivateKey; -+import java.security.PublicKey; -+import java.security.interfaces.DSAParams; -+import java.security.spec.DSAPrivateKeySpec; -+import java.security.spec.DSAPublicKeySpec; -+import java.security.spec.InvalidKeySpecException; -+import java.security.spec.KeySpec; -+import java.security.spec.PKCS8EncodedKeySpec; -+import java.security.spec.X509EncodedKeySpec; -+ -+/** -+ * This class implements the DSA key factory of the Sun provider. -+ * -+ * @author Jan Luehe -+ * -+ * @version 1.8, 97/12/10 -+ * -+ * @since JDK1.2 -+ */ -+ -+public class DSAKeyFactory extends KeyFactorySpi { -+ -+ /** -+ * Generates a public key object from the provided key specification -+ * (key material). -+ * -+ * @param keySpec the specification (key material) of the public key -+ * -+ * @return the public key -+ * -+ * @exception InvalidKeySpecException if the given key specification -+ * is inappropriate for this key factory to produce a public key. -+ */ -+ protected PublicKey engineGeneratePublic(KeySpec keySpec) -+ throws InvalidKeySpecException { -+ try { -+ if (keySpec instanceof DSAPublicKeySpec) { -+ DSAPublicKeySpec dsaPubKeySpec = (DSAPublicKeySpec) keySpec; -+ return new DSAPublicKey(dsaPubKeySpec.getY(), -+ dsaPubKeySpec.getP(), -+ dsaPubKeySpec.getQ(), -+ dsaPubKeySpec.getG()); -+ -+ } else if (keySpec instanceof X509EncodedKeySpec) { -+ return new DSAPublicKey(((X509EncodedKeySpec) keySpec).getEncoded()); -+ -+ } else { -+ throw new InvalidKeySpecException("Inappropriate key specification"); -+ } -+ } catch (InvalidKeyException e) { -+ throw new InvalidKeySpecException("Inappropriate key specification: " + e.getMessage()); -+ } -+ } -+ -+ /** -+ * Generates a private key object from the provided key specification -+ * (key material). -+ * -+ * @param keySpec the specification (key material) of the private key -+ * -+ * @return the private key -+ * -+ * @exception InvalidKeySpecException if the given key specification -+ * is inappropriate for this key factory to produce a private key. -+ */ -+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) -+ throws InvalidKeySpecException { -+ try { -+ if (keySpec instanceof DSAPrivateKeySpec) { -+ DSAPrivateKeySpec dsaPrivKeySpec = (DSAPrivateKeySpec) keySpec; -+ return new DSAPrivateKey(dsaPrivKeySpec.getX(), -+ dsaPrivKeySpec.getP(), -+ dsaPrivKeySpec.getQ(), -+ dsaPrivKeySpec.getG()); -+ -+ } else if (keySpec instanceof PKCS8EncodedKeySpec) { -+ return new DSAPrivateKey(((PKCS8EncodedKeySpec) keySpec).getEncoded()); -+ -+ } else { -+ throw new InvalidKeySpecException("Inappropriate key specification"); -+ } -+ } catch (InvalidKeyException e) { -+ throw new InvalidKeySpecException("Inappropriate key specification: " + e.getMessage()); -+ } -+ } -+ -+ /** -+ * Returns a specification (key material) of the given key object -+ * in the requested format. -+ * -+ * @param key the key -+ * -+ * @param keySpec the requested format in which the key material shall be -+ * returned -+ * -+ * @return the underlying key specification (key material) in the -+ * requested format -+ * -+ * @exception InvalidKeySpecException if the requested key specification is -+ * inappropriate for the given key, or the given key cannot be processed -+ * (e.g., the given key has an unrecognized algorithm or format). -+ */ -+ @SuppressWarnings("unchecked") -+ protected T engineGetKeySpec(Key key, Class keySpec) -+ throws InvalidKeySpecException { -+ -+ DSAParams params; -+ -+ try { -+ -+ if (key instanceof java.security.interfaces.DSAPublicKey) { -+ -+ // Determine valid key specs -+ Class dsaPubKeySpec = Class.forName -+ ("java.security.spec.DSAPublicKeySpec"); -+ Class x509KeySpec = Class.forName -+ ("java.security.spec.X509EncodedKeySpec"); -+ -+ if (dsaPubKeySpec.isAssignableFrom(keySpec)) { -+ java.security.interfaces.DSAPublicKey dsaPubKey = (java.security.interfaces.DSAPublicKey) key; -+ params = dsaPubKey.getParams(); -+ return (T) new DSAPublicKeySpec(dsaPubKey.getY(), -+ params.getP(), -+ params.getQ(), -+ params.getG()); -+ -+ } else if (x509KeySpec.isAssignableFrom(keySpec)) { -+ return (T) new X509EncodedKeySpec(key.getEncoded()); -+ -+ } else { -+ throw new InvalidKeySpecException("Inappropriate key specification"); -+ } -+ -+ } else if (key instanceof java.security.interfaces.DSAPrivateKey) { -+ -+ // Determine valid key specs -+ Class dsaPrivKeySpec = Class.forName -+ ("java.security.spec.DSAPrivateKeySpec"); -+ Class pkcs8KeySpec = Class.forName -+ ("java.security.spec.PKCS8EncodedKeySpec"); -+ -+ if (dsaPrivKeySpec.isAssignableFrom(keySpec)) { -+ java.security.interfaces.DSAPrivateKey dsaPrivKey = (java.security.interfaces.DSAPrivateKey) key; -+ params = dsaPrivKey.getParams(); -+ return (T) new DSAPrivateKeySpec(dsaPrivKey.getX(), -+ params.getP(), -+ params.getQ(), -+ params.getG()); -+ -+ } else if (pkcs8KeySpec.isAssignableFrom(keySpec)) { -+ return (T) new PKCS8EncodedKeySpec(key.getEncoded()); -+ -+ } else { -+ throw new InvalidKeySpecException("Inappropriate key specification"); -+ } -+ -+ } else { -+ throw new InvalidKeySpecException("Inappropriate key type"); -+ } -+ -+ } catch (ClassNotFoundException e) { -+ throw new InvalidKeySpecException("Unsupported key specification: " + e.getMessage()); -+ } -+ } -+ -+ /** -+ * Translates a key object, whose provider may be unknown or potentially -+ * untrusted, into a corresponding key object of this key factory. -+ * -+ * @param key the key whose provider is unknown or untrusted -+ * -+ * @return the translated key -+ * -+ * @exception InvalidKeyException if the given key cannot be processed by -+ * this key factory. -+ */ -+ protected Key engineTranslateKey(Key key) throws InvalidKeyException { -+ -+ try { -+ -+ if (key instanceof java.security.interfaces.DSAPublicKey) { -+ // Check if key originates from this factory -+ if (key instanceof org.mozilla.jss.netscape.security.provider.DSAPublicKey) { -+ return key; -+ } -+ // Convert key to spec -+ DSAPublicKeySpec dsaPubKeySpec = engineGetKeySpec(key, DSAPublicKeySpec.class); -+ // Create key from spec, and return it -+ return engineGeneratePublic(dsaPubKeySpec); -+ -+ } else if (key instanceof java.security.interfaces.DSAPrivateKey) { -+ // Check if key originates from this factory -+ if (key instanceof org.mozilla.jss.netscape.security.provider.DSAPrivateKey) { -+ return key; -+ } -+ // Convert key to spec -+ DSAPrivateKeySpec dsaPrivKeySpec = engineGetKeySpec(key, DSAPrivateKeySpec.class); -+ // Create key from spec, and return it -+ return engineGeneratePrivate(dsaPrivKeySpec); -+ -+ } else { -+ throw new InvalidKeyException("Wrong algorithm type"); -+ } -+ -+ } catch (InvalidKeySpecException e) { -+ throw new InvalidKeyException("Cannot translate key: " -+ + e.getMessage()); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/provider/DSAKeyPairGenerator.java b/org/mozilla/jss/netscape/security/provider/DSAKeyPairGenerator.java -new file mode 100644 -index 00000000..c4942dea ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/DSAKeyPairGenerator.java -@@ -0,0 +1,389 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.math.BigInteger; -+import java.security.AlgorithmParameterGenerator; -+import java.security.InvalidAlgorithmParameterException; -+import java.security.InvalidKeyException; -+import java.security.InvalidParameterException; -+import java.security.KeyPair; -+import java.security.KeyPairGenerator; -+import java.security.NoSuchAlgorithmException; -+import java.security.NoSuchProviderException; -+import java.security.ProviderException; -+import java.security.SecureRandom; -+import java.security.interfaces.DSAParams; -+import java.security.spec.AlgorithmParameterSpec; -+import java.security.spec.DSAParameterSpec; -+import java.security.spec.InvalidParameterSpecException; -+import java.util.Hashtable; -+ -+import org.mozilla.jss.netscape.security.x509.AlgIdDSA; -+ -+/** -+ * This class generates DSA key parameters and public/private key -+ * pairs according to the DSS standard NIST FIPS 186. It uses the -+ * updated version of SHA, SHA-1 as described in FIPS 180-1. -+ * -+ * @author Benjamin Renaud -+ * -+ * @version 1.23, 97/12/10 -+ */ -+ -+public class DSAKeyPairGenerator extends KeyPairGenerator -+ implements java.security.interfaces.DSAKeyPairGenerator { -+ -+ private static Hashtable precomputedParams; -+ -+ static { -+ -+ /* We support precomputed parameter for 512, 768 and 1024 bit -+ moduli. In this file we provide both the seed and counter -+ value of the generation process for each of these seeds, -+ for validation purposes. We also include the test vectors -+ from the DSA specification, FIPS 186, and the FIPS 186 -+ Change No 1, which updates the test vector using SHA-1 -+ instead of SHA (for both the G function and the message -+ hash. -+ */ -+ -+ precomputedParams = new Hashtable(); -+ -+ /* -+ * L = 512 -+ * SEED = b869c82b35d70e1b1ff91b28e37a62ecdc34409b -+ * counter = 123 -+ */ -+ BigInteger p512 = -+ new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecb" + -+ "cd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e1" + -+ "2ed0899bcd132acd50d99151bdc43ee737592e17", 16); -+ -+ BigInteger q512 = -+ new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16); -+ -+ BigInteger g512 = -+ new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a43" + -+ "4d6486931d2d14271b9e35030b71fd73da179069b32e" + -+ "2935630e1c2062354d0da20a6c416e50be794ca4", 16); -+ -+ /* -+ * L = 768 -+ * SEED = 77d0f8c4dad15eb8c4f2f8d6726cefd96d5bb399 -+ * counter = 263 -+ */ -+ BigInteger p768 = -+ new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e" + -+ "927b3a9670fbec5d890141922d2c3b3ad24800937" + -+ "99869d1e846aab49fab0ad26d2ce6a22219d470bc" + -+ "e7d777d4a21fbe9c270b57f607002f3cef8393694" + -+ "cf45ee3688c11a8c56ab127a3daf", 16); -+ -+ BigInteger q768 = -+ new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", -+ 16); -+ -+ BigInteger g768 = -+ new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5fac" + -+ "baecbe95f190aa7a31d23c4dbbcbe06174544401a" + -+ "5b2c020965d8c2bd2171d3668445771f74ba084d2" + -+ "029d83c1c158547f3a9f1a2715be23d51ae4d3e5a" + -+ "1f6a7064f316933a346d3f529252", 16); -+ -+ /* -+ * L = 1024 -+ * SEED = 8d5155894229d5e689ee01e6018a237e2cae64cd -+ * counter = 92 -+ */ -+ BigInteger p1024 = -+ new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523c" + -+ "ef4400c31e3f80b6512669455d402251fb593d8d58" + -+ "fabfc5f5ba30f6cb9b556cd7813b801d346ff26660" + -+ "b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c6" + -+ "1bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554" + -+ "135a169132f675f3ae2b61d72aeff22203199dd148" + -+ "01c7", 16); -+ -+ BigInteger q1024 = -+ new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", -+ 16); -+ -+ BigInteger g1024 = -+ new BigInteger("f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa" + -+ "3aea82f9574c0b3d0782675159578ebad4594fe671" + -+ "07108180b449167123e84c281613b7cf09328cc8a6" + -+ "e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f" + -+ "0bfa213562f1fb627a01243bcca4f1bea8519089a8" + -+ "83dfe15ae59f06928b665e807b552564014c3bfecf" + -+ "492a", 16); -+ -+ try { -+ AlgIdDSA alg512 = new AlgIdDSA(p512, q512, g512); -+ AlgIdDSA alg768 = new AlgIdDSA(p768, q768, g768); -+ AlgIdDSA alg1024 = new AlgIdDSA(p1024, q1024, g1024); -+ -+ precomputedParams.put(Integer.valueOf(512), alg512); -+ precomputedParams.put(Integer.valueOf(768), alg768); -+ precomputedParams.put(Integer.valueOf(1024), alg1024); -+ -+ } catch (Exception e) { -+ throw new InternalError("initializing precomputed " + -+ "algorithm parameters for Sun DSA"); -+ } -+ } -+ -+ /* The modulus length */ -+ private int modlen = 1024; -+ -+ /* Generate new parameters, even if we have precomputed ones. */ -+ boolean generateNewParameters = false; -+ -+ /* preset algorithm parameters. */ -+ private BigInteger presetP, presetQ, presetG; -+ -+ /* The source of random bits to use */ -+ SecureRandom random; -+ -+ public DSAKeyPairGenerator() { -+ super("DSA"); -+ } -+ -+ public void initialize(int strength, SecureRandom random) { -+ if ((strength < 512) || (strength > 1024) || (strength % 64 != 0)) { -+ throw new InvalidParameterException("Modulus size must range from 512 to 1024 " -+ + "and be a multiple of 64"); -+ } -+ -+ /* Set the random */ -+ this.random = random; -+ if (this.random == null) { -+ this.random = new SecureRandom(); -+ } -+ -+ this.modlen = strength; -+ DSAParams params = null; -+ -+ /* Find the precomputed parameters, if any */ -+ if (!generateNewParameters) { -+ Integer mod = Integer.valueOf(this.modlen); -+ params = precomputedParams.get(mod); -+ } -+ if (params != null) { -+ setParams(params); -+ } -+ } -+ -+ /** -+ * Initializes the DSA key pair generator. If genParams is false, a set of pre-computed parameters is -+ * used. In this case, modelen must be 512, 768, or 1024. -+ */ -+ public void initialize(int modlen, boolean genParams, SecureRandom random) -+ throws InvalidParameterException { -+ if (genParams == false && modlen != 512 && modlen != 768 -+ && modlen != 1024) { -+ throw new InvalidParameterException("No precomputed parameters for requested modulus size " -+ + "available"); -+ } -+ this.generateNewParameters = genParams; -+ initialize(modlen, random); -+ } -+ -+ /** -+ * Initializes the DSA object using a DSA parameter object. -+ * -+ * @param params a fully initialized DSA parameter object. -+ */ -+ public void initialize(DSAParams params, SecureRandom random) -+ throws InvalidParameterException { -+ initialize(params.getP().bitLength(), random); -+ setParams(params); -+ } -+ -+ /** -+ * Initializes the DSA object using a parameter object. -+ * -+ * @param params the parameter set to be used to generate -+ * the keys. -+ * @param random the source of randomness for this generator. -+ * -+ * @exception InvalidAlgorithmParameterException if the given parameters -+ * are inappropriate for this key pair generator -+ */ -+ public void initialize(AlgorithmParameterSpec params, SecureRandom random) -+ throws InvalidAlgorithmParameterException { -+ if (!(params instanceof DSAParameterSpec)) { -+ throw new InvalidAlgorithmParameterException("Inappropriate parameter"); -+ } -+ initialize(((DSAParameterSpec) params).getP().bitLength(), -+ random); -+ setParams((DSAParameterSpec) params); -+ } -+ -+ /** -+ * Generates a pair of keys usable by any JavaSecurity compliant -+ * DSA implementation. -+ * -+ * @param rnd the source of random bits from which the random key -+ * generation parameters are drawn. In particular, this includes -+ * the XSEED parameter. -+ * -+ * @exception InvalidParameterException if the modulus is not -+ * between 512 and 1024. -+ */ -+ public KeyPair generateKeyPair() { -+ -+ // set random if initialize() method has been skipped -+ if (this.random == null) { -+ this.random = new SecureRandom(); -+ } -+ -+ if (presetP == null || presetQ == null || presetG == null || -+ generateNewParameters) { -+ -+ AlgorithmParameterGenerator dsaParamGen; -+ -+ try { -+ dsaParamGen = AlgorithmParameterGenerator.getInstance("DSA", -+ "SUN"); -+ } catch (NoSuchAlgorithmException e) { -+ // this should never happen, because we provide it -+ throw new RuntimeException(e.getMessage()); -+ } catch (NoSuchProviderException e) { -+ // this should never happen, because we provide it -+ throw new RuntimeException(e.getMessage()); -+ } -+ -+ dsaParamGen.init(modlen, random); -+ -+ DSAParameterSpec dsaParamSpec; -+ try { -+ dsaParamSpec = dsaParamGen.generateParameters().getParameterSpec -+ (DSAParameterSpec.class); -+ } catch (InvalidParameterSpecException e) { -+ // this should never happen -+ throw new RuntimeException(e.getMessage()); -+ } -+ presetP = dsaParamSpec.getP(); -+ presetQ = dsaParamSpec.getQ(); -+ presetG = dsaParamSpec.getG(); -+ } -+ -+ return generateKeyPair(presetP, presetQ, presetG, random); -+ } -+ -+ public KeyPair generateKeyPair(BigInteger p, BigInteger q, BigInteger g, -+ SecureRandom random) { -+ -+ BigInteger x = generateX(random, q); -+ BigInteger y = generateY(x, p, g); -+ -+ try { -+ DSAPublicKey pub = new DSAPublicKey(y, p, q, g); -+ DSAPrivateKey priv = new DSAPrivateKey(x, p, q, g); -+ -+ KeyPair pair = new KeyPair(pub, priv); -+ return pair; -+ -+ } catch (InvalidKeyException e) { -+ throw new ProviderException(e.getMessage()); -+ } -+ } -+ -+ /** -+ * Generate the private key component of the key pair using the -+ * provided source of random bits. This method uses the random but -+ * source passed to generate a seed and then calls the seed-based -+ * generateX method. -+ */ -+ private BigInteger generateX(SecureRandom random, BigInteger q) { -+ BigInteger x = null; -+ while (true) { -+ int[] seed = new int[5]; -+ for (int i = 0; i < 5; i++) { -+ seed[i] = random.nextInt(); -+ } -+ x = generateX(seed, q); -+ if (x.signum() > 0 && (x.compareTo(q) < 0)) { -+ break; -+ } -+ } -+ return x; -+ } -+ -+ /** -+ * Given a seed, generate the private key component of the key -+ * pair. In the terminology used in the DSA specification -+ * (FIPS-186) seed is the XSEED quantity. -+ * -+ * @param seed the seed to use to generate the private key. -+ */ -+ BigInteger generateX(int[] seed, BigInteger q) { -+ -+ /* Test vector -+ int[] tseed = { 0xbd029bbe, 0x7f51960b, 0xcf9edb2b, -+ 0x61f06f0f, 0xeb5a38b6 }; -+ seed = tseed; -+ */ -+ // check out t in the spec. -+ int[] t = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, -+ 0x10325476, 0xC3D2E1F0 }; -+ // -+ -+ int[] tmp = DSA.SHA_7(seed, t); -+ byte[] tmpBytes = new byte[tmp.length * 4]; -+ for (int i = 0; i < tmp.length; i++) { -+ int k = tmp[i]; -+ for (int j = 0; j < 4; j++) { -+ tmpBytes[(i * 4) + j] = (byte) (k >>> (24 - (j * 8))); -+ } -+ } -+ BigInteger x = new BigInteger(1, tmpBytes).mod(q); -+ return x; -+ } -+ -+ /** -+ * Generate the public key component y of the key pair. -+ * -+ * @param x the private key component. -+ * -+ * @param p the base parameter. -+ */ -+ BigInteger generateY(BigInteger x, BigInteger p, BigInteger g) { -+ BigInteger y = g.modPow(x, p); -+ return y; -+ } -+ -+ /** -+ * Set the parameters. -+ */ -+ private void setParams(DSAParams params) { -+ presetP = params.getP(); -+ presetQ = params.getQ(); -+ presetG = params.getG(); -+ } -+ -+ /** -+ * Set the parameters. -+ */ -+ private void setParams(DSAParameterSpec params) { -+ presetP = params.getP(); -+ presetQ = params.getQ(); -+ presetG = params.getG(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/provider/DSAParameterGenerator.java b/org/mozilla/jss/netscape/security/provider/DSAParameterGenerator.java -new file mode 100755 -index 00000000..5cd86c79 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/DSAParameterGenerator.java -@@ -0,0 +1,298 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.math.BigInteger; -+import java.security.AlgorithmParameterGeneratorSpi; -+import java.security.AlgorithmParameters; -+import java.security.InvalidAlgorithmParameterException; -+import java.security.InvalidParameterException; -+import java.security.NoSuchAlgorithmException; -+import java.security.NoSuchProviderException; -+import java.security.SecureRandom; -+import java.security.spec.AlgorithmParameterSpec; -+import java.security.spec.DSAParameterSpec; -+import java.security.spec.InvalidParameterSpecException; -+ -+/* -+ * This class generates parameters for the DSA algorithm. It uses a default -+ * prime modulus size of 1024 bits, which can be overwritten during -+ * initialization. -+ * -+ * @author Jan Luehe -+ * -+ * @version 1.4, 97/12/10 -+ * -+ * @see java.security.AlgorithmParameters -+ * @see java.security.spec.AlgorithmParameterSpec -+ * @see DSAParameters -+ * -+ * @since JDK1.2 -+ */ -+ -+public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { -+ -+ // the modulus length -+ private int modLen = 1024; // default -+ -+ // the source of randomness -+ private SecureRandom random; -+ -+ // useful constants -+ private static final BigInteger ONE = BigInteger.valueOf(1); -+ private static final BigInteger TWO = BigInteger.valueOf(2); -+ -+ // Make a SHA-1 hash function -+ private SHA sha; -+ -+ public DSAParameterGenerator() { -+ this.sha = new SHA(); -+ } -+ -+ /** -+ * Initializes this parameter generator for a certain strength -+ * and source of randomness. -+ * -+ * @param strength the strength (size of prime) in bits -+ * @param random the source of randomness -+ */ -+ protected void engineInit(int strength, SecureRandom random) { -+ /* -+ * Bruce Schneier, "Applied Cryptography", 2nd Edition, -+ * Description of DSA: -+ * [...] The algorithm uses the following parameter: -+ * p=a prime number L bits long, when L ranges from 512 to 1024 and is -+ * a multiple of 64. [...] -+ */ -+ if ((strength < 512) || (strength > 1024) || (strength % 64 != 0)) { -+ throw new InvalidParameterException("Prime size must range from 512 to 1024 " -+ + "and be a multiple of 64"); -+ } -+ this.modLen = strength; -+ this.random = random; -+ } -+ -+ /** -+ * Initializes this parameter generator with a set of -+ * algorithm-specific parameter generation values. -+ * -+ * @param params the set of algorithm-specific parameter generation values -+ * @param random the source of randomness -+ * -+ * @exception InvalidAlgorithmParameterException if the given parameter -+ * generation values are inappropriate for this parameter generator -+ */ -+ protected void engineInit(AlgorithmParameterSpec genParamSpec, -+ SecureRandom random) -+ throws InvalidAlgorithmParameterException { -+ throw new InvalidAlgorithmParameterException("Invalid parameter"); -+ } -+ -+ /** -+ * Generates the parameters. -+ * -+ * @return the new AlgorithmParameters object -+ */ -+ protected AlgorithmParameters engineGenerateParameters() { -+ AlgorithmParameters algParams = null; -+ try { -+ if (this.random == null) { -+ this.random = new SecureRandom(); -+ } -+ -+ BigInteger[] pAndQ = generatePandQ(this.random, this.modLen); -+ BigInteger paramP = pAndQ[0]; -+ BigInteger paramQ = pAndQ[1]; -+ BigInteger paramG = generateG(paramP, paramQ); -+ -+ DSAParameterSpec dsaParamSpec = new DSAParameterSpec(paramP, -+ paramQ, -+ paramG); -+ algParams = AlgorithmParameters.getInstance("DSA", "SUN"); -+ algParams.init(dsaParamSpec); -+ } catch (InvalidParameterSpecException e) { -+ // this should never happen -+ throw new RuntimeException(e.getMessage()); -+ } catch (NoSuchAlgorithmException e) { -+ // this should never happen, because we provide it -+ throw new RuntimeException(e.getMessage()); -+ } catch (NoSuchProviderException e) { -+ // this should never happen, because we provide it -+ throw new RuntimeException(e.getMessage()); -+ } -+ -+ return algParams; -+ } -+ -+ /* -+ * Generates the prime and subprime parameters for DSA, -+ * using the provided source of randomness. -+ * This method will generate new seeds until a suitable -+ * seed has been found. -+ * -+ * @param random the source of randomness to generate the -+ * seed -+ * @param L the size of p, in bits. -+ * -+ * @return an array of BigInteger, with p at index 0 and -+ * q at index 1. -+ */ -+ BigInteger[] generatePandQ(SecureRandom random, int L) { -+ BigInteger[] result = null; -+ byte[] seed = new byte[20]; -+ -+ while (result == null) { -+ for (int i = 0; i < 20; i++) { -+ seed[i] = (byte) random.nextInt(); -+ } -+ result = generatePandQ(seed, L); -+ } -+ return result; -+ } -+ -+ /* -+ * Generates the prime and subprime parameters for DSA. -+ * -+ *

The seed parameter corresponds to the SEED parameter -+ * referenced in the FIPS specification of the DSA algorithm, -+ * and L is the size of p, in bits. -+ * -+ * @param seed the seed to generate the parameters -+ * @param L the size of p, in bits. -+ * -+ * @return an array of BigInteger, with p at index 0, -+ * q at index 1, the seed at index 2, and the counter value -+ * at index 3, or null if the seed does not yield suitable numbers. -+ */ -+ BigInteger[] generatePandQ(byte[] seed, int L) { -+ -+ /* Useful variables */ -+ int g = seed.length * 8; -+ int n = (L - 1) / 160; -+ int b = (L - 1) % 160; -+ -+ BigInteger SEED = new BigInteger(1, seed); -+ BigInteger TWOG = TWO.pow(2 * g); -+ -+ /* Step 2 (Step 1 is getting seed). */ -+ byte[] U1 = SHA(seed); -+ byte[] U2 = SHA(toByteArray((SEED.add(ONE)).mod(TWOG))); -+ -+ xor(U1, U2); -+ byte[] U = U1; -+ -+ /* Step 3: For q by setting the msb and lsb to 1 */ -+ U[0] |= 0x80; -+ U[19] |= 1; -+ BigInteger q = new BigInteger(1, U); -+ -+ /* Step 5 */ -+ if (!q.isProbablePrime(40)) { -+ return null; -+ -+ } else { -+ BigInteger V[] = new BigInteger[n + 1]; -+ BigInteger offset = TWO; -+ -+ /* Step 6 */ -+ for (int counter = 0; counter < 4096; counter++) { -+ -+ /* Step 7 */ -+ for (int k = 0; k <= n; k++) { -+ BigInteger K = BigInteger.valueOf(k); -+ BigInteger tmp = (SEED.add(offset).add(K)).mod(TWOG); -+ V[k] = new BigInteger(1, SHA(toByteArray(tmp))); -+ } -+ -+ /* Step 8 */ -+ BigInteger W = V[0]; -+ for (int i = 1; i < n; i++) { -+ W = W.add(V[i].multiply(TWO.pow(i * 160))); -+ } -+ W = W.add((V[n].mod(TWO.pow(b))).multiply(TWO.pow(n * 160))); -+ -+ BigInteger TWOLm1 = TWO.pow(L - 1); -+ BigInteger X = W.add(TWOLm1); -+ -+ /* Step 9 */ -+ BigInteger c = X.mod(q.multiply(TWO)); -+ BigInteger p = X.subtract(c.subtract(ONE)); -+ -+ /* Step 10 - 13 */ -+ if (p.compareTo(TWOLm1) > -1 && p.isProbablePrime(15)) { -+ BigInteger[] result = { p, q, SEED, -+ BigInteger.valueOf(counter) }; -+ return result; -+ } -+ offset = offset.add(BigInteger.valueOf(n)).add(ONE); -+ } -+ return null; -+ } -+ } -+ -+ /* -+ * Generates the g parameter for DSA. -+ * -+ * @param p the prime, p. -+ * @param q the subprime, q. -+ * -+ * @param the g -+ */ -+ BigInteger generateG(BigInteger p, BigInteger q) { -+ BigInteger h = ONE; -+ BigInteger pMinusOneOverQ = (p.subtract(ONE)).divide(q); -+ BigInteger g = ONE; -+ while (g.compareTo(TWO) < 0) { -+ g = h.modPow(pMinusOneOverQ, p); -+ h = h.add(ONE); -+ } -+ return g; -+ } -+ -+ /* -+ * Returns the SHA-1 digest of some data -+ */ -+ private byte[] SHA(byte[] array) { -+ sha.engineReset(); -+ sha.engineUpdate(array, 0, array.length); -+ return sha.engineDigest(); -+ } -+ -+ /* -+ * Converts the result of a BigInteger.toByteArray call to an exact -+ * signed magnitude representation for any positive number. -+ */ -+ private byte[] toByteArray(BigInteger bigInt) { -+ byte[] result = bigInt.toByteArray(); -+ if (result[0] == 0) { -+ byte[] tmp = new byte[result.length - 1]; -+ System.arraycopy(result, 1, tmp, 0, tmp.length); -+ result = tmp; -+ } -+ return result; -+ } -+ -+ /* -+ * XORs U2 into U1 -+ */ -+ private void xor(byte[] U1, byte[] U2) { -+ for (int i = 0; i < U1.length; i++) { -+ U1[i] ^= U2[i]; -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/provider/DSAParameters.java b/org/mozilla/jss/netscape/security/provider/DSAParameters.java -new file mode 100755 -index 00000000..c457698b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/DSAParameters.java -@@ -0,0 +1,131 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.io.IOException; -+import java.math.BigInteger; -+import java.security.AlgorithmParametersSpi; -+import java.security.spec.AlgorithmParameterSpec; -+import java.security.spec.DSAParameterSpec; -+import java.security.spec.InvalidParameterSpecException; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class implements the parameter set used by the -+ * Digital Signature Algorithm as specified in the FIPS 186 -+ * standard. -+ * -+ * @author Jan Luehe -+ * -+ * @version 1.8, 97/12/10 -+ * -+ * @since JDK1.2 -+ */ -+ -+public class DSAParameters extends AlgorithmParametersSpi { -+ -+ // the prime (p) -+ protected BigInteger p; -+ -+ // the sub-prime (q) -+ protected BigInteger q; -+ -+ // the base (g) -+ protected BigInteger g; -+ -+ protected void engineInit(AlgorithmParameterSpec paramSpec) -+ throws InvalidParameterSpecException { -+ if (!(paramSpec instanceof DSAParameterSpec)) { -+ throw new InvalidParameterSpecException("Inappropriate parameter specification"); -+ } -+ this.p = ((DSAParameterSpec) paramSpec).getP(); -+ this.q = ((DSAParameterSpec) paramSpec).getQ(); -+ this.g = ((DSAParameterSpec) paramSpec).getG(); -+ } -+ -+ protected void engineInit(byte[] params) throws IOException { -+ DerValue encodedParams = new DerValue(params); -+ -+ if (encodedParams.tag != DerValue.tag_Sequence) { -+ throw new IOException("DSA params parsing error"); -+ } -+ -+ encodedParams.data.reset(); -+ -+ this.p = encodedParams.data.getInteger().toBigInteger(); -+ this.q = encodedParams.data.getInteger().toBigInteger(); -+ this.g = encodedParams.data.getInteger().toBigInteger(); -+ -+ if (encodedParams.data.available() != 0) { -+ throw new IOException("encoded params have " + -+ encodedParams.data.available() + -+ " extra bytes"); -+ } -+ } -+ -+ protected void engineInit(byte[] params, String decodingMethod) -+ throws IOException { -+ engineInit(params); -+ } -+ -+ @SuppressWarnings("unchecked") -+ protected T engineGetParameterSpec(Class paramSpec) -+ throws InvalidParameterSpecException { -+ try { -+ Class dsaParamSpec = Class.forName -+ ("java.security.spec.DSAParameterSpec"); -+ if (dsaParamSpec.isAssignableFrom(paramSpec)) { -+ return (T) new DSAParameterSpec(this.p, this.q, this.g); -+ } else { -+ throw new InvalidParameterSpecException("Inappropriate parameter Specification"); -+ } -+ } catch (ClassNotFoundException e) { -+ throw new InvalidParameterSpecException("Unsupported parameter specification: " + e.getMessage()); -+ } -+ } -+ -+ protected byte[] engineGetEncoded() throws IOException { -+ try (DerOutputStream out = new DerOutputStream()) { -+ DerOutputStream bytes = new DerOutputStream(); -+ -+ bytes.putInteger(new BigInt(p.toByteArray())); -+ bytes.putInteger(new BigInt(q.toByteArray())); -+ bytes.putInteger(new BigInt(g.toByteArray())); -+ out.write(DerValue.tag_Sequence, bytes); -+ return out.toByteArray(); -+ } -+ } -+ -+ protected byte[] engineGetEncoded(String encodingMethod) -+ throws IOException { -+ return engineGetEncoded(); -+ } -+ -+ /* -+ * Returns a formatted string describing the parameters. -+ */ -+ protected String engineToString() { -+ return "\n\tp: " + new BigInt(p).toString() -+ + "\n\tq: " + new BigInt(q).toString() -+ + "\n\tg: " + new BigInt(g).toString() -+ + "\n"; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/provider/DSAPrivateKey.java b/org/mozilla/jss/netscape/security/provider/DSAPrivateKey.java -new file mode 100644 -index 00000000..6db2dbf6 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/DSAPrivateKey.java -@@ -0,0 +1,170 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.io.IOException; -+import java.io.Serializable; -+import java.math.BigInteger; -+import java.security.AlgorithmParameters; -+import java.security.InvalidKeyException; -+import java.security.interfaces.DSAParams; -+import java.security.spec.DSAParameterSpec; -+import java.security.spec.InvalidParameterSpecException; -+ -+import org.mozilla.jss.netscape.security.pkcs.PKCS8Key; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.x509.AlgIdDSA; -+ -+/** -+ * A PKCS#8 private key for the Digital Signature Algorithm. -+ * -+ * @author Benjamin Renaud -+ * -+ * @version 1.47, 97/12/10 -+ * -+ * @see DSAPublicKey -+ * @see AlgIdDSA -+ * @see DSA -+ */ -+ -+public final class DSAPrivateKey extends PKCS8Key -+ implements java.security.interfaces.DSAPrivateKey, Serializable { -+ -+ /** use serialVersionUID from JDK 1.1. for interoperability */ -+ private static final long serialVersionUID = -3244453684193605938L; -+ -+ /* the private key */ -+ private BigInteger x; -+ -+ /* -+ * Keep this constructor for backwards compatibility with JDK1.1. -+ */ -+ public DSAPrivateKey() { -+ } -+ -+ /** -+ * Make a DSA private key out of a private key and three parameters. -+ */ -+ public DSAPrivateKey(BigInteger x, BigInteger p, -+ BigInteger q, BigInteger g) -+ throws InvalidKeyException { -+ this.x = x; -+ algid = new AlgIdDSA(p, q, g); -+ -+ try { -+ key = new DerValue(DerValue.tag_Integer, -+ x.toByteArray()).toByteArray(); -+ encode(); -+ } catch (IOException e) { -+ throw new InvalidKeyException("could not DER encode x: " + -+ e.getMessage()); -+ } -+ } -+ -+ /** -+ * Make a DSA private key from its DER encoding (PKCS #8). -+ */ -+ public DSAPrivateKey(byte[] encoded) throws InvalidKeyException { -+ clearOldKey(); -+ decode(encoded); -+ } -+ -+ /** -+ * Returns the DSA parameters associated with this key, or null if the -+ * parameters could not be parsed. -+ */ -+ public DSAParams getParams() { -+ try { -+ if (algid instanceof DSAParams) { -+ return (DSAParams) algid; -+ } else { -+ AlgorithmParameters algParams = algid.getParameters(); -+ if (algParams == null) { -+ return null; -+ } -+ return algParams.getParameterSpec(DSAParameterSpec.class); -+ } -+ } catch (InvalidParameterSpecException e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Get the raw private key, x, without the parameters. -+ * -+ */ -+ public BigInteger getX() { -+ return x; -+ } -+ -+ private void clearOldKey() { -+ int i; -+ if (this.encodedKey != null) { -+ for (i = 0; i < this.encodedKey.length; i++) { -+ this.encodedKey[i] = (byte) 0x00; -+ } -+ } -+ if (this.key != null) { -+ for (i = 0; i < this.key.length; i++) { -+ this.key[i] = (byte) 0x00; -+ } -+ } -+ } -+ -+ public String toString() { -+ return "Sun DSA Private Key \nparameters:" + algid + "\nx: " + -+ x.toString(16) + "\n"; -+ } -+ -+ protected void parseKeyBits() throws InvalidKeyException { -+ DerInputStream in = new DerInputStream(key); -+ -+ try { -+ x = in.getInteger().toBigInteger(); -+ } catch (IOException e) { -+ throw new InvalidKeyException(e.getMessage()); -+ } -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = super.hashCode(); -+ result = prime * result + ((x == null) ? 0 : x.hashCode()); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (!super.equals(obj)) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ DSAPrivateKey other = (DSAPrivateKey) obj; -+ if (x == null) { -+ if (other.x != null) -+ return false; -+ } else if (!x.equals(other.x)) -+ return false; -+ return true; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/provider/DSAPublicKey.java b/org/mozilla/jss/netscape/security/provider/DSAPublicKey.java -new file mode 100644 -index 00000000..b05210e2 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/DSAPublicKey.java -@@ -0,0 +1,159 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.io.IOException; -+import java.io.Serializable; -+import java.math.BigInteger; -+import java.security.AlgorithmParameters; -+import java.security.InvalidKeyException; -+import java.security.interfaces.DSAParams; -+import java.security.spec.DSAParameterSpec; -+import java.security.spec.InvalidParameterSpecException; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.x509.AlgIdDSA; -+import org.mozilla.jss.netscape.security.x509.X509Key; -+ -+/** -+ * An X.509 public key for the Digital Signature Algorithm. -+ * -+ * @author Benjamin Renaud -+ * -+ * @version 1.52, 97/12/10 -+ * -+ * @see DSAPrivateKey -+ * @see AlgIdDSA -+ * @see DSA -+ */ -+ -+public final class DSAPublicKey extends X509Key -+ implements java.security.interfaces.DSAPublicKey, Serializable { -+ -+ /** use serialVersionUID from JDK 1.1. for interoperability */ -+ private static final long serialVersionUID = -2994193307391104133L; -+ -+ /* the public key */ -+ private BigInteger y; -+ -+ /* -+ * Keep this constructor for backwards compatibility with JDK1.1. -+ */ -+ public DSAPublicKey() { -+ } -+ -+ /** -+ * Make a DSA public key out of a public key and three parameters. -+ */ -+ public DSAPublicKey(BigInteger y, BigInteger p, BigInteger q, -+ BigInteger g) -+ throws InvalidKeyException { -+ this.y = y; -+ algid = new AlgIdDSA(p, q, g); -+ -+ try { -+ key = new DerValue(DerValue.tag_Integer, -+ y.toByteArray()).toByteArray(); -+ encode(); -+ } catch (IOException e) { -+ throw new InvalidKeyException("could not DER encode y: " + -+ e.getMessage()); -+ } -+ } -+ -+ /** -+ * Make a DSA public key from its DER encoding (X.509). -+ */ -+ public DSAPublicKey(byte[] encoded) throws InvalidKeyException { -+ decode(encoded); -+ } -+ -+ /** -+ * Returns the DSA parameters associated with this key, or null if the -+ * parameters could not be parsed. -+ */ -+ public DSAParams getParams() { -+ try { -+ if (algid instanceof DSAParams) { -+ return (DSAParams) algid; -+ } else { -+ DSAParameterSpec paramSpec; -+ AlgorithmParameters algParams = algid.getParameters(); -+ if (algParams == null) { -+ return null; -+ } -+ paramSpec = algParams.getParameterSpec -+ (DSAParameterSpec.class); -+ return paramSpec; -+ } -+ } catch (InvalidParameterSpecException e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Get the raw public value, y, without the parameters. -+ * -+ */ -+ public BigInteger getY() { -+ return y; -+ } -+ -+ public String toString() { -+ return "Sun DSA Public Key\n Parameters:" + algid -+ + "\n y:\n" + (new BigInt(y)).toString() + "\n"; -+ } -+ -+ protected void parseKeyBits() throws InvalidKeyException { -+ try { -+ DerInputStream in = new DerInputStream(key); -+ y = in.getInteger().toBigInteger(); -+ } catch (IOException e) { -+ throw new InvalidKeyException("Invalid key: y value\n" + -+ e.getMessage()); -+ } -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = super.hashCode(); -+ result = prime * result + ((y == null) ? 0 : y.hashCode()); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (!super.equals(obj)) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ DSAPublicKey other = (DSAPublicKey) obj; -+ if (y == null) { -+ if (other.y != null) -+ return false; -+ } else if (!y.equals(other.y)) -+ return false; -+ return true; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/provider/MD5.java b/org/mozilla/jss/netscape/security/provider/MD5.java -new file mode 100644 -index 00000000..d46da4fc ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/MD5.java -@@ -0,0 +1,378 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.security.DigestException; -+import java.security.MessageDigestSpi; -+ -+/** -+ * The MD5 class is used to compute an MD5 message digest over a given -+ * buffer of bytes. It is an implementation of the RSA Data Security Inc -+ * MD5 algorithim as described in internet RFC 1321. -+ * -+ * @version 1.24 97/12/10 -+ * @author Chuck McManis -+ * @author Benjamin Renaud -+ */ -+ -+public final class MD5 extends MessageDigestSpi implements Cloneable { -+ -+ /** contains the computed message digest */ -+ private byte[] digestBits; -+ -+ private int state[]; -+ private long count; // bit count AND buffer[] index aid -+ private byte buffer[]; -+ private int transformBuffer[]; -+ -+ private static final int S11 = 7; -+ private static final int S12 = 12; -+ private static final int S13 = 17; -+ private static final int S14 = 22; -+ private static final int S21 = 5; -+ private static final int S22 = 9; -+ private static final int S23 = 14; -+ private static final int S24 = 20; -+ private static final int S31 = 4; -+ private static final int S32 = 11; -+ private static final int S33 = 16; -+ private static final int S34 = 23; -+ private static final int S41 = 6; -+ private static final int S42 = 10; -+ private static final int S43 = 15; -+ private static final int S44 = 21; -+ -+ private static final int MD5_LENGTH = 16; -+ -+ /** -+ * Standard constructor, creates a new MD5 instance, allocates its -+ * buffers from the heap. -+ */ -+ public MD5() { -+ init(); -+ } -+ -+ /* ********************************************************** -+ * The MD5 Functions. These are copied verbatim from -+ * the RFC to insure accuracy. The results of this -+ * implementation were checked against the RSADSI version. -+ * ********************************************************** -+ */ -+ -+ private int F(int x, int y, int z) { -+ return ((x & y) | ((~x) & z)); -+ } -+ -+ private int G(int x, int y, int z) { -+ return ((x & z) | (y & (~z))); -+ } -+ -+ private int H(int x, int y, int z) { -+ return ((x ^ y) ^ z); -+ } -+ -+ private int I(int x, int y, int z) { -+ return (y ^ (x | (~z))); -+ } -+ -+ private int rotateLeft(int a, int n) { -+ return ((a << n) | (a >>> (32 - n))); -+ } -+ -+ private int FF(int a, int b, int c, int d, int x, int s, int ac) { -+ a += F(b, c, d) + x + ac; -+ a = rotateLeft(a, s); -+ a += b; -+ return a; -+ } -+ -+ private int GG(int a, int b, int c, int d, int x, int s, int ac) { -+ a += G(b, c, d) + x + ac; -+ a = rotateLeft(a, s); -+ a += b; -+ return a; -+ } -+ -+ private int HH(int a, int b, int c, int d, int x, int s, int ac) { -+ a += H(b, c, d) + x + ac; -+ a = rotateLeft(a, s); -+ a += b; -+ return a; -+ } -+ -+ private int II(int a, int b, int c, int d, int x, int s, int ac) { -+ a += I(b, c, d) + x + ac; -+ a = rotateLeft(a, s); -+ a += b; -+ return a; -+ } -+ -+ /** -+ * This is where the functions come together as the generic MD5 -+ * transformation operation, it is called by update() which is -+ * synchronized (to protect transformBuffer). It consumes sixteen -+ * bytes from the buffer, beginning at the specified offset. -+ */ -+ void transform(byte buf[], int offset) { -+ int a, b, c, d; -+ int x[] = transformBuffer; -+ -+ a = state[0]; -+ b = state[1]; -+ c = state[2]; -+ d = state[3]; -+ -+ for (int i = 0; i < 16; i++) { -+ x[i] = buf[i * 4 + offset] & 0xff; -+ for (int j = 1; j < 4; j++) { -+ x[i] += (buf[i * 4 + j + offset] & 0xff) << (j * 8); -+ } -+ } -+ -+ /* Round 1 */ -+ a = FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ -+ d = FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ -+ c = FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ -+ b = FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ -+ a = FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ -+ d = FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ -+ c = FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ -+ b = FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ -+ a = FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ -+ d = FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ -+ c = FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ -+ b = FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ -+ a = FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ -+ d = FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ -+ c = FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ -+ b = FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ -+ -+ /* Round 2 */ -+ a = GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ -+ d = GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ -+ c = GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ -+ b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ -+ a = GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ -+ d = GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ -+ c = GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ -+ b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ -+ a = GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ -+ d = GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ -+ c = GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ -+ b = GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ -+ a = GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ -+ d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ -+ c = GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ -+ b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ -+ -+ /* Round 3 */ -+ a = HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ -+ d = HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ -+ c = HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ -+ b = HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ -+ a = HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ -+ d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ -+ c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ -+ b = HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ -+ a = HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ -+ d = HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ -+ c = HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ -+ b = HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ -+ a = HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ -+ d = HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ -+ c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ -+ b = HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ -+ -+ /* Round 4 */ -+ a = II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ -+ d = II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ -+ c = II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ -+ b = II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ -+ a = II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ -+ d = II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ -+ c = II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ -+ b = II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ -+ a = II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ -+ d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ -+ c = II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ -+ b = II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ -+ a = II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ -+ d = II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ -+ c = II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ -+ b = II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ -+ -+ state[0] += a; -+ state[1] += b; -+ state[2] += c; -+ state[3] += d; -+ } -+ -+ /** -+ * Initialize the MD5 state information and reset the bit count -+ * to 0. Given this implementation you are constrained to counting -+ * 2^64 bits. -+ */ -+ public void init() { -+ state = new int[4]; -+ transformBuffer = new int[16]; -+ synchronized (this) { -+ buffer = new byte[64]; -+ } -+ digestBits = new byte[16]; -+ count = 0; -+ // Load magic initialization constants. -+ state[0] = 0x67452301; -+ state[1] = 0xefcdab89; -+ state[2] = 0x98badcfe; -+ state[3] = 0x10325476; -+ for (int i = 0; i < digestBits.length; i++) -+ digestBits[i] = 0; -+ } -+ -+ protected void engineReset() { -+ init(); -+ } -+ -+ /** -+ * Return the digest length in bytes -+ */ -+ protected int engineGetDigestLength() { -+ return (MD5_LENGTH); -+ } -+ -+ /** -+ * Update adds the passed byte to the digested data. -+ */ -+ protected synchronized void engineUpdate(byte b) { -+ int index; -+ -+ index = (int) ((count >>> 3) & 0x3f); -+ count += 8; -+ buffer[index] = b; -+ if (index >= 63) { -+ transform(buffer, 0); -+ } -+ } -+ -+ /** -+ * Update adds the selected part of an array of bytes to the digest. -+ * This version is more efficient than the byte-at-a-time version; -+ * it avoids data copies and reduces per-byte call overhead. -+ */ -+ protected synchronized void engineUpdate(byte input[], int offset, -+ int len) { -+ int i; -+ -+ for (i = offset; len > 0;) { -+ int index = (int) ((count >>> 3) & 0x3f); -+ -+ if (index == 0 && len > 64) { -+ count += (64 * 8); -+ transform(input, i); -+ len -= 64; -+ i += 64; -+ } else { -+ count += 8; -+ buffer[index] = input[i]; -+ if (index >= 63) -+ transform(buffer, 0); -+ i++; -+ len--; -+ } -+ } -+ } -+ -+ /** -+ * Perform the final computations, any buffered bytes are added -+ * to the digest, the count is added to the digest, and the resulting -+ * digest is stored. After calling final you will need to call -+ * init() again to do another digest. -+ */ -+ private void finish() { -+ byte bits[] = new byte[8]; -+ byte padding[]; -+ int i, index, padLen; -+ -+ for (i = 0; i < 8; i++) { -+ bits[i] = (byte) ((count >>> (i * 8)) & 0xff); -+ } -+ -+ index = (int) (count >> 3) & 0x3f; -+ padLen = (index < 56) ? (56 - index) : (120 - index); -+ padding = new byte[padLen]; -+ padding[0] = (byte) 0x80; -+ engineUpdate(padding, 0, padding.length); -+ engineUpdate(bits, 0, bits.length); -+ -+ for (i = 0; i < 4; i++) { -+ for (int j = 0; j < 4; j++) { -+ digestBits[i * 4 + j] = (byte) ((state[i] >>> (j * 8)) & 0xff); -+ } -+ } -+ } -+ -+ /** -+ */ -+ protected byte[] engineDigest() { -+ finish(); -+ -+ byte[] result = new byte[MD5_LENGTH]; -+ System.arraycopy(digestBits, 0, result, 0, MD5_LENGTH); -+ -+ init(); -+ -+ return result; -+ } -+ -+ /** -+ */ -+ protected int engineDigest(byte[] buf, int offset, int len) -+ throws DigestException { -+ finish(); -+ -+ if (len < MD5_LENGTH) -+ throw new DigestException("partial digests not returned"); -+ if (buf.length - offset < MD5_LENGTH) -+ throw new DigestException("insufficient space in the output " + -+ "buffer to store the digest"); -+ -+ System.arraycopy(digestBits, 0, buf, offset, MD5_LENGTH); -+ -+ init(); -+ -+ return MD5_LENGTH; -+ } -+ -+ /* -+ * Clones this object. -+ */ -+ public Object clone() { -+ MD5 that = null; -+ try { -+ that = (MD5) super.clone(); -+ that.state = this.state.clone(); -+ that.transformBuffer = this.transformBuffer.clone(); -+ that.buffer = this.buffer.clone(); -+ that.digestBits = this.digestBits.clone(); -+ that.count = this.count; -+ return that; -+ } catch (CloneNotSupportedException e) { -+ } -+ return that; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/provider/Makefile b/org/mozilla/jss/netscape/security/provider/Makefile -new file mode 100644 -index 00000000..8fd7054b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/Makefile -@@ -0,0 +1,45 @@ -+#! gmake -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+####################################################################### -+# (1) Include initial platform-independent assignments (MANDATORY). # -+####################################################################### -+ -+include manifest.mn -+ -+####################################################################### -+# (2) Include "global" configuration information. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/config.mk -+ -+####################################################################### -+# (3) Include "component" configuration information. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (4) Include "local" platform-dependent assignments (OPTIONAL). # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (5) Execute "global" rules. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/rules.mk -+ -+####################################################################### -+# (6) Execute "component" rules. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -diff --git a/org/mozilla/jss/netscape/security/provider/RSAPublicKey.java b/org/mozilla/jss/netscape/security/provider/RSAPublicKey.java -new file mode 100644 -index 00000000..2c5886ac ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/RSAPublicKey.java -@@ -0,0 +1,193 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.io.IOException; -+import java.io.Serializable; -+import java.security.InvalidKeyException; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.x509.AlgorithmId; -+import org.mozilla.jss.netscape.security.x509.X509Key; -+ -+/** -+ * An X.509 public key for the RSA Algorithm. -+ * -+ * @author galperin -+ * -+ * @version $Revision$, $Date$ -+ * -+ */ -+ -+public final class RSAPublicKey extends X509Key implements Serializable { -+ -+ /* XXX This currently understands only PKCS#1 RSA Encryption OID -+ and parameter format -+ Later we may consider adding X509v3 OID for RSA keys. Besides -+ different OID it also has a parameter equal to modulus size -+ in bits (redundant!) -+ */ -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 7764823589128565374L; -+ -+ private static final ObjectIdentifier ALGORITHM_OID = -+ AlgorithmId.RSAEncryption_oid; -+ -+ private BigInt modulus; -+ private BigInt publicExponent; -+ -+ /* -+ * Keep this constructor for backwards compatibility with JDK1.1. -+ */ -+ public RSAPublicKey() { -+ } -+ -+ /** -+ * Make a RSA public key out of a public exponent and modulus -+ */ -+ public RSAPublicKey(BigInt modulus, BigInt publicExponent) -+ throws InvalidKeyException { -+ this.modulus = modulus; -+ this.publicExponent = publicExponent; -+ this.algid = new AlgorithmId(ALGORITHM_OID); -+ -+ try (DerOutputStream out = new DerOutputStream()) { -+ out.putInteger(modulus); -+ out.putInteger(publicExponent); -+ key = (new DerValue(DerValue.tag_Sequence, -+ out.toByteArray())).toByteArray(); -+ encode(); -+ } catch (IOException ex) { -+ throw new InvalidKeyException("could not DER encode : " + -+ ex.getMessage()); -+ } -+ } -+ -+ /** -+ * Make a RSA public key from its DER encoding (X.509). -+ */ -+ public RSAPublicKey(byte[] encoded) throws InvalidKeyException { -+ decode(encoded); -+ } -+ -+ /** -+ * Get key size as number of bits in modulus -+ * (Always rounded up to a multiple of 8) -+ * -+ */ -+ public int getKeySize() { -+ return this.modulus.byteLength() * 8; -+ } -+ -+ /** -+ * Get the raw public exponent -+ * -+ */ -+ public BigInt getPublicExponent() { -+ return this.publicExponent; -+ } -+ -+ /** -+ * Get the raw modulus -+ * -+ */ -+ public BigInt getModulus() { -+ return this.modulus; -+ } -+ -+ public String toString() { -+ return "RSA Public Key\n Algorithm: " + algid -+ + "\n modulus:\n" + this.modulus.toString() + "\n" -+ + "\n publicExponent:\n" + this.publicExponent.toString() -+ + "\n"; -+ } -+ -+ protected void parseKeyBits() throws InvalidKeyException { -+ if (!this.algid.getOID().equals(ALGORITHM_OID) && -+ !this.algid.getOID().equals(AlgorithmId.RSA_oid)) { -+ throw new InvalidKeyException("Key algorithm OID is not RSA"); -+ } -+ -+ try { -+ DerValue val = new DerValue(key); -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new InvalidKeyException("Invalid RSA public key format:" + -+ " must be a SEQUENCE"); -+ } -+ -+ DerInputStream in = val.data; -+ -+ this.modulus = in.getInteger(); -+ this.publicExponent = in.getInteger(); -+ } catch (IOException e) { -+ throw new InvalidKeyException("Invalid RSA public key: " + -+ e.getMessage()); -+ } -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = super.hashCode(); -+ result = prime * result + ((modulus == null) ? 0 : modulus.hashCode()); -+ result = prime * result + ((publicExponent == null) ? 0 : publicExponent.hashCode()); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (!super.equals(obj)) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ RSAPublicKey other = (RSAPublicKey) obj; -+ if (modulus == null) { -+ if (other.modulus != null) -+ return false; -+ } else if (!modulus.equals(other.modulus)) -+ return false; -+ if (publicExponent == null) { -+ if (other.publicExponent != null) -+ return false; -+ } else if (!publicExponent.equals(other.publicExponent)) -+ return false; -+ return true; -+ } -+ -+ public boolean bigIntEquals(BigInt x, BigInt y) { -+ if (x == null) { -+ if (y != null) { -+ return false; -+ } -+ } else { -+ if (!x.equals(y)) { -+ return false; -+ } -+ } -+ return true; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/provider/SHA.java b/org/mozilla/jss/netscape/security/provider/SHA.java -new file mode 100644 -index 00000000..a911e386 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/SHA.java -@@ -0,0 +1,349 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.security.DigestException; -+import java.security.MessageDigestSpi; -+ -+/** -+ * This class implements the Secure Hash Algorithm (SHA) developed by -+ * the National Institute of Standards and Technology along with the -+ * National Security Agency. This is the updated version of SHA -+ * fip-180 as superseded by fip-180-1. -+ * -+ *

-+ * It implement JavaSecurity MessageDigest, and can be used by in the Java Security framework, as a pluggable -+ * implementation, as a filter for the digest stream classes. -+ * -+ * @version 1.30 97/12/10 -+ * @author Roger Riggs -+ * @author Benjamin Renaud -+ */ -+ -+public class SHA extends MessageDigestSpi implements Cloneable { -+ -+ /* This private hookm controlled by the appropriate constructor, -+ causes this class to implement the first version of SHA, -+ as defined in FIPS 180, as opposed to FIPS 180-1. This was -+ useful for DSA testing. */ -+ private int version = 1; -+ -+ private static final int SHA_LENGTH = 20; -+ -+ // Buffer of int's and count of characters accumulated -+ // 64 bytes are included in each hash block so the low order -+ // bits of count are used to know how to pack the bytes into ints -+ // and to know when to compute the block and start the next one. -+ private int W[] = new int[80]; -+ private long count = 0; -+ private final int countmax = 64; -+ private final int countmask = (countmax - 1); -+ -+ private int AA, BB, CC, DD, EE; -+ -+ SHA(int version) { -+ this(); -+ this.version = version; -+ } -+ -+ /** -+ * Creates a new SHA object. -+ */ -+ public SHA() { -+ init(); -+ } -+ -+ /** -+ * Return the length of the digest in bytes -+ */ -+ protected int engineGetDigestLength() { -+ return (SHA_LENGTH); -+ } -+ -+ public void engineUpdate(byte b) { -+ engineUpdate((int) b); -+ } -+ -+ /** -+ * Update a byte. -+ * -+ * @param b the byte -+ */ -+ private void engineUpdate(int b) { -+ int word; -+ int offset; -+ -+ /* compute word offset and bit offset within word the low bits -+ of count are inverted to make put the bytes in the write -+ order */ -+ word = ((int) count & countmask) >>> 2; -+ offset = (~(int) count & 3) << 3; -+ -+ W[word] = (W[word] & ~(0xff << offset)) | ((b & 0xff) << offset); -+ -+ /* If this is the last byte of a block, compute the partial hash */ -+ if (((int) count & countmask) == countmask) { -+ computeBlock(); -+ } -+ count++; -+ } -+ -+ /** -+ * Update a buffer. -+ * -+ * @param b the data to be updated. -+ * @param off the start offset in the data -+ * @param len the number of bytes to be updated. -+ */ -+ public void engineUpdate(byte b[], int off, int len) { -+ int word; -+ -+ if ((off < 0) || (len < 0) || (off + len > b.length)) -+ throw new ArrayIndexOutOfBoundsException(); -+ -+ // Use single writes until integer aligned -+ while ((len > 0) && -+ ((int) count & 3) != 0) { -+ engineUpdate(b[off]); -+ off++; -+ len--; -+ } -+ -+ /* Assemble groups of 4 bytes to be inserted in integer array */ -+ for (; len >= 4; len -= 4, off += 4) { -+ -+ word = ((int) count & countmask) >> 2; -+ -+ W[word] = ((b[off] & 0xff) << 24) | -+ ((b[off + 1] & 0xff) << 16) | -+ ((b[off + 2] & 0xff) << 8) | -+ ((b[off + 3] & 0xff)); -+ -+ count += 4; -+ if (((int) count & countmask) == 0) { -+ computeBlock(); -+ } -+ } -+ -+ /* Use single writes for last few bytes */ -+ for (; len > 0; len--, off++) { -+ engineUpdate(b[off]); -+ } -+ } -+ -+ /** -+ * Resets the buffers and hash value to start a new hash. -+ */ -+ public void init() { -+ AA = 0x67452301; -+ BB = 0xefcdab89; -+ CC = 0x98badcfe; -+ DD = 0x10325476; -+ EE = 0xc3d2e1f0; -+ -+ for (int i = 0; i < 80; i++) -+ W[i] = 0; -+ count = 0; -+ } -+ -+ /** -+ * Resets the buffers and hash value to start a new hash. -+ */ -+ public void engineReset() { -+ init(); -+ } -+ -+ /** -+ * Computes the final hash and returns the final value as a -+ * byte[20] array. The object is reset to be ready for further -+ * use, as specified in the JavaSecurity MessageDigest -+ * specification. -+ */ -+ public byte[] engineDigest() { -+ byte hashvalue[] = new byte[SHA_LENGTH]; -+ -+ try { -+ engineDigest(hashvalue, 0, hashvalue.length); -+ } catch (DigestException e) { -+ throw new InternalError(""); -+ } -+ return hashvalue; -+ } -+ -+ /** -+ * Computes the final hash and returns the final value as a -+ * byte[20] array. The object is reset to be ready for further -+ * use, as specified in the JavaSecurity MessageDigest -+ * specification. -+ */ -+ public int engineDigest(byte[] hashvalue, int offset, int len) -+ throws DigestException { -+ -+ if (len < SHA_LENGTH) -+ throw new DigestException("partial digests not returned"); -+ if (hashvalue.length - offset < SHA_LENGTH) -+ throw new DigestException("insufficient space in the output " + -+ "buffer to store the digest"); -+ -+ /* The number of bits before padding occurs */ -+ long bits = count << 3; -+ -+ engineUpdate(0x80); -+ -+ /* Pad with zeros until length is a multiple of 448 (the last two -+ 32 ints are used a holder for bits (see above). */ -+ while ((int) (count & countmask) != 56) { -+ engineUpdate(0); -+ } -+ -+ W[14] = (int) (bits >>> 32); -+ W[15] = (int) (bits & 0xffffffff); -+ -+ count += 8; -+ computeBlock(); -+ -+ // Copy out the result -+ hashvalue[offset + 0] = (byte) (AA >>> 24); -+ hashvalue[offset + 1] = (byte) (AA >>> 16); -+ hashvalue[offset + 2] = (byte) (AA >>> 8); -+ hashvalue[offset + 3] = (byte) (AA >>> 0); -+ -+ hashvalue[offset + 4] = (byte) (BB >>> 24); -+ hashvalue[offset + 5] = (byte) (BB >>> 16); -+ hashvalue[offset + 6] = (byte) (BB >>> 8); -+ hashvalue[offset + 7] = (byte) (BB >>> 0); -+ -+ hashvalue[offset + 8] = (byte) (CC >>> 24); -+ hashvalue[offset + 9] = (byte) (CC >>> 16); -+ hashvalue[offset + 10] = (byte) (CC >>> 8); -+ hashvalue[offset + 11] = (byte) (CC >>> 0); -+ -+ hashvalue[offset + 12] = (byte) (DD >>> 24); -+ hashvalue[offset + 13] = (byte) (DD >>> 16); -+ hashvalue[offset + 14] = (byte) (DD >>> 8); -+ hashvalue[offset + 15] = (byte) (DD >>> 0); -+ -+ hashvalue[offset + 16] = (byte) (EE >>> 24); -+ hashvalue[offset + 17] = (byte) (EE >>> 16); -+ hashvalue[offset + 18] = (byte) (EE >>> 8); -+ hashvalue[offset + 19] = (byte) (EE >>> 0); -+ -+ engineReset(); // remove the evidence -+ -+ return SHA_LENGTH; -+ } -+ -+ // Constants for each round -+ private final int round1_kt = 0x5a827999; -+ private final int round2_kt = 0x6ed9eba1; -+ private final int round3_kt = 0x8f1bbcdc; -+ private final int round4_kt = 0xca62c1d6; -+ -+ /** -+ * Compute a the hash for the current block. -+ * -+ * This is in the same vein as Peter Gutmann's algorithm listed in -+ * the back of Applied Cryptography, Compact implementation of -+ * "old" NIST Secure Hash Algorithm. -+ * -+ */ -+ private void computeBlock() { -+ int temp, a, b, c, d, e; -+ -+ // The first 16 ints have the byte stream, compute the rest of -+ // the buffer -+ for (int t = 16; t <= 79; t++) { -+ if (version == 0) { -+ W[t] = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; -+ } else { -+ temp = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; -+ W[t] = ((temp << 1) | (temp >>> (32 - 1))); -+ } -+ } -+ -+ a = AA; -+ b = BB; -+ c = CC; -+ d = DD; -+ e = EE; -+ -+ // Round 1 -+ for (int i = 0; i < 20; i++) { -+ temp = ((a << 5) | (a >>> (32 - 5))) + -+ ((b & c) | ((~b) & d)) + e + W[i] + round1_kt; -+ e = d; -+ d = c; -+ c = ((b << 30) | (b >>> (32 - 30))); -+ b = a; -+ a = temp; -+ } -+ -+ // Round 2 -+ for (int i = 20; i < 40; i++) { -+ temp = ((a << 5) | (a >>> (32 - 5))) + -+ (b ^ c ^ d) + e + W[i] + round2_kt; -+ e = d; -+ d = c; -+ c = ((b << 30) | (b >>> (32 - 30))); -+ b = a; -+ a = temp; -+ } -+ -+ // Round 3 -+ for (int i = 40; i < 60; i++) { -+ temp = ((a << 5) | (a >>> (32 - 5))) + -+ ((b & c) | (b & d) | (c & d)) + e + W[i] + round3_kt; -+ e = d; -+ d = c; -+ c = ((b << 30) | (b >>> (32 - 30))); -+ b = a; -+ a = temp; -+ } -+ -+ // Round 4 -+ for (int i = 60; i < 80; i++) { -+ temp = ((a << 5) | (a >>> (32 - 5))) + -+ (b ^ c ^ d) + e + W[i] + round4_kt; -+ e = d; -+ d = c; -+ c = ((b << 30) | (b >>> (32 - 30))); -+ b = a; -+ a = temp; -+ } -+ AA += a; -+ BB += b; -+ CC += c; -+ DD += d; -+ EE += e; -+ } -+ -+ /* -+ * Clones this object. -+ */ -+ public Object clone() { -+ SHA that = null; -+ try { -+ that = (SHA) super.clone(); -+ that.W = new int[80]; -+ System.arraycopy(this.W, 0, that.W, 0, W.length); -+ return that; -+ } catch (CloneNotSupportedException e) { -+ } -+ return that; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/provider/Sun.java b/org/mozilla/jss/netscape/security/provider/Sun.java -new file mode 100644 -index 00000000..94e72ef4 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/Sun.java -@@ -0,0 +1,135 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.security.Provider; -+ -+/** -+ * The SUN Security Provider. -+ * -+ * @author Benjamin Renaud -+ * -+ * @version 1.24, 97/12/10 -+ */ -+ -+/** -+ * Defines the SUN provider. -+ * -+ * Algorithm supported, and their names: -+ * -+ * - SHA-1 is the message digest scheme decribed FIPS 180-1. -+ * Aliases for SHA-1 are SHA. -+ * -+ * - DSA is the signature scheme described in FIPS 186. (SHA used in -+ * DSA is SHA-1: FIPS 186 with Change No 1.) Aliases for DSA are -+ * SHA/DSA, SHA-1/DSA, SHA1/DSA, DSS and the object identifier -+ * strings "OID.1.3.14.3.2.13", "OID.1.3.14.3.2.27" and -+ * "OID.1.2.840.10040.4.3". -+ * -+ * - DSA is the key generation scheme as described in FIPS 186. -+ * Aliases for DSA include the OID strings "OID.1.3.14.3.2.12" -+ * and "OID.1.2.840.10040.4.1". -+ * -+ * - MD5 is the message digest scheme described in RFC 1321. -+ * There are no aliases for MD5. -+ * -+ * Notes: The name of algorithm described in FIPS-180 is SHA-0, and is -+ * not supported by the SUN provider.) -+ */ -+public final class Sun extends Provider { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 9134942296334703727L; -+ private static String info = "SUN Security Provider v1.0, " + -+ "DSA signing and key generation, SHA-1 and MD5 message digests."; -+ -+ public Sun() { -+ /* We are the SUN provider */ -+ super("SUN", 1.0, info); -+ -+ try { -+ -+ // AccessController.beginPrivileged(); -+ -+ /* -+ * Signature engines -+ */ -+ put("Signature.DSA", "org.mozilla.jss.netscape.security.provider.DSA"); -+ -+ put("Alg.Alias.Signature.SHA/DSA", "DSA"); -+ put("Alg.Alias.Signature.SHA1/DSA", "DSA"); -+ put("Alg.Alias.Signature.SHA-1/DSA", "DSA"); -+ put("Alg.Alias.Signature.DSS", "DSA"); -+ put("Alg.Alias.Signature.OID.1.3.14.3.2.13", "DSA"); -+ put("Alg.Alias.Signature.OID.1.3.14.3.2.27", "DSA"); -+ put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", "DSA"); -+ // the following are not according to our formal spec but -+ // are still supported -+ put("Alg.Alias.Signature.1.3.14.3.2.13", "DSA"); -+ put("Alg.Alias.Signature.1.3.14.3.2.27", "DSA"); -+ put("Alg.Alias.Signature.1.2.840.10040.4.3", "DSA"); -+ put("Alg.Alias.Signature.SHAwithDSA", "DSA"); -+ put("Alg.Alias.Signature.SHA1withDSA", "DSA"); -+ -+ /* -+ * Key Pair Generator engines -+ */ -+ put("KeyPairGenerator.DSA", -+ "org.mozilla.jss.netscape.security.provider.DSAKeyPairGenerator"); -+ -+ put("Alg.Alias.KeyPairGenerator.OID.1.3.14.3.2.12", "DSA"); -+ put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA"); -+ // the following are not according to our formal spec but -+ // are still supported -+ put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA"); -+ put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA"); -+ -+ /* -+ * Digest engines -+ */ -+ put("MessageDigest.MD5", "org.mozilla.jss.netscape.security.provider.MD5"); -+ put("MessageDigest.SHA-1", "org.mozilla.jss.netscape.security.provider.SHA"); -+ -+ put("Alg.Alias.MessageDigest.SHA", "SHA-1"); -+ put("Alg.Alias.MessageDigest.SHA1", "SHA-1"); -+ -+ /* -+ * Algorithm Parameter Generator engines -+ */ -+ put("AlgorithmParameterGenerator.DSA", -+ "org.mozilla.jss.netscape.security.provider.DSAParameterGenerator"); -+ -+ /* -+ * Algorithm Parameter engines -+ */ -+ put("AlgorithmParameters.DSA", -+ "org.mozilla.jss.netscape.security.provider.DSAParameters"); -+ put("Alg.Alias.AlgorithmParameters.1.3.14.3.2.12", "DSA"); -+ put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.1", "DSA"); -+ /* -+ * Key factories -+ */ -+ put("KeyFactory.DSA", "org.mozilla.jss.netscape.security.provider.DSAKeyFactory"); -+ -+ } finally { -+ // AccessController.endPrivileged(); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/provider/X509CertificateFactory.java b/org/mozilla/jss/netscape/security/provider/X509CertificateFactory.java -new file mode 100644 -index 00000000..ab579299 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/X509CertificateFactory.java -@@ -0,0 +1,61 @@ -+// --- 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 org.mozilla.jss.netscape.security.provider; -+ -+import java.io.InputStream; -+import java.security.cert.CRL; -+import java.security.cert.CRLException; -+import java.security.cert.Certificate; -+import java.security.cert.CertificateException; -+import java.security.cert.CertificateFactorySpi; -+import java.util.Collection; -+ -+import org.mozilla.jss.netscape.security.x509.X509CRLImpl; -+import org.mozilla.jss.netscape.security.x509.X509CertImpl; -+import org.mozilla.jss.netscape.security.x509.X509ExtensionException; -+ -+public class X509CertificateFactory extends CertificateFactorySpi { -+ -+ public Certificate engineGenerateCertificate(InputStream inStream) -+ throws CertificateException { -+ return new X509CertImpl(inStream); -+ } -+ -+ public Collection engineGenerateCertificates(InputStream inStream) -+ throws CertificateException { -+ return null; -+ } -+ -+ public CRL engineGenerateCRL(InputStream inStream) -+ throws CRLException { -+ X509CRLImpl crl = null; -+ try { -+ crl = new X509CRLImpl(inStream); -+ } catch (X509ExtensionException e) { -+ ; -+ } -+ -+ return crl; -+ } -+ -+ public Collection engineGenerateCRLs(InputStream inStream) -+ throws CRLException { -+ return null; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/provider/manifest.mn b/org/mozilla/jss/netscape/security/provider/manifest.mn -new file mode 100644 -index 00000000..3073171c ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/provider/manifest.mn -@@ -0,0 +1,8 @@ -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+CORE_DEPTH = ../../../../../.. -+PACKAGE = org/mozilla/jss/netscape/security/provider -+MODULE = jss -diff --git a/org/mozilla/jss/netscape/security/util/ASN1CharStrConvMap.java b/org/mozilla/jss/netscape/security/util/ASN1CharStrConvMap.java -new file mode 100644 -index 00000000..c4f82679 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/ASN1CharStrConvMap.java -@@ -0,0 +1,168 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetDecoder; -+import java.nio.charset.CharsetEncoder; -+import java.util.HashMap; -+import java.util.Iterator; -+import java.util.Map; -+ -+/** -+ * Maps a ASN.1 character string type to a charset encoder and decoder. -+ * The converter is used to convert a DerValue of a ASN.1 character string type -+ * from bytes to unicode characters and vice versa. -+ * -+ *

-+ * A global default ASN1CharStrConvMap is created when the class is initialized. The global default map is extensible. -+ * -+ * @author Lily Hsiao -+ * @author Slava Galperin -+ * -+ */ -+ -+public class ASN1CharStrConvMap { -+ // public constructors -+ -+ /** -+ * Constructs a ASN1CharStrConvMap. -+ */ -+ public ASN1CharStrConvMap() { -+ } -+ -+ /** -+ * Get an encoder for the specified DER tag. -+ * -+ * @param tag A DER tag of a ASN.1 character string type, -+ * for example DerValue.tag_PrintableString. -+ * -+ * @return An encoder for the DER tag. -+ */ -+ public CharsetEncoder getEncoder(byte tag) { -+ Charset charset = charsets.get(tag); -+ if (charset == null) -+ return null; -+ return charset.newEncoder(); -+ } -+ -+ /** -+ * Get a decoder for the given DER tag. -+ * -+ * @param tag A DER tag of a ASN.1 character string type, -+ * for example DerValue.tag_PrintableString. -+ * -+ * @return A decoder for the DER tag. -+ */ -+ public CharsetDecoder getDecoder(byte tag) { -+ Charset charset = charsets.get(tag); -+ if (charset == null) -+ return null; -+ return charset.newDecoder(); -+ } -+ -+ /** -+ * Add a tag-charset entry in the map. -+ * -+ * @param tag A DER tag of a ASN.1 character string type, -+ * ex. DerValue.tag_IA5String -+ * @param charset A charset for the tag. -+ */ -+ public void addEntry(byte tag, Charset charset) { -+ -+ Charset currentCharset = charsets.get(tag); -+ -+ if (currentCharset != null) { -+ if (currentCharset != charset) { -+ throw new IllegalArgumentException( -+ "a DER tag to converter entry already exists."); -+ } else { -+ return; -+ } -+ } -+ -+ charsets.put(tag, charset); -+ } -+ -+ /** -+ * Get an iterator of all tags in the map. -+ * -+ * @return An Iterator of DER tags in the map as Bytes. -+ */ -+ public Iterator getTags() { -+ return charsets.keySet().iterator(); -+ } -+ -+ // static public methods. -+ -+ /** -+ * Get the global ASN1CharStrConvMap. -+ * -+ * @return The global default ASN1CharStrConvMap. -+ */ -+ static public ASN1CharStrConvMap getDefault() { -+ return defaultMap; -+ } -+ -+ /** -+ * Set the global default ASN1CharStrConvMap. -+ * -+ * @param newDefault The new default ASN1CharStrConvMap. -+ */ -+ static public void setDefault(ASN1CharStrConvMap newDefault) { -+ if (newDefault == null) -+ throw new IllegalArgumentException( -+ "Cannot set a null default Der Tag Converter map"); -+ defaultMap = newDefault; -+ } -+ -+ // private methods and variables. -+ -+ private Map charsets = new HashMap(); -+ -+ private static ASN1CharStrConvMap defaultMap; -+ -+ /** -+ * Create the default converter map on initialization -+ */ -+ static { -+ ASN1CharsetProvider provider = new ASN1CharsetProvider(); -+ -+ defaultMap = new ASN1CharStrConvMap(); -+ defaultMap.addEntry(DerValue.tag_PrintableString, -+ provider.charsetForName("ASN.1-Printable")); -+ defaultMap.addEntry(DerValue.tag_VisibleString, -+ provider.charsetForName("ASN.1-Printable")); -+ defaultMap.addEntry(DerValue.tag_IA5String, -+ provider.charsetForName("ASN.1-IA5")); -+ defaultMap.addEntry(DerValue.tag_BMPString, -+ Charset.forName("UnicodeBig")); -+ defaultMap.addEntry(DerValue.tag_UniversalString, -+ provider.charsetForName("ASN.1-Universal")); -+ // XXX this is an oversimplified implementation of T.61 strings, it -+ // doesn't handle all cases -+ defaultMap.addEntry(DerValue.tag_T61String, -+ Charset.forName("ISO-8859-1")); -+ // UTF8String added to ASN.1 in 1998 -+ defaultMap.addEntry(DerValue.tag_UTF8String, -+ Charset.forName("UTF-8")); -+ defaultMap.addEntry(DerValue.tag_GeneralString, -+ Charset.forName("UTF-8")); -+ }; -+ -+}; -diff --git a/org/mozilla/jss/netscape/security/util/ASN1CharsetProvider.java b/org/mozilla/jss/netscape/security/util/ASN1CharsetProvider.java -new file mode 100644 -index 00000000..9ac4698b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/ASN1CharsetProvider.java -@@ -0,0 +1,30 @@ -+package org.mozilla.jss.netscape.security.util; -+ -+import java.nio.charset.Charset; -+import java.nio.charset.spi.CharsetProvider; -+import java.util.HashMap; -+import java.util.Iterator; -+import java.util.Map; -+ -+public class ASN1CharsetProvider extends CharsetProvider { -+ -+ protected Map charsets = new HashMap(); -+ -+ public ASN1CharsetProvider() { -+ addCharset(new PrintableCharset()); -+ addCharset(new IA5Charset()); -+ addCharset(new UniversalCharset()); -+ } -+ -+ public Iterator charsets() { -+ return charsets.values().iterator(); -+ } -+ -+ public Charset charsetForName(String charsetName) { -+ return charsets.get(charsetName); -+ } -+ -+ public void addCharset(Charset cs) { -+ charsets.put(cs.name(), cs); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/BigInt.java b/org/mozilla/jss/netscape/security/util/BigInt.java -new file mode 100644 -index 00000000..e3ba42b8 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/BigInt.java -@@ -0,0 +1,221 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.Serializable; -+import java.math.BigInteger; -+import java.util.Arrays; -+ -+/** -+ * A low-overhead arbitrary-precision unsigned integer. -+ * This is intended for use with ASN.1 parsing, and printing of -+ * such parsed values. Convert to "BigInteger" if you need to do -+ * arbitrary precision arithmetic, rather than just represent -+ * the number as a wrapped array of bytes. -+ * -+ *

-+ * NOTE: This class may eventually disappear, to -+ * be supplanted by big-endian byte arrays which hold both signed -+ * and unsigned arbitrary-precision integers. -+ * -+ * @version 1.23 -+ * @author David Brownell -+ */ -+public final class BigInt implements Serializable { -+ -+ private static final long serialVersionUID = 705094142021888265L; -+ // Big endian -- MSB first. -+ private byte[] places; -+ -+ /** -+ * Constructs a "Big" integer from a set of (big-endian) bytes. -+ * Leading zeroes should be stripped off. -+ * -+ * @param data a sequence of bytes, most significant bytes/digits -+ * first. CONSUMED. -+ */ -+ public BigInt(byte[] data) { -+ places = data.clone(); -+ } -+ -+ /** -+ * Constructs a "Big" integer from a "BigInteger", which must be -+ * positive (or zero) in value. -+ */ -+ public BigInt(BigInteger i) { -+ byte[] temp = i.toByteArray(); -+ -+ if ((temp[0] & 0x80) != 0) -+ throw new IllegalArgumentException("negative BigInteger"); -+ -+ // XXX we assume exactly _one_ sign byte is used... -+ -+ if (temp[0] != 0) -+ places = temp; -+ else { -+ // Note that if i = new BigInteger("0"), -+ // i.toByteArray() contains only 1 zero. -+ if (temp.length == 1) { -+ places = new byte[1]; -+ places[0] = (byte) 0; -+ } else { -+ places = new byte[temp.length - 1]; -+ for (int j = 1; j < temp.length; j++) -+ places[j - 1] = temp[j]; -+ } -+ } -+ } -+ -+ /** -+ * Constructs a "Big" integer from a normal Java integer. -+ * -+ * @param i the java primitive integer -+ */ -+ public BigInt(int i) { -+ if (i < (1 << 8)) { -+ places = new byte[1]; -+ places[0] = (byte) i; -+ } else if (i < (1 << 16)) { -+ places = new byte[2]; -+ places[0] = (byte) (i >> 8); -+ places[1] = (byte) i; -+ } else if (i < (1 << 24)) { -+ places = new byte[3]; -+ places[0] = (byte) (i >> 16); -+ places[1] = (byte) (i >> 8); -+ places[2] = (byte) i; -+ } else { -+ places = new byte[4]; -+ places[0] = (byte) (i >> 24); -+ places[1] = (byte) (i >> 16); -+ places[2] = (byte) (i >> 8); -+ places[3] = (byte) i; -+ } -+ } -+ -+ /** -+ * Converts the "big" integer to a java primitive integer. -+ * -+ * @exception NumberFormatException if 32 bits is insufficient. -+ */ -+ public int toInt() { -+ if (places.length > 4) -+ throw new NumberFormatException("BigInt.toInt, too big"); -+ int retval = 0, i = 0; -+ for (; i < places.length; i++) -+ retval = (retval << 8) + (places[i] & 0xff); -+ return retval; -+ } -+ -+ /** -+ * Returns a hexadecimal printed representation. The value is -+ * formatted to fit on lines of at least 75 characters, with -+ * embedded newlines. Words are separated for readability, -+ * with eight words (32 bytes) per line. -+ */ -+ public String toString() { -+ return hexify(); -+ } -+ -+ /** -+ * Returns a BigInteger value which supports many arithmetic -+ * operations. Assumes negative values will never occur. -+ */ -+ public BigInteger toBigInteger() { -+ return new BigInteger(1, places); -+ } -+ -+ /** -+ * Returns the length of the data as a byte array. -+ */ -+ public int byteLength() { -+ return places.length; -+ } -+ -+ /** -+ * Returns the data as a byte array. The most significant bit -+ * of the array is bit zero (as in java.math.BigInteger). -+ */ -+ public byte[] toByteArray() { -+ if (places.length == 0) { -+ byte zero[] = new byte[1]; -+ zero[0] = (byte) 0; -+ return zero; -+ } else { -+ return places.clone(); -+ } -+ } -+ -+ private static final String digits = "0123456789abcdef"; -+ -+ private String hexify() { -+ if (places.length == 0) -+ return " 0 "; -+ -+ StringBuffer buf = new StringBuffer(places.length * 2); -+ buf.append(" "); // four spaces -+ for (int i = 0; i < places.length; i++) { -+ buf.append(digits.charAt((places[i] >> 4) & 0x0f)); -+ buf.append(digits.charAt(places[i] & 0x0f)); -+ if (((i + 1) % 32) == 0) { -+ if ((i + 1) != places.length) -+ buf.append("\n "); // line after four words -+ } else if (((i + 1) % 4) == 0) -+ buf.append(' '); // space between words -+ } -+ return buf.toString(); -+ } -+ -+ /** -+ * Returns true iff the parameter is a numerically equivalent -+ * BigInt. -+ * -+ * @param other the object being compared with this one. -+ */ -+ public boolean equals(Object other) { -+ if (other instanceof BigInt) -+ return equals((BigInt) other); -+ return false; -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + Arrays.hashCode(places); -+ return result; -+ } -+ -+ /** -+ * Returns true iff the parameter is numerically equivalent. -+ * -+ * @param other the BigInt being compared with this one. -+ */ -+ public boolean equals(BigInt other) { -+ if (this == other) -+ return true; -+ -+ byte[] otherPlaces = other.toByteArray(); -+ if (places.length != otherPlaces.length) -+ return false; -+ for (int i = 0; i < places.length; i++) -+ if (places[i] != otherPlaces[i]) -+ return false; -+ return true; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/BitArray.java b/org/mozilla/jss/netscape/security/util/BitArray.java -new file mode 100644 -index 00000000..5c77ac2c ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/BitArray.java -@@ -0,0 +1,257 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.ByteArrayOutputStream; -+ -+/** -+ * A packed array of booleans. -+ * -+ * @author Joshua Bloch -+ * @author Douglas Hoover -+ * @version 1.2 97/12/10 -+ */ -+ -+public class BitArray { -+ -+ private byte[] repn; -+ private int length; -+ -+ private static final int BITS_PER_UNIT = 8; -+ -+ private static int subscript(int idx) { -+ return idx / BITS_PER_UNIT; -+ } -+ -+ private static int position(int idx) { // bits big-endian in each unit -+ return 1 << (BITS_PER_UNIT - 1 - (idx % BITS_PER_UNIT)); -+ } -+ -+ /** -+ * Creates a BitArray of the specified size, initialized to zeros. -+ */ -+ public BitArray(int length) throws IllegalArgumentException { -+ if (length < 0) { -+ throw new IllegalArgumentException("Negative length for BitArray"); -+ } -+ -+ this.length = length; -+ -+ repn = new byte[(length + BITS_PER_UNIT - 1) / BITS_PER_UNIT]; -+ } -+ -+ /** -+ * Creates a BitArray of the specified size, initialized from the -+ * specified byte array. The most significant bit of a[0] gets -+ * index zero in the BitArray. The array a must be large enough -+ * to specify a value for every bit in the BitArray. In other words, -+ * 8*a.length >= length. -+ */ -+ public BitArray(int length, byte[] a) throws IllegalArgumentException { -+ -+ if (length < 0) { -+ throw new IllegalArgumentException("Negative length for BitArray"); -+ } -+ if (a.length * BITS_PER_UNIT < length) { -+ throw new IllegalArgumentException("Byte array too short to represent " + -+ "bit array of given length"); -+ } -+ -+ this.length = length; -+ -+ int repLength = ((length + BITS_PER_UNIT - 1) / BITS_PER_UNIT); -+ int unusedBits = repLength * BITS_PER_UNIT - length; -+ byte bitMask = (byte) (0xFF << unusedBits); -+ -+ /* -+ normalize the representation: -+ 1. discard extra bytes -+ 2. zero out extra bits in the last byte -+ */ -+ repn = new byte[repLength]; -+ System.arraycopy(a, 0, repn, 0, repLength); -+ if (repn.length > 0) -+ repn[repn.length - 1] = (byte) (repn[repn.length - 1] & bitMask); -+ } -+ -+ /** -+ * Create a BitArray whose bits are those of the given array -+ * of Booleans. -+ */ -+ public BitArray(boolean[] bits) { -+ length = bits.length; -+ repn = new byte[(length + 7) / 8]; -+ -+ for (int i = 0; i < length; i++) { -+ set(i, bits[i]); -+ } -+ } -+ -+ /** -+ * Copy constructor (for cloning). -+ */ -+ private BitArray(BitArray ba) { -+ length = ba.length; -+ repn = ba.repn.clone(); -+ } -+ -+ /** -+ * Returns the indexed bit in this BitArray. -+ */ -+ public boolean get(int index) throws ArrayIndexOutOfBoundsException { -+ if (index < 0 || index >= length) { -+ throw new ArrayIndexOutOfBoundsException(Integer.toString(index)); -+ } -+ -+ return (repn[subscript(index)] & position(index)) != 0; -+ } -+ -+ /** -+ * Sets the indexed bit in this BitArray. -+ */ -+ public void set(int index, boolean value) -+ throws ArrayIndexOutOfBoundsException { -+ if (index < 0 || index >= length) { -+ throw new ArrayIndexOutOfBoundsException(Integer.toString(index)); -+ } -+ int idx = subscript(index); -+ int bit = position(index); -+ -+ if (value) { -+ repn[idx] |= bit; -+ } else { -+ repn[idx] &= ~bit; -+ } -+ } -+ -+ /** -+ * Returns the length of this BitArray. -+ */ -+ public int length() { -+ return length; -+ } -+ -+ /** -+ * Returns a Byte array containing the contents of this BitArray. -+ * The bit stored at index zero in this BitArray will be copied -+ * into the most significant bit of the zeroth element of the -+ * returned byte array. The last byte of the returned byte array -+ * will be contain zeros in any bits that do not have corresponding -+ * bits in the BitArray. (This matters only if the BitArray's size -+ * is not a multiple of 8.) -+ */ -+ public byte[] toByteArray() { -+ return repn.clone(); -+ } -+ -+ public boolean equals(Object obj) { -+ if (obj == this) -+ return true; -+ if (obj == null || !(obj instanceof BitArray)) -+ return false; -+ -+ BitArray ba = (BitArray) obj; -+ -+ if (ba.length != length) -+ return false; -+ -+ for (int i = 0; i < repn.length; i += 1) { -+ if (repn[i] != ba.repn[i]) -+ return false; -+ } -+ return true; -+ } -+ -+ /** -+ * Return a boolean array with the same bit values a this BitArray. -+ */ -+ public boolean[] toBooleanArray() { -+ boolean[] bits = new boolean[length]; -+ -+ for (int i = 0; i < length; i++) { -+ bits[i] = get(i); -+ } -+ return bits; -+ } -+ -+ /** -+ * Returns a hash code value for this bit array. -+ * -+ * @return a hash code value for this bit array. -+ */ -+ public int hashCode() { -+ int hashCode = 0; -+ -+ for (int i = 0; i < repn.length; i++) -+ hashCode = 31 * hashCode + repn[i]; -+ -+ return hashCode ^ length; -+ } -+ -+ public Object clone() { -+ return new BitArray(this); -+ } -+ -+ private static final byte[][] NYBBLE = { -+ { (byte) '0', (byte) '0', (byte) '0', (byte) '0' }, -+ { (byte) '0', (byte) '0', (byte) '0', (byte) '1' }, -+ { (byte) '0', (byte) '0', (byte) '1', (byte) '0' }, -+ { (byte) '0', (byte) '0', (byte) '1', (byte) '1' }, -+ { (byte) '0', (byte) '1', (byte) '0', (byte) '0' }, -+ { (byte) '0', (byte) '1', (byte) '0', (byte) '1' }, -+ { (byte) '0', (byte) '1', (byte) '1', (byte) '0' }, -+ { (byte) '0', (byte) '1', (byte) '1', (byte) '1' }, -+ { (byte) '1', (byte) '0', (byte) '0', (byte) '0' }, -+ { (byte) '1', (byte) '0', (byte) '0', (byte) '1' }, -+ { (byte) '1', (byte) '0', (byte) '1', (byte) '0' }, -+ { (byte) '1', (byte) '0', (byte) '1', (byte) '1' }, -+ { (byte) '1', (byte) '1', (byte) '0', (byte) '0' }, -+ { (byte) '1', (byte) '1', (byte) '0', (byte) '1' }, -+ { (byte) '1', (byte) '1', (byte) '1', (byte) '0' }, -+ { (byte) '1', (byte) '1', (byte) '1', (byte) '1' } -+ }; -+ -+ private static final int BYTES_PER_LINE = 8; -+ -+ /** -+ * Returns a string representation of this BitArray. -+ */ -+ public String toString() { -+ ByteArrayOutputStream out = new ByteArrayOutputStream(); -+ -+ for (int i = 0; i < repn.length - 1; i++) { -+ out.write(NYBBLE[(repn[i] >> 4) & 0x0F], 0, 4); -+ out.write(NYBBLE[repn[i] & 0x0F], 0, 4); -+ -+ if (i % BYTES_PER_LINE == BYTES_PER_LINE - 1) { -+ out.write('\n'); -+ } else { -+ out.write(' '); -+ } -+ } -+ -+ // in last byte of repn, use only the valid bits -+ for (int i = BITS_PER_UNIT * (repn.length - 1); i < length; i++) { -+ out.write(get(i) ? '1' : '0'); -+ } -+ -+ return new String(out.toByteArray()); -+ -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/util/ByteArrayLexOrder.java b/org/mozilla/jss/netscape/security/util/ByteArrayLexOrder.java -new file mode 100644 -index 00000000..2747721a ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/ByteArrayLexOrder.java -@@ -0,0 +1,60 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.util.Comparator; -+ -+/** -+ * Compare two byte arrays in lexicographical order. -+ * -+ * @version 1.4 97/12/10 -+ * @author D. N. Hoover -+ */ -+public class ByteArrayLexOrder implements Comparator, java.io.Serializable { -+ -+ private static final long serialVersionUID = 1897537410212918669L; -+ -+ /** -+ * Perform lexicographical comparison of two byte arrays, -+ * regarding each byte as unsigned. That is, compare array entries -+ * in order until they differ--the array with the smaller entry -+ * is "smaller". If array entries are -+ * equal till one array ends, then the longer array is "bigger". -+ * -+ * @param obj1 first byte array to compare. -+ * @param obj2 second byte array to compare. -+ * @return negative number if obj1 < obj2, 0 if obj1 == obj2, -+ * positive number if obj1 > obj2. -+ * -+ * @exception ClassCastException if either argument is not a byte array. -+ */ -+ public final int compare(byte[] bytes1, byte[] bytes2) { -+ -+ int diff; -+ for (int i = 0; i < bytes1.length && i < bytes2.length; i++) { -+ diff = (bytes1[i] & 0xFF) - (bytes2[i] & 0xFF); -+ if (diff != 0) { -+ return diff; -+ } -+ } -+ // if array entries are equal till the first ends, then the -+ // longer is "bigger" -+ return bytes1.length - bytes2.length; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/util/ByteArrayTagOrder.java b/org/mozilla/jss/netscape/security/util/ByteArrayTagOrder.java -new file mode 100644 -index 00000000..02f9687e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/ByteArrayTagOrder.java -@@ -0,0 +1,46 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.util.Comparator; -+ -+public class ByteArrayTagOrder implements Comparator, java.io.Serializable { -+ -+ private static final long serialVersionUID = -2027007556858126443L; -+ -+ /** -+ * Compare two byte arrays, by the order of their tags, -+ * as defined in ITU-T X.680, sec. 6.4. (First compare -+ * tag classes, then tag numbers, ignoring the constructivity bit.) -+ * -+ * @param obj1 first byte array to compare. -+ * @param obj2 second byte array to compare. -+ * @return negative number if obj1 < obj2, 0 if obj1 == obj2, -+ * positive number if obj1 > obj2. -+ * -+ * @exception ClassCastException if either argument is not a byte array. -+ */ -+ -+ public final int compare(byte[] bytes1, byte[] bytes2) { -+ -+ // tag order is same as byte order ignoring any difference in -+ // the constructivity bit (0x02) -+ return (bytes1[0] | 0x20) - (bytes2[0] | 0x20); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/util/Cert.java b/org/mozilla/jss/netscape/security/util/Cert.java -new file mode 100644 -index 00000000..508b9b86 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/Cert.java -@@ -0,0 +1,201 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.IOException; -+import java.security.cert.CertificateException; -+import java.security.cert.X509CRL; -+import java.security.cert.X509Certificate; -+ -+import org.mozilla.jss.crypto.SignatureAlgorithm; -+ -+import org.mozilla.jss.netscape.security.pkcs.PKCS7; -+import org.mozilla.jss.netscape.security.x509.X509CRLImpl; -+import org.mozilla.jss.netscape.security.x509.X509CertImpl; -+ -+public class Cert { -+ -+ public static final String HEADER = "-----BEGIN CERTIFICATE-----"; -+ public static final String FOOTER = "-----END CERTIFICATE-----"; -+ -+ // From https://www.rfc-editor.org/rfc/rfc7468.txt -+ public static final String REQUEST_HEADER = "-----BEGIN CERTIFICATE REQUEST-----"; -+ public static final String REQUEST_FOOTER = "-----END CERTIFICATE REQUEST-----"; -+ -+ public static SignatureAlgorithm mapAlgorithmToJss(String algname) { -+ if (algname.equals("MD5withRSA")) -+ return SignatureAlgorithm.RSASignatureWithMD5Digest; -+ else if (algname.equals("MD2withRSA")) -+ return SignatureAlgorithm.RSASignatureWithMD2Digest; -+ else if (algname.equals("SHA1withRSA")) -+ return SignatureAlgorithm.RSASignatureWithSHA1Digest; -+ else if (algname.equals("SHA1withDSA")) -+ return SignatureAlgorithm.DSASignatureWithSHA1Digest; -+ else if (algname.equals("SHA256withRSA")) -+ return SignatureAlgorithm.RSASignatureWithSHA256Digest; -+ else if (algname.equals("SHA384withRSA")) -+ return SignatureAlgorithm.RSASignatureWithSHA384Digest; -+ else if (algname.equals("SHA512withRSA")) -+ return SignatureAlgorithm.RSASignatureWithSHA512Digest; -+ else if (algname.equals("SHA1withEC")) -+ return SignatureAlgorithm.ECSignatureWithSHA1Digest; -+ else if (algname.equals("SHA256withEC")) -+ return SignatureAlgorithm.ECSignatureWithSHA256Digest; -+ else if (algname.equals("SHA384withEC")) -+ return SignatureAlgorithm.ECSignatureWithSHA384Digest; -+ else if (algname.equals("SHA512withEC")) -+ return SignatureAlgorithm.ECSignatureWithSHA512Digest; -+ return null; -+ } -+ -+ public static String stripBrackets(String s) { -+ if (s == null) { -+ return s; -+ } -+ -+ if ((s.startsWith(HEADER)) && -+ (s.endsWith(FOOTER))) { -+ return (s.substring(27, (s.length() - 25))); -+ } -+ -+ // To support Thawte's header and footer -+ if ((s.startsWith("-----BEGIN PKCS #7 SIGNED DATA-----")) && -+ (s.endsWith("-----END PKCS #7 SIGNED DATA-----"))) { -+ return (s.substring(35, (s.length() - 33))); -+ } -+ -+ return s; -+ } -+ -+ public static String stripCRLBrackets(String s) { -+ if (s == null) { -+ return s; -+ } -+ if ((s.startsWith("-----BEGIN CERTIFICATE REVOCATION LIST-----")) && -+ (s.endsWith("-----END CERTIFICATE REVOCATION LIST-----"))) { -+ return (s.substring(43, (s.length() - 41))); -+ } -+ return s; -+ } -+ -+ public static String stripCertBrackets(String s) { -+ return stripBrackets(s); -+ } -+ -+ // private static BASE64Decoder mDecoder = new BASE64Decoder(); -+ public static X509CertImpl mapCert(String mime64) -+ throws IOException { -+ mime64 = stripCertBrackets(mime64.trim()); -+ String newval = normalizeCertStr(mime64); -+ // byte rawPub[] = mDecoder.decodeBuffer(newval); -+ byte rawPub[] = Utils.base64decode(newval); -+ X509CertImpl cert = null; -+ -+ try { -+ cert = new X509CertImpl(rawPub); -+ } catch (CertificateException e) { -+ } -+ return cert; -+ } -+ -+ public static X509Certificate[] mapCertFromPKCS7(String mime64) -+ throws IOException { -+ mime64 = stripCertBrackets(mime64.trim()); -+ String newval = normalizeCertStr(mime64); -+ // byte rawPub[] = mDecoder.decodeBuffer(newval); -+ byte rawPub[] = Utils.base64decode(newval); -+ PKCS7 p7 = null; -+ -+ try { -+ p7 = new PKCS7(rawPub); -+ } catch (Exception e) { -+ throw new IOException("p7 is null"); -+ } -+ return p7.getCertificates(); -+ } -+ -+ public static X509CRL mapCRL(String mime64) -+ throws IOException { -+ mime64 = stripCRLBrackets(mime64.trim()); -+ String newval = normalizeCertStr(mime64); -+ // byte rawPub[] = mDecoder.decodeBuffer(newval); -+ byte rawPub[] = Utils.base64decode(newval); -+ X509CRL crl = null; -+ -+ try { -+ crl = new X509CRLImpl(rawPub); -+ } catch (Exception e) { -+ } -+ return crl; -+ } -+ -+ public static X509CRL mapCRL1(String mime64) -+ throws IOException { -+ mime64 = stripCRLBrackets(mime64.trim()); -+ -+ byte rawPub[] = Utils.base64decode(mime64); -+ X509CRL crl = null; -+ -+ try { -+ crl = new X509CRLImpl(rawPub); -+ } catch (Exception e) { -+ throw new IOException(e.toString()); -+ } -+ return crl; -+ } -+ -+ public static String normalizeCertStr(String s) { -+ StringBuffer val = new StringBuffer(); -+ -+ for (int i = 0; i < s.length(); i++) { -+ if (s.charAt(i) == '\n') { -+ continue; -+ } else if (s.charAt(i) == '\r') { -+ continue; -+ } else if (s.charAt(i) == '"') { -+ continue; -+ } else if (s.charAt(i) == ' ') { -+ continue; -+ } -+ val.append(s.charAt(i)); -+ } -+ return val.toString(); -+ } -+ -+ public static String normalizeCertStrAndReq(String s) { -+ StringBuffer val = new StringBuffer(); -+ -+ for (int i = 0; i < s.length(); i++) { -+ if (s.charAt(i) == '\n') { -+ continue; -+ } else if (s.charAt(i) == '\r') { -+ continue; -+ } else if (s.charAt(i) == '"') { -+ continue; -+ } -+ val.append(s.charAt(i)); -+ } -+ return val.toString(); -+ } -+ -+ public static byte[] parseCertificate(String cert) { -+ String encoded = normalizeCertStrAndReq(cert); -+ String b64 = stripBrackets(encoded); -+ return Utils.base64decode(b64); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/CertPrettyPrint.java b/org/mozilla/jss/netscape/security/util/CertPrettyPrint.java -new file mode 100644 -index 00000000..e6a09b06 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/CertPrettyPrint.java -@@ -0,0 +1,346 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.security.MessageDigest; -+import java.security.PublicKey; -+import java.security.cert.Certificate; -+import java.text.DateFormat; -+import java.util.Locale; -+import java.util.ResourceBundle; -+import java.util.TimeZone; -+ -+import org.mozilla.jss.asn1.ASN1Util; -+import org.mozilla.jss.asn1.SET; -+import org.mozilla.jss.pkcs7.ContentInfo; -+import org.mozilla.jss.pkcs7.SignedData; -+ -+ -+import org.mozilla.jss.netscape.security.x509.CertificateExtensions; -+import org.mozilla.jss.netscape.security.x509.CertificateX509Key; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.X509CertImpl; -+import org.mozilla.jss.netscape.security.x509.X509CertInfo; -+import org.mozilla.jss.netscape.security.x509.X509Key; -+ -+/** -+ * This class will display the certificate content in predefined -+ * format. -+ * -+ * @author Jack Pan-Chen -+ * @version $Revision$, $Date$ -+ */ -+public class CertPrettyPrint { -+ -+ /*========================================================== -+ * constants -+ *==========================================================*/ -+ private final static String CUSTOM_LOCALE = "Custom"; -+ -+ /*========================================================== -+ * variables -+ *==========================================================*/ -+ private X509CertImpl mX509Cert = null; -+ private PrettyPrintFormat pp = null; -+ private byte[] mCert_b = null; -+ -+ /*========================================================== -+ * constructors -+ *==========================================================*/ -+ -+ public CertPrettyPrint(Certificate cert) { -+ if (cert instanceof X509CertImpl) -+ mX509Cert = (X509CertImpl) cert; -+ -+ pp = new PrettyPrintFormat(":"); -+ } -+ -+ public CertPrettyPrint(byte[] certb) { -+ mCert_b = certb; -+ pp = new PrettyPrintFormat(":"); -+ } -+ -+ /*========================================================== -+ * public methods -+ *==========================================================*/ -+ -+ /** -+ * This method return string representation of the certificate -+ * in predefined format using specified client local. I18N Support. -+ * -+ * @param clientLocale Locale to be used for localization -+ * @return string representation of the certificate -+ */ -+ public String toString(Locale clientLocale) { -+ -+ if (mX509Cert != null) -+ return X509toString(clientLocale); -+ else if (mCert_b != null) -+ return pkcs7toString(clientLocale); -+ else -+ return null; -+ } -+ -+ public String pkcs7toString(Locale clientLocale) { -+ StringBuffer content=new StringBuffer(); -+ -+ try { -+ mX509Cert = new X509CertImpl(mCert_b); -+ return toString(clientLocale); -+ } catch (Exception e) { -+ } -+ -+ ContentInfo ci = null; -+ try { -+ ci = (ContentInfo) -+ ASN1Util.decode(ContentInfo.getTemplate(), mCert_b); -+ } catch (Exception e) { -+ return ""; -+ } -+ -+ if (ci.getContentType().equals(ContentInfo.SIGNED_DATA)) { -+ SignedData sd = null; -+ try { -+ sd = (SignedData) ci.getInterpretedContent(); -+ } catch (Exception e) { -+ return ""; -+ } -+ -+ if (sd.hasCertificates()) { -+ SET certs = sd.getCertificates(); -+ -+ for (int i = 0; i < certs.size(); i++) { -+ org.mozilla.jss.pkix.cert.Certificate cert = -+ (org.mozilla.jss.pkix.cert.Certificate) certs.elementAt(i); -+ X509CertImpl certImpl = null; -+ try { -+ certImpl = new X509CertImpl( -+ ASN1Util.encode(cert)); -+ } catch (Exception e) { -+ } -+ -+ CertPrettyPrint print = new CertPrettyPrint(certImpl); -+ content.append(print.toString(Locale.getDefault())); -+ content.append("\n"); -+ } -+ -+ return content.toString(); -+ } -+ } -+ -+ return content.toString(); -+ } -+ -+ public String stripCertBrackets(String s) { -+ if (s == null) { -+ return s; -+ } -+ -+ if ((s.startsWith(Cert.HEADER)) && -+ (s.endsWith(Cert.FOOTER))) { -+ return (s.substring(27, (s.length() - 25))); -+ } -+ -+ // To support Thawte's header and footer -+ if ((s.startsWith("-----BEGIN PKCS #7 SIGNED DATA-----")) && -+ (s.endsWith("-----END PKCS #7 SIGNED DATA-----"))) { -+ return (s.substring(35, (s.length() - 33))); -+ } -+ -+ return s; -+ } -+ -+ public String normalizeCertStr(String s) { -+ StringBuffer val = new StringBuffer(); -+ -+ for (int i = 0; i < s.length(); i++) { -+ if (s.charAt(i) == '\n') { -+ continue; -+ } else if (s.charAt(i) == '\r') { -+ continue; -+ } else if (s.charAt(i) == '"') { -+ continue; -+ } else if (s.charAt(i) == ' ') { -+ continue; -+ } -+ val.append(s.charAt(i)); -+ } -+ return val.toString(); -+ } -+ -+ public String X509toString(Locale clientLocale) { -+ -+ //get I18N resources -+ ResourceBundle resource = ResourceBundle.getBundle( -+ PrettyPrintResources.class.getName()); -+ DateFormat dateFormater = DateFormat.getDateTimeInstance( -+ DateFormat.FULL, DateFormat.FULL, clientLocale); -+ //get timezone and timezone ID -+ String tz = " "; -+ String tzid = " "; -+ -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ X509CertInfo info = (X509CertInfo) mX509Cert.get( -+ X509CertImpl.NAME + "." + X509CertImpl.INFO); -+ String serial2 = mX509Cert.getSerialNumber().toString(16).toUpperCase(); -+ -+ //get correct instance of key -+ PublicKey pKey = mX509Cert.getPublicKey(); -+ X509Key key = null; -+ -+ if (pKey instanceof CertificateX509Key) { -+ CertificateX509Key certKey = (CertificateX509Key) pKey; -+ -+ key = (X509Key) certKey.get(CertificateX509Key.KEY); -+ } -+ if (pKey instanceof X509Key) { -+ key = (X509Key) pKey; -+ } -+ -+ //take care of spki -+ sb.append(pp.indent(4) + resource.getString( -+ PrettyPrintResources.TOKEN_CERTIFICATE) + "\n"); -+ sb.append(pp.indent(8) + resource.getString( -+ PrettyPrintResources.TOKEN_DATA) + "\n"); -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_VERSION) + " v"); -+ sb.append((mX509Cert.getVersion() + 1) + "\n"); -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_SERIAL) + "0x" + serial2 + "\n"); -+ //XXX I18N Algorithm Name ? -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_SIGALG) + mX509Cert.getSigAlgName() + -+ " - " + mX509Cert.getSigAlgOID() + "\n"); -+ //XXX I18N IssuerDN ? -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_ISSUER) + -+ mX509Cert.getIssuerDN().toString() + "\n"); -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_VALIDITY) + "\n"); -+ String notBefore = dateFormater.format(mX509Cert.getNotBefore()); -+ String notAfter = dateFormater.format(mX509Cert.getNotAfter()); -+ -+ //get timezone and timezone ID -+ if (TimeZone.getDefault() != null) { -+ tz = TimeZone.getDefault().getDisplayName( -+ TimeZone.getDefault().inDaylightTime( -+ mX509Cert.getNotBefore()), -+ TimeZone.SHORT, -+ clientLocale); -+ tzid = TimeZone.getDefault().getID(); -+ } -+ // Specify notBefore -+ if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) { -+ // Do NOT append timezone ID -+ sb.append(pp.indent(16) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_NOT_BEFORE) -+ + notBefore -+ + "\n"); -+ } else { -+ // Append timezone ID -+ sb.append(pp.indent(16) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_NOT_BEFORE) -+ + notBefore -+ + " " + tzid + "\n"); -+ } -+ // re-get timezone (just in case it is different . . .) -+ if (TimeZone.getDefault() != null) { -+ tz = TimeZone.getDefault().getDisplayName( -+ TimeZone.getDefault().inDaylightTime( -+ mX509Cert.getNotAfter()), -+ TimeZone.SHORT, -+ clientLocale); -+ } -+ // Specify notAfter -+ if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) { -+ // Do NOT append timezone ID -+ sb.append(pp.indent(16) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_NOT_AFTER) -+ + notAfter -+ + "\n"); -+ } else { -+ // Append timezone ID -+ sb.append(pp.indent(16) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_NOT_AFTER) -+ + notAfter -+ + " " + tzid + "\n"); -+ } -+ //XXX I18N SubjectDN ? -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_SUBJECT) + -+ mX509Cert.getSubjectDN().toString() + "\n"); -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_SPKI) + "\n"); -+ -+ PubKeyPrettyPrint pkpp = new PubKeyPrettyPrint(key); -+ -+ sb.append(pkpp.toString(clientLocale, 16, 16)); -+ -+ //take care of extensions -+ CertificateExtensions extensions = (CertificateExtensions) -+ info.get(X509CertInfo.EXTENSIONS); -+ -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_EXTENSIONS) + "\n"); -+ if (extensions != null) -+ for (int i = 0; i < extensions.size(); i++) { -+ Extension ext = extensions.elementAt(i); -+ ExtPrettyPrint extpp = new ExtPrettyPrint(ext, 16); -+ -+ sb.append(extpp.toString()); -+ } -+ -+ //take care of signature -+ sb.append(pp.indent(8) + resource.getString( -+ PrettyPrintResources.TOKEN_SIGNATURE) + "\n"); -+ //XXX I18N Algorithm Name ? -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_ALGORITHM) + -+ mX509Cert.getSigAlgName() + " - " + mX509Cert.getSigAlgOID() + "\n"); -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_SIGNATURE) + "\n"); -+ sb.append(pp.toHexString(mX509Cert.getSignature(), 16, 16)); -+ -+ // fingerprints -+ String[] hashes = new String[] { "MD2", "MD5", "SHA-1", "SHA-256", "SHA-512" }; -+ StringBuffer certFingerprints = new StringBuffer(); -+ -+ sb.append(pp.indent(8) + "FingerPrint\n"); -+ for (int i = 0; i < hashes.length; i++) { -+ MessageDigest md = MessageDigest.getInstance(hashes[i]); -+ -+ md.update(mX509Cert.getEncoded()); -+ certFingerprints.append(pp.indent(12) + hashes[i] + ":\n" + -+ pp.toHexString(md.digest(), 16, 16)); -+ } -+ -+ sb.append(certFingerprints.toString()); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } -+ -+ return sb.toString(); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/util/CrlPrettyPrint.java b/org/mozilla/jss/netscape/security/util/CrlPrettyPrint.java -new file mode 100644 -index 00000000..842e95d6 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/CrlPrettyPrint.java -@@ -0,0 +1,271 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.text.DateFormat; -+import java.util.Iterator; -+import java.util.Locale; -+import java.util.ResourceBundle; -+import java.util.Set; -+import java.util.TimeZone; -+ -+import org.mozilla.jss.netscape.security.x509.CRLExtensions; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.RevokedCertificate; -+import org.mozilla.jss.netscape.security.x509.X509CRLImpl; -+ -+/** -+ * This class will display the certificate content in predefined -+ * format. -+ * -+ * @author Andrew Wnuk -+ * @version $Revision$, $Date$ -+ */ -+public class CrlPrettyPrint { -+ -+ /*========================================================== -+ * constants -+ *==========================================================*/ -+ private final static String CUSTOM_LOCALE = "Custom"; -+ -+ /*========================================================== -+ * variables -+ *==========================================================*/ -+ private X509CRLImpl mCRL = null; -+ private PrettyPrintFormat pp = null; -+ -+ /*========================================================== -+ * constructors -+ *==========================================================*/ -+ -+ public CrlPrettyPrint(X509CRLImpl crl) { -+ mCRL = crl; -+ pp = new PrettyPrintFormat(":"); -+ } -+ -+ /*========================================================== -+ * public methods -+ *==========================================================*/ -+ -+ /** -+ * This method return string representation of the certificate -+ * revocation list in predefined format using specified client -+ * local. I18N Support. -+ * -+ * @param clientLocale Locale to be used for localization -+ * @return string representation of the certificate -+ */ -+ public String toString(Locale clientLocale) { -+ return toString(clientLocale, 0, 0, 0); -+ } -+ -+ public String toString(Locale clientLocale, long crlSize, long pageStart, long pageSize) { -+ -+ //get I18N resources -+ ResourceBundle resource = ResourceBundle.getBundle( -+ PrettyPrintResources.class.getName()); -+ DateFormat dateFormater = DateFormat.getDateTimeInstance( -+ DateFormat.FULL, DateFormat.FULL, clientLocale); -+ //get timezone and timezone ID -+ String tz = " "; -+ String tzid = " "; -+ -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(4) + resource.getString( -+ PrettyPrintResources.TOKEN_CRL) + "\n"); -+ sb.append(pp.indent(8) + resource.getString( -+ PrettyPrintResources.TOKEN_DATA) + "\n"); -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_VERSION) + " v"); -+ sb.append((mCRL.getVersion() + 1) + "\n"); -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_SIGALG) + mCRL.getSigAlgName() + -+ " - " + mCRL.getSigAlgOID() + "\n"); -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_ISSUER) + -+ mCRL.getIssuerDN().toString() + "\n"); -+ // Format thisUpdate -+ String thisUpdate = dateFormater.format(mCRL.getThisUpdate()); -+ -+ // get timezone and timezone ID -+ if (TimeZone.getDefault() != null) { -+ tz = TimeZone.getDefault().getDisplayName( -+ TimeZone.getDefault().inDaylightTime( -+ mCRL.getThisUpdate()), -+ TimeZone.SHORT, -+ clientLocale); -+ tzid = TimeZone.getDefault().getID(); -+ } -+ // Specify ThisUpdate -+ if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) { -+ // Do NOT append timezone ID -+ sb.append(pp.indent(12) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_THIS_UPDATE) -+ + thisUpdate -+ + "\n"); -+ } else { -+ // Append timezone ID -+ sb.append(pp.indent(12) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_THIS_UPDATE) -+ + thisUpdate -+ + " " + tzid + "\n"); -+ } -+ // Check for presence of NextUpdate -+ if (mCRL.getNextUpdate() != null) { -+ // Format nextUpdate -+ String nextUpdate = dateFormater.format(mCRL.getNextUpdate()); -+ -+ // re-get timezone (just in case it is different . . .) -+ if (TimeZone.getDefault() != null) { -+ tz = TimeZone.getDefault().getDisplayName( -+ TimeZone.getDefault().inDaylightTime( -+ mCRL.getNextUpdate()), -+ TimeZone.SHORT, -+ clientLocale); -+ } -+ // Specify NextUpdate -+ if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) { -+ // Do NOT append timezone ID -+ sb.append(pp.indent(12) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_NEXT_UPDATE) -+ + nextUpdate -+ + "\n"); -+ } else { -+ // Append timezone ID -+ sb.append(pp.indent(12) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_NEXT_UPDATE) -+ + nextUpdate -+ + " " + tzid + "\n"); -+ } -+ } -+ -+ if (crlSize > 0 && pageStart == 0 && pageSize == 0) { -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_REVOKED_CERTIFICATES) + crlSize + "\n"); -+ } else if ((crlSize == 0 && pageStart == 0 && pageSize == 0) || -+ (crlSize > 0 && pageStart > 0 && pageSize > 0)) { -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_REVOKED_CERTIFICATES)); -+ if (crlSize > 0 && pageStart > 0 && pageSize > 0) { -+ long upperLimit = (pageStart + pageSize - 1 > crlSize) ? crlSize : pageStart + pageSize - 1; -+ -+ sb.append("" + pageStart + "-" + upperLimit + " of " + crlSize); -+ } -+ sb.append("\n"); -+ -+ Set revokedCerts = mCRL.getRevokedCertificates(); -+ -+ if (revokedCerts != null) { -+ Iterator i = revokedCerts.iterator(); -+ long l = 1; -+ -+ while ((i.hasNext()) && ((crlSize == 0) || (pageStart + pageSize > l))) { -+ RevokedCertificate revokedCert = i.next(); -+ -+ if ((crlSize == 0) || ((pageStart <= l) && (pageStart + pageSize > l))) { -+ sb.append(pp.indent(16) + resource.getString( -+ PrettyPrintResources.TOKEN_SERIAL) + "0x" + -+ revokedCert.getSerialNumber().toString(16).toUpperCase() + "\n"); -+ String revocationDate = -+ dateFormater.format(revokedCert.getRevocationDate()); -+ -+ // re-get timezone -+ // (just in case it is different . . .) -+ if (TimeZone.getDefault() != null) { -+ tz = TimeZone.getDefault().getDisplayName( -+ TimeZone.getDefault().inDaylightTime( -+ revokedCert.getRevocationDate()), -+ TimeZone.SHORT, -+ clientLocale); -+ } -+ // Specify revocationDate -+ if (tz.equals(tzid) || -+ tzid.equals(CUSTOM_LOCALE)) { -+ // Do NOT append timezone ID -+ sb.append(pp.indent(16) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_REVOCATION_DATE) -+ + revocationDate -+ + "\n"); -+ } else { -+ // Append timezone ID -+ sb.append(pp.indent(16) -+ + resource.getString( -+ PrettyPrintResources.TOKEN_REVOCATION_DATE) -+ + revocationDate -+ + " " + tzid + "\n"); -+ } -+ if (revokedCert.hasExtensions()) { -+ sb.append(pp.indent(16) + resource.getString( -+ PrettyPrintResources.TOKEN_EXTENSIONS) + "\n"); -+ CRLExtensions crlExtensions = revokedCert.getExtensions(); -+ -+ if (crlExtensions != null) { -+ for (int k = 0; k < crlExtensions.size(); k++) { -+ Extension ext = crlExtensions.elementAt(k); -+ ExtPrettyPrint extpp = new ExtPrettyPrint(ext, 20); -+ -+ sb.append(extpp.toString()); -+ } -+ } -+ } -+ } -+ l++; -+ } -+ } -+ } -+ -+ CRLExtensions crlExtensions = mCRL.getExtensions(); -+ -+ if (crlExtensions != null) { -+ sb.append(pp.indent(8) + resource.getString( -+ PrettyPrintResources.TOKEN_EXTENSIONS) + "\n"); -+ for (int k = 0; k < crlExtensions.size(); k++) { -+ Extension ext = crlExtensions.elementAt(k); -+ ExtPrettyPrint extpp = new ExtPrettyPrint(ext, 12); -+ -+ sb.append(extpp.toString()); -+ } -+ } -+ -+ //take care of signature -+ sb.append(pp.indent(8) + resource.getString( -+ PrettyPrintResources.TOKEN_SIGNATURE) + "\n"); -+ //XXX I18N Algorithm Name ? -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_ALGORITHM) + -+ mCRL.getSigAlgName() + " - " + mCRL.getSigAlgOID() + "\n"); -+ sb.append(pp.indent(12) + resource.getString( -+ PrettyPrintResources.TOKEN_SIGNATURE) + "\n"); -+ sb.append(pp.toHexString(mCRL.getSignature(), 16, 16)); -+ -+ } catch (Exception e) { -+ sb.append("\n\n" + pp.indent(4) + resource.getString( -+ PrettyPrintResources.TOKEN_DECODING_ERROR) + "\n\n"); -+ e.printStackTrace(); -+ } -+ -+ return sb.toString(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/DerEncoder.java b/org/mozilla/jss/netscape/security/util/DerEncoder.java -new file mode 100644 -index 00000000..9121e24d ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/DerEncoder.java -@@ -0,0 +1,40 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.IOException; -+import java.io.OutputStream; -+ -+/** -+ * Interface to an object that knows how to write its own DER -+ * encoding to an output stream. -+ * -+ * @version 1.2 97/12/10 -+ * @author D. N. Hoover -+ */ -+public interface DerEncoder { -+ -+ /** -+ * DER encode this object and write the results to a stream. -+ * -+ * @param out the stream on which the DER encoding is written. -+ */ -+ public void derEncode(OutputStream out) -+ throws IOException; -+ -+} -diff --git a/org/mozilla/jss/netscape/security/util/DerInputBuffer.java b/org/mozilla/jss/netscape/security/util/DerInputBuffer.java -new file mode 100644 -index 00000000..c1c33ac0 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/DerInputBuffer.java -@@ -0,0 +1,186 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.ByteArrayInputStream; -+import java.io.IOException; -+import java.io.OutputStream; -+ -+/** -+ * DER input buffer ... this is the main abstraction in the DER library -+ * which actively works with the "untyped byte stream" abstraction. It -+ * does so with impunity, since it's not intended to be exposed to the -+ * anyone who could violate the "typed value stream" DER model and hence -+ * corrupt the input stream of DER values. -+ * -+ * @version 1.11 -+ * @author David Brownell -+ */ -+class DerInputBuffer extends ByteArrayInputStream implements Cloneable { -+ -+ DerInputBuffer(byte[] buf) { -+ super(buf); -+ } -+ -+ DerInputBuffer(byte[] buf, int offset, int len) { -+ super(buf, offset, len); -+ } -+ -+ DerInputBuffer dup() { -+ try { -+ DerInputBuffer retval = (DerInputBuffer) clone(); -+ -+ retval.mark(Integer.MAX_VALUE); -+ return retval; -+ } catch (CloneNotSupportedException e) { -+ throw new IllegalArgumentException(e.toString()); -+ } -+ } -+ -+ byte[] toByteArray() throws IOException { -+ int len = available(); -+ if (len <= 0) -+ throw new IOException("No Buffer Space Available."); -+ byte[] retval = new byte[len]; -+ -+ System.arraycopy(buf, pos, retval, 0, len); -+ return retval; -+ } -+ -+ int peek() throws IOException { -+ if (pos >= count) -+ throw new IOException("out of data"); -+ else -+ return buf[pos]; -+ } -+ -+ /** -+ * Compares this DerInputBuffer for equality with the specified -+ * object. -+ */ -+ public boolean equals(Object other) { -+ if (other instanceof DerInputBuffer) -+ return equals((DerInputBuffer) other); -+ else -+ return false; -+ } -+ -+ boolean equals(DerInputBuffer other) { -+ if (this == other) -+ return true; -+ -+ int max = this.available(); -+ if (other.available() != max) -+ return false; -+ for (int i = 0; i < max; i++) { -+ if (this.buf[this.pos + i] != other.buf[other.pos + i]) { -+ return false; -+ } -+ } -+ return true; -+ } -+ -+ void truncate(int len) throws IOException { -+ if (len > available()) -+ throw new IOException("insufficient data"); -+ count = pos + len; -+ } -+ -+ /** -+ * Returns the unsigned integer which takes up the specified number -+ * of bytes in this buffer. -+ */ -+ BigInt getUnsigned(int len) throws IOException { -+ if (len > available()) -+ throw new IOException("short read, getInteger"); -+ -+ /* -+ * A prepended zero is used to ensure that the integer is -+ * interpreted as unsigned even when the high order bit is -+ * zero. We don't support signed BigInts. -+ * -+ * Fix this here ... BigInts aren't expected to have these, -+ * and stuff like signing (sigsize = f(modulus)) misbehaves. -+ */ -+ if (len > 1 && buf[pos] == 0) { -+ len--; -+ skip(1); -+ } -+ -+ /* -+ * Consume the rest of the buffer, returning its value as -+ * an unsigned integer. -+ */ -+ byte[] bytes = new byte[len]; -+ -+ System.arraycopy(buf, pos, bytes, 0, len); -+ skip(len); -+ return new BigInt(bytes); -+ } -+ -+ /** -+ * Returns the bit string which takes up the rest of this buffer. -+ * This bit string must be byte-aligned. -+ */ -+ byte[] getBitString() { -+ if (pos >= count || buf[pos] != 0) -+ return null; -+ /* -+ * Just copy the data into an aligned, padded octet buffer, -+ * and consume the rest of the buffer. -+ */ -+ int len = available(); -+ byte[] retval = new byte[len - 1]; -+ -+ System.arraycopy(buf, pos + 1, retval, 0, len - 1); -+ pos = count; -+ return retval; -+ } -+ -+ /** -+ * Returns the bit string which takes up the rest of this buffer. -+ * The bit string need not be byte-aligned. -+ */ -+ BitArray getUnalignedBitString() { -+ if (pos >= count) -+ return null; -+ /* -+ * Just copy the data into an aligned, padded octet buffer, -+ * and consume the rest of the buffer. -+ */ -+ int len = available(); -+ byte[] bits = new byte[len - 1]; -+ int length = bits.length * 8 - buf[pos]; // number of valid bits -+ -+ System.arraycopy(buf, pos + 1, bits, 0, len - 1); -+ -+ BitArray bitArray = new BitArray(length, bits); -+ pos = count; -+ return bitArray; -+ } -+ -+ /** -+ * Package-access method to optimize output operations -+ */ -+ void dump(OutputStream out, int length) throws IOException { -+ if (count < mark + length) -+ throw new IOException("short DER value (encode)"); -+ out.write(buf, mark, length); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/util/DerInputStream.java b/org/mozilla/jss/netscape/security/util/DerInputStream.java -new file mode 100644 -index 00000000..6ff4bf23 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/DerInputStream.java -@@ -0,0 +1,667 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.util.Calendar; -+import java.util.Date; -+import java.util.GregorianCalendar; -+import java.util.TimeZone; -+import java.util.Vector; -+ -+/** -+ * A DER input stream, used for parsing ASN.1 DER-encoded data such as -+ * that found in X.509 certificates. DER is a subset of BER/1, which has -+ * the advantage that it allows only a single encoding of primitive data. -+ * (High level data such as dates still support many encodings.) That is, -+ * it uses the "Definite" Encoding Rules (DER) not the "Basic" ones (BER). -+ * -+ *

-+ * Note that, like BER/1, DER streams are streams of explicitly tagged data values. Accordingly, this programming -+ * interface does not expose any variant of the java.io.InputStream interface, since that kind of input stream holds -+ * untagged data values and using that I/O model could prevent correct parsing of the DER data. -+ * -+ *

-+ * At this time, this class supports only a subset of the types of DER data encodings which are defined. That subset is -+ * sufficient for parsing most X.509 certificates. -+ * -+ * @version 1.35 -+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class DerInputStream { -+ /* -+ * This version only supports fully buffered DER. This is easy to -+ * work with, though if large objects are manipulated DER becomes -+ * awkward to deal with. That's where BER is useful, since BER -+ * handles streaming data relatively well. -+ */ -+ DerInputBuffer buffer; -+ -+ /** -+ * Create a DER input stream from a data buffer. The buffer is not -+ * copied, it is shared. Accordingly, the buffer should be treated -+ * as read-only. -+ * -+ * @param data the buffer from which to create the string (CONSUMED) -+ */ -+ public DerInputStream(byte[] data) { -+ buffer = new DerInputBuffer(data); -+ buffer.mark(Integer.MAX_VALUE); -+ } -+ -+ /** -+ * Create a DER input stream from part of a data buffer. -+ * The buffer is not copied, it is shared. Accordingly, the -+ * buffer should be treated as read-only. -+ * -+ * @param data the buffer from which to create the string (CONSUMED) -+ * @param offset the first index of data which will -+ * be read as DER input in the new stream -+ * @param len how long a chunk of the buffer to use, -+ * starting at "offset" -+ */ -+ public DerInputStream(byte[] data, int offset, int len) { -+ buffer = new DerInputBuffer(data, offset, len); -+ buffer.mark(Integer.MAX_VALUE); -+ } -+ -+ DerInputStream(DerInputBuffer buf) { -+ buffer = buf; -+ buffer.mark(Integer.MAX_VALUE); -+ } -+ -+ /** -+ * Creates a new DER input stream from part of this input stream. -+ * -+ * @param len how long a chunk of the current input stream to use, -+ * starting at the current position. -+ * @param do_skip true if the existing data in the input stream should -+ * be skipped. If this value is false, the next data read -+ * on this stream and the newly created stream will be the -+ * same. -+ */ -+ public DerInputStream subStream(int len, boolean do_skip) -+ throws IOException { -+ DerInputBuffer newbuf = buffer.dup(); -+ -+ newbuf.truncate(len); -+ if (do_skip) -+ buffer.skip(len); -+ return new DerInputStream(newbuf); -+ } -+ -+ /** -+ * Return what has been written to this DerInputStream -+ * as a byte array. Useful for debugging. -+ * @throws IOException -+ */ -+ public byte[] toByteArray() throws IOException { -+ return buffer.toByteArray(); -+ } -+ -+ /* -+ * PRIMITIVES -- these are "universal" ASN.1 simple types. -+ * -+ * INTEGER, BIT STRING, OCTET STRING, NULL -+ * OBJECT IDENTIFIER, SEQUENCE (OF), SET (OF) -+ * PrintableString, T61String, IA5String, UTCTime -+ */ -+ -+ /** -+ * Get an (unsigned) integer from the input stream. -+ */ -+ public BigInt getInteger() throws IOException { -+ if (buffer.read() != DerValue.tag_Integer) -+ throw new IOException("DER input, Integer tag error"); -+ -+ return buffer.getUnsigned(getLength(buffer)); -+ } -+ -+ /** -+ * Get a bit string from the input stream. Only octet-aligned -+ * bitstrings (multiples of eight bits in length) are handled -+ * by this method. -+ */ -+ public byte[] getBitString() throws IOException { -+ if (buffer.read() != DerValue.tag_BitString) -+ throw new IOException("DER input not an bit string"); -+ int length = getLength(buffer); -+ -+ /* -+ * This byte affects alignment and padding (for the last byte). -+ * Use getUnalignedBitString() for none 8-bit aligned bit strings. -+ */ -+ if (buffer.read() != 0) -+ return null; -+ length--; -+ -+ /* -+ * Just read the data into an aligned, padded octet buffer. -+ */ -+ byte[] retval = new byte[length]; -+ if (buffer.read(retval) != length) -+ throw new IOException("short read of DER bit string"); -+ return retval; -+ } -+ -+ /** -+ * Get a bit string from the input stream. The bit string need -+ * not be byte-aligned. -+ */ -+ public BitArray getUnalignedBitString() throws IOException { -+ if (buffer.read() != DerValue.tag_BitString) -+ throw new IOException("DER input not a bit string"); -+ -+ int length = getLength(buffer) - 1; -+ -+ /* -+ * First byte = number of excess bits in the last octet of the -+ * representation. -+ */ -+ int validBits = length * 8 - buffer.read(); -+ -+ byte[] repn = new byte[length]; -+ -+ if (buffer.read(repn) != length) -+ throw new IOException("short read of DER bit string"); -+ return new BitArray(validBits, repn); -+ } -+ -+ /** -+ * Returns an ASN.1 OCTET STRING from the input stream. -+ */ -+ public byte[] getOctetString() throws IOException { -+ if (buffer.read() != DerValue.tag_OctetString) -+ throw new IOException("DER input not an octet string"); -+ -+ int length = getLength(buffer); -+ byte[] retval = new byte[length]; -+ if (buffer.read(retval) != length) -+ throw new IOException("short read of DER octet string"); -+ -+ return retval; -+ } -+ -+ /** -+ * Returns the asked number of bytes from the input stream. -+ */ -+ public void getBytes(byte[] val) throws IOException { -+ if (val.length != 0) { -+ if (buffer.read(val) != val.length) { -+ throw new IOException("short read of DER octet string"); -+ } -+ } -+ } -+ -+ /** -+ * Reads an encoded null value from the input stream. -+ */ -+ public void getNull() throws IOException { -+ if (buffer.read() != DerValue.tag_Null || buffer.read() != 0) -+ throw new IOException("getNull, bad data"); -+ } -+ -+ /** -+ * Reads an X.200 style Object Identifier from the stream. -+ */ -+ public ObjectIdentifier getOID() throws IOException { -+ return new ObjectIdentifier(this); -+ } -+ -+ /** -+ * Return a sequence of encoded entities. ASN.1 sequences are -+ * ordered, and they are often used, like a "struct" in C or C++, -+ * to group data values. They may have optional or context -+ * specific values. -+ * -+ * @param startLen guess about how long the sequence will be -+ * (used to initialize an auto-growing data structure) -+ * @return array of the values in the sequence -+ */ -+ public DerValue[] getSequence(int startLen) throws IOException { -+ int b = buffer.read(); -+ if (b != DerValue.tag_Sequence) -+ throw new IOException("Sequence tag error " + b); -+ return readVector(startLen); -+ } -+ -+ public void skipSequence(int startLen) throws IOException { -+ int b = buffer.read(); -+ if (b != DerValue.tag_Sequence) -+ throw new IOException("Sequence tag error " + b); -+ int len = getLength(buffer); -+ buffer.skip(len); -+ } -+ -+ /** -+ * Return a set of encoded entities. ASN.1 sets are unordered, -+ * though DER may specify an order for some kinds of sets (such -+ * as the attributes in an X.500 relative distinguished name) -+ * to facilitate binary comparisons of encoded values. -+ * -+ * @param startLen guess about how large the set will be -+ * (used to initialize an auto-growing data structure) -+ * @return array of the values in the sequence -+ */ -+ public DerValue[] getSet(int startLen) throws IOException { -+ if (buffer.read() != DerValue.tag_Set) -+ throw new IOException("Set tag error"); -+ return readVector(startLen); -+ } -+ -+ /** -+ * Return a set of encoded entities. ASN.1 sets are unordered, -+ * though DER may specify an order for some kinds of sets (such -+ * as the attributes in an X.500 relative distinguished name) -+ * to facilitate binary comparisons of encoded values. -+ * -+ * @param startLen guess about how large the set will be -+ * (used to initialize an auto-growing data structure) -+ * @param implicit if true tag is assumed implicit. -+ * @return array of the values in the sequence -+ */ -+ public DerValue[] getSet(int startLen, boolean implicit) throws IOException { -+ int tag = buffer.read(); -+ if (!implicit) { -+ if (tag != DerValue.tag_Set) { -+ throw new IOException("Set tag error"); -+ } -+ } -+ return (readVector(startLen)); -+ } -+ -+ /* -+ * Read a "vector" of values ... set or sequence have the -+ * same encoding, except for the initial tag, so both use -+ * this same helper routine. -+ */ -+ protected DerValue[] readVector(int startLen) throws IOException { -+ int len = getLength(buffer); -+ DerInputStream newstr; -+ -+ if (len == 0) -+ // return empty array instead of null, which should be -+ // used only for missing optionals -+ return new DerValue[0]; -+ -+ /* -+ * Create a temporary stream from which to read the data, -+ * unless it's not really needed. -+ */ -+ if (buffer.available() == len) -+ newstr = this; -+ else -+ newstr = subStream(len, true); -+ -+ /* -+ * Pull values out of the stream. -+ */ -+ Vector vec = new Vector(startLen); -+ DerValue value; -+ -+ do { -+ value = new DerValue(newstr.buffer); -+ vec.addElement(value); -+ } while (newstr.available() > 0); -+ -+ if (newstr.available() != 0) -+ throw new IOException("extra data at end of vector"); -+ -+ /* -+ * Now stick them into the array we're returning. -+ */ -+ int i, max = vec.size(); -+ DerValue[] retval = new DerValue[max]; -+ -+ for (i = 0; i < max; i++) -+ retval[i] = vec.elementAt(i); -+ -+ return retval; -+ } -+ -+ /** -+ * Get a single DER-encoded value from the input stream. -+ * It can often be useful to pull a value from the stream -+ * and defer parsing it. For example, you can pull a nested -+ * sequence out with one call, and only examine its elements -+ * later when you really need to. -+ */ -+ public DerValue getDerValue() throws IOException { -+ return new DerValue(buffer); -+ } -+ -+ public String getPrintableString() throws IOException { -+ return (new DerValue(buffer)).getPrintableString(); -+ } -+ -+ public String getT61String() throws IOException { -+ return (new DerValue(buffer)).getT61String(); -+ } -+ -+ public String getIA5String() throws IOException { -+ return (new DerValue(buffer)).getIA5String(); -+ } -+ -+ public String getBMPString() throws IOException { -+ return (new DerValue(buffer)).getBMPString(); -+ } -+ -+ public String getUniversalString() throws IOException { -+ return (new DerValue(buffer)).getUniversalString(); -+ } -+ -+ public String getDirectoryString() throws IOException { -+ return (new DerValue(buffer)).getDirectoryString(); -+ } -+ -+ /** -+ * Get a UTC encoded time value from the input stream. -+ */ -+ public Date getUTCTime() throws IOException { -+ if (buffer.read() != DerValue.tag_UtcTime) -+ throw new IOException("DER input, UTCtime tag invalid "); -+ if (buffer.available() < 11) -+ throw new IOException("DER input, UTCtime short input"); -+ -+ int len = getLength(buffer); -+ -+ if (len < 11 || len > 17) -+ throw new IOException("DER getUTCTime length error"); -+ -+ /* -+ * UTC time encoded as ASCII chars, YYMMDDhhmmss. -+ * If YY <= 50, we assume 20YY; -+ * if YY > 50, we assume 19YY, as per IETF-PKIX part I. -+ */ -+ int year, month, day, hour, minute, second; -+ -+ year = 10 * Character.digit((char) buffer.read(), 10); -+ year += Character.digit((char) buffer.read(), 10); -+ if (year <= 50) // origin 2000 -+ year += 2000; -+ else -+ year += 1900; // origin 1900 -+ -+ month = 10 * Character.digit((char) buffer.read(), 10); -+ month += Character.digit((char) buffer.read(), 10); -+ month -= 1; // months are 0-11 -+ -+ day = 10 * Character.digit((char) buffer.read(), 10); -+ day += Character.digit((char) buffer.read(), 10); -+ -+ hour = 10 * Character.digit((char) buffer.read(), 10); -+ hour += Character.digit((char) buffer.read(), 10); -+ -+ minute = 10 * Character.digit((char) buffer.read(), 10); -+ minute += Character.digit((char) buffer.read(), 10); -+ -+ len -= 10; -+ -+ /** -+ * We allow for non-encoded seconds, even though the -+ * IETF-PKIX specification says that the seconds should -+ * always be encoded even if it is zero. -+ */ -+ -+ if (len == 3 || len == 7) { -+ second = 10 * Character.digit((char) buffer.read(), 10); -+ second += Character.digit((char) buffer.read(), 10); -+ len -= 2; -+ } else -+ second = 0; -+ -+ if (month < 0 || day <= 0 -+ || month > 11 || day > 31 || hour >= 24 -+ || minute >= 60 || second >= 60) -+ throw new IOException("Parse UTC time, invalid format"); -+ -+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); -+ cal.set(year, month, day, hour, minute, second); -+ cal.set(Calendar.MILLISECOND, 0); /* To clear millisecond field */ -+ cal.set(Calendar.ERA, GregorianCalendar.AD); -+ Date readDate = cal.getTime(); -+ long utcTime = readDate.getTime(); -+ -+ /* -+ * Finally, "Z" or "+hhmm" or "-hhmm" ... offsets change hhmm -+ */ -+ if (!(len == 1 || len == 5)) -+ throw new IOException("Parse UTC time, invalid offset"); -+ -+ switch (buffer.read()) { -+ case '+': { -+ int Htmp = 10 * Character.digit((char) buffer.read(), 10); -+ Htmp += Character.digit((char) buffer.read(), 10); -+ int Mtmp = 10 * Character.digit((char) buffer.read(), 10); -+ Mtmp += Character.digit((char) buffer.read(), 10); -+ -+ if (Htmp >= 24 || Mtmp >= 60) -+ throw new IOException("Parse UTCtime, +hhmm"); -+ -+ utcTime += ((Htmp * 60) + Mtmp) * 60 * 1000L; -+ } -+ break; -+ -+ case '-': { -+ int Htmp = 10 * Character.digit((char) buffer.read(), 10); -+ Htmp += Character.digit((char) buffer.read(), 10); -+ int Mtmp = 10 * Character.digit((char) buffer.read(), 10); -+ Mtmp += Character.digit((char) buffer.read(), 10); -+ -+ if (Htmp >= 24 || Mtmp >= 60) -+ throw new IOException("Parse UTCtime, -hhmm"); -+ -+ utcTime -= ((Htmp * 60) + Mtmp) * 60 * 1000L; -+ } -+ break; -+ -+ case 'Z': -+ break; -+ -+ default: -+ throw new IOException("Parse UTCtime, garbage offset"); -+ } -+ readDate.setTime(utcTime); -+ return readDate; -+ } -+ -+ /** -+ * Get a Generalized encoded time value from the input stream. -+ */ -+ public Date getGeneralizedTime() throws IOException { -+ if (buffer.read() != DerValue.tag_GeneralizedTime) -+ throw new IOException("DER input, GeneralizedTime tag invalid "); -+ -+ if (buffer.available() < 13) -+ throw new IOException("DER input, GeneralizedTime short input"); -+ -+ int len = getLength(buffer); -+ -+ /* -+ * Generalized time encoded as ASCII chars, YYYYMMDDhhmm[ss] -+ */ -+ int year, month, day, hour, minute, second; -+ -+ year = 1000 * Character.digit((char) buffer.read(), 10); -+ year += 100 * Character.digit((char) buffer.read(), 10); -+ year += 10 * Character.digit((char) buffer.read(), 10); -+ year += Character.digit((char) buffer.read(), 10); -+ -+ month = 10 * Character.digit((char) buffer.read(), 10); -+ month += Character.digit((char) buffer.read(), 10); -+ month -= 1; // Calendar months are 0-11 -+ -+ day = 10 * Character.digit((char) buffer.read(), 10); -+ day += Character.digit((char) buffer.read(), 10); -+ -+ hour = 10 * Character.digit((char) buffer.read(), 10); -+ hour += Character.digit((char) buffer.read(), 10); -+ -+ minute = 10 * Character.digit((char) buffer.read(), 10); -+ minute += Character.digit((char) buffer.read(), 10); -+ -+ len -= 12; -+ -+ /** -+ * We allow for non-encoded seconds, even though the -+ * IETF-PKIX specification says that the seconds should -+ * always be encoded even if it is zero. -+ */ -+ -+ if (len == 3 || len == 7) { -+ second = 10 * Character.digit((char) buffer.read(), 10); -+ second += Character.digit((char) buffer.read(), 10); -+ len -= 2; -+ } else -+ second = 0; -+ -+ if (month < 0 || day <= 0 -+ || month > 11 || day > 31 || hour >= 24 -+ || minute >= 60 || second >= 60) -+ throw new IOException("Parse Generalized time, invalid format"); -+ -+ /* Shouldn't this construct a Gregorian calendar directly??? -+ * We don't really want locale dependant processing here */ -+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); -+ cal.set(year, month, day, hour, minute, second); -+ cal.set(Calendar.MILLISECOND, 0); /* To clear millisecond field */ -+ cal.set(Calendar.ERA, GregorianCalendar.AD); -+ Date readDate = cal.getTime(); -+ long utcTime = readDate.getTime(); -+ -+ /* -+ * Finally, "Z" or "+hhmm" or "-hhmm" ... offsets change hhmm -+ */ -+ if (!(len == 1 || len == 5)) -+ throw new IOException("Parse Generalized time, invalid offset"); -+ -+ switch (buffer.read()) { -+ case '+': { -+ int Htmp = 10 * Character.digit((char) buffer.read(), 10); -+ Htmp += Character.digit((char) buffer.read(), 10); -+ int Mtmp = 10 * Character.digit((char) buffer.read(), 10); -+ Mtmp += Character.digit((char) buffer.read(), 10); -+ -+ if (Htmp >= 24 || Mtmp >= 60) -+ throw new IOException("Parse GeneralizedTime, +hhmm"); -+ -+ utcTime += ((Htmp * 60) + Mtmp) * 60 * 1000L; -+ } -+ break; -+ -+ case '-': { -+ int Htmp = 10 * Character.digit((char) buffer.read(), 10); -+ Htmp += Character.digit((char) buffer.read(), 10); -+ int Mtmp = 10 * Character.digit((char) buffer.read(), 10); -+ Mtmp += Character.digit((char) buffer.read(), 10); -+ -+ if (Htmp >= 24 || Mtmp >= 60) -+ throw new IOException("Parse GeneralizedTime, -hhmm"); -+ -+ utcTime -= ((Htmp * 60) + Mtmp) * 60 * 1000L; -+ } -+ break; -+ -+ case 'Z': -+ break; -+ -+ default: -+ throw new IOException("Parse GeneralizedTime, garbage offset"); -+ } -+ readDate.setTime(utcTime); -+ return readDate; -+ } -+ -+ /* -+ * Get a byte from the input stream. -+ */ -+ // package private -+ int getByte() throws IOException { -+ return (0x00ff & buffer.read()); -+ } -+ -+ public int peekByte() throws IOException { -+ return buffer.peek(); -+ } -+ -+ // package private -+ int getLength() throws IOException { -+ return getLength(buffer); -+ } -+ -+ /* -+ * Get a length from the input stream, allowing for at most 32 bits of -+ * encoding to be used. (Not the same as getting a tagged integer!) -+ */ -+ static int getLength(InputStream in) throws IOException { -+ int value, tmp; -+ -+ tmp = in.read(); -+ if ((tmp & 0x080) == 0x00) { // 1 byte datum? -+ value = tmp; -+ } else { // no, more ... -+ tmp &= 0x07f; -+ -+ /* -+ * NOTE: tmp == 0 indicates BER encoded data. -+ * tmp > 4 indicates more than 4Gb of data. -+ */ -+ if (tmp <= 0 || tmp > 4) -+ throw new IOException("DerInput.getLength(): lengthTag=" -+ + tmp + ", " -+ + ((tmp == 0) ? "Indefinite length encoding not supported" -+ + " or incorrect DER encoding." -+ : "too big.")); -+ -+ for (value = 0; tmp > 0; tmp--) { -+ value <<= 8; -+ value += 0x0ff & in.read(); -+ } -+ } -+ return value; -+ } -+ -+ /** -+ * Mark the current position in the buffer, so that -+ * a later call to reset will return here. -+ */ -+ public void mark(int value) { -+ buffer.mark(value); -+ } -+ -+ /** -+ * Return to the position of the last mark call. A mark is implicitly set at the beginning of -+ * the stream when it is created. -+ */ -+ public void reset() { -+ buffer.reset(); -+ } -+ -+ /** -+ * Returns the number of bytes available for reading. -+ * This is most useful for testing whether the stream is -+ * empty. -+ */ -+ public int available() { -+ return buffer.available(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/DerOutputStream.java b/org/mozilla/jss/netscape/security/util/DerOutputStream.java -new file mode 100644 -index 00000000..ad355926 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/DerOutputStream.java -@@ -0,0 +1,729 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.ByteArrayOutputStream; -+import java.io.IOException; -+import java.io.OutputStream; -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.CharacterCodingException; -+import java.nio.charset.CharsetEncoder; -+import java.text.SimpleDateFormat; -+import java.util.Arrays; -+import java.util.Calendar; -+import java.util.Comparator; -+import java.util.Date; -+import java.util.GregorianCalendar; -+import java.util.TimeZone; -+ -+/** -+ * Output stream marshaling DER-encoded data. This is eventually provided -+ * in the form of a byte array; there is no advance limit on the size of -+ * that byte array. -+ * -+ *

-+ * At this time, this class supports only a subset of the types of DER data encodings which are defined. That subset is -+ * sufficient for generating most X.509 certificates. -+ * -+ * @version 1.32 -+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class DerOutputStream -+ extends ByteArrayOutputStream implements DerEncoder { -+ /** -+ * Construct an DER output stream. -+ * -+ * @param size how large a buffer to preallocate. -+ */ -+ public DerOutputStream(int size) { -+ super(size); -+ } -+ -+ /** -+ * Construct an DER output stream. -+ */ -+ public DerOutputStream() { -+ } -+ -+ /** -+ * Writes tagged, pre-marshaled data. This calcuates and encodes -+ * the length, so that the output data is the standard triple of -+ * { tag, length, data } used by all DER values. -+ * -+ * @param tag the DER value tag for the data, such as DerValue.tag_Sequence -+ * @param buf buffered data, which must be DER-encoded -+ */ -+ public void write(byte tag, byte[] buf) throws IOException { -+ write(tag); -+ putLength(buf.length); -+ write(buf, 0, buf.length); -+ } -+ -+ /** -+ * Writes tagged data using buffer-to-buffer copy. As above, -+ * this writes a standard DER record. This is often used when -+ * efficiently encapsulating values in sequences. -+ * -+ * @param tag the DER value tag for the data, such as DerValue.tag_Sequence -+ * @param out buffered data -+ */ -+ public void write(byte tag, DerOutputStream out) throws IOException { -+ write(tag); -+ putLength(out.count); -+ write(out.buf, 0, out.count); -+ } -+ -+ /** -+ * Writes implicitly tagged data using buffer-to-buffer copy. As above, -+ * this writes a standard DER record. This is often used when -+ * efficiently encapsulating implicitly tagged values. -+ * -+ * @param tag the DER value of the context-specific tag that replaces -+ * original tag of the value in the output , such as in -+ * -+ *

-+     * 	  [N] IMPLICIT 
-+     * 
-+ * -+ * For example, FooLength [1] IMPLICIT INTEGER, with value=4; -+ * would be encoded as "81 01 04" whereas in explicit -+ * tagging it would be encoded as "A1 03 02 01 04". -+ * Notice that the tag is A1 and not 81, this is because with -+ * explicit tagging the form is always constructed. -+ * @param value original value being implicitly tagged -+ */ -+ public void writeImplicit(byte tag, DerOutputStream value) -+ throws IOException { -+ write(tag); -+ write(value.buf, 1, value.count - 1); -+ } -+ -+ /** -+ * Marshals pre-encoded DER value onto the output stream. -+ */ -+ public void putDerValue(DerValue val) throws IOException { -+ val.encode(this); -+ } -+ -+ /* -+ * PRIMITIVES -- these are "universal" ASN.1 simple types. -+ * -+ * BOOLEAN, INTEGER, BIT STRING, OCTET STRING, NULL -+ * OBJECT IDENTIFIER, SEQUENCE(OF), SET(OF) -+ * PrintableString, T61String, IA5String, UTCTime -+ */ -+ -+ /** -+ * Marshals a DER boolean on the output stream. -+ */ -+ public void putBoolean(boolean val) throws IOException { -+ write(DerValue.tag_Boolean); -+ putLength(1); -+ if (val) { -+ write(0xff); -+ } else { -+ write(0); -+ } -+ } -+ -+ /** -+ * Marshals a DER unsigned integer on the output stream. -+ */ -+ public void putInteger(BigInt i) throws IOException { -+ putUnsignedInteger(i.toByteArray()); -+ } -+ -+ /** -+ * Marshals a DER unsigned integer on the output stream. -+ */ -+ public void putUnsignedInteger(byte[] integerBytes) throws IOException { -+ -+ write(DerValue.tag_Integer); -+ if ((integerBytes[0] & 0x080) != 0) { -+ /* -+ * prepend zero so it's not read as a negative number -+ */ -+ putLength(integerBytes.length + 1); -+ write(0); -+ } else -+ putLength(integerBytes.length); -+ write(integerBytes, 0, integerBytes.length); -+ } -+ -+ /** -+ * Marshals a DER enumerated value on the output stream. -+ */ -+ public void putEnumerated(int i) throws IOException { -+ write(DerValue.tag_Enumerated); -+ -+ int bytemask = 0xff000000; -+ int signmask = 0x80000000; -+ int length; -+ if ((i & 0x80000000) != 0) { -+ // negative case -+ for (length = 4; length > 1; --length) { -+ if ((i & bytemask) != bytemask) -+ break; -+ bytemask = bytemask >>> 8; -+ signmask = signmask >>> 8; -+ } -+ if ((i & signmask) == 0) { -+ // ensure negative case -+ putLength(length + 1); -+ write(0xff); -+ } else { -+ putLength(length); -+ } -+ // unrolled loop -+ switch (length) { -+ case 4: -+ write((byte) (i >>> 24)); -+ case 3: -+ write((byte) (i >>> 16)); -+ case 2: -+ write((byte) (i >>> 8)); -+ case 1: -+ write((byte) i); -+ } -+ } else { -+ // positive case -+ for (length = 4; length > 0; --length) { -+ if ((i & bytemask) != 0) -+ break; -+ bytemask = bytemask >>> 8; -+ signmask = signmask >>> 8; -+ } -+ if ((i & signmask) != 0) { -+ // ensure posititive case -+ putLength(length + 1); -+ write(0x00); -+ } else { -+ putLength(length); -+ } -+ // unrolled loop -+ switch (length) { -+ case 4: -+ write((byte) (i >>> 24)); -+ case 3: -+ write((byte) (i >>> 16)); -+ case 2: -+ write((byte) (i >>> 8)); -+ case 1: -+ write((byte) i); -+ } -+ } -+ } -+ -+ /** -+ * Marshals a DER bit string on the output stream. The bit -+ * string must be byte-aligned. -+ * -+ * @param bits the bit string, MSB first -+ */ -+ public void putBitString(byte[] bits) throws IOException { -+ write(DerValue.tag_BitString); -+ putLength(bits.length + 1); -+ write(0); // all of last octet is used -+ write(bits); -+ } -+ -+ /** -+ * Converts a boolean array to a BitArray. Trims trailing 0 bits -+ * in accordance with DER encoding standard. We assume the input is not -+ * null. -+ */ -+ private static BitArray toBitArray(boolean[] bitString) { -+ if (bitString.length == 0) { -+ return new BitArray(bitString); -+ } -+ -+ // find index of last 1 bit. -1 if there aren't any -+ int i; -+ for (i = bitString.length - 1; i >= 0; i--) { -+ if (bitString[i]) { -+ break; -+ } -+ } -+ int length = i + 1; -+ -+ // if length changed, copy to new appropriately-sized array -+ if (length != bitString.length) { -+ boolean[] newBitString = new boolean[length]; -+ System.arraycopy(bitString, 0, newBitString, 0, length); -+ bitString = newBitString; -+ } -+ -+ return new BitArray(bitString); -+ } -+ -+ /** -+ * Converts bit string to a BitArray, stripping off trailing 0 bits. -+ * We assume that the bit string is not null. -+ */ -+ private static BitArray toBitArray(byte[] bitString) { -+ // compute length in bits of bit string -+ int length, i; -+ int maxIndex = 0; -+ -+ if (bitString.length == 0) { -+ return new BitArray(0, bitString); -+ } -+ -+ // find the index of the last byte with a 1 bit -+ for (i = 0; i < bitString.length; i++) { -+ if (bitString[i] != 0) { -+ maxIndex = i; -+ } -+ } -+ byte lastByte = bitString[maxIndex]; -+ length = (maxIndex + 1) * 8; // maximum, might reduce in next step -+ -+ // now find the last 1 bit in this last byte -+ for (i = 1; i <= 0x80; i <<= 1) { -+ if ((lastByte & i) == 0) { -+ length--; -+ } else { -+ break; -+ } -+ } -+ return new BitArray(length, bitString); -+ } -+ -+ /** -+ * Marshals a DER bit string on the output stream. -+ * The bit strings need not be byte-aligned. -+ * -+ * @param bits the bit string, MSB first -+ */ -+ public void putUnalignedBitString(BitArray ba) throws IOException { -+ byte[] bits = ba.toByteArray(); -+ -+ write(DerValue.tag_BitString); -+ putLength(bits.length + 1); -+ write(bits.length * 8 - ba.length()); // excess bits in last octet -+ write(bits); -+ } -+ -+ /** -+ * Marshals a DER bit string on the output stream. -+ * All trailing 0 bits will be stripped off in accordance with DER -+ * encoding. -+ * -+ * @param bits the bit string, MSB first -+ */ -+ public void putUnalignedBitString(byte[] bitString) throws IOException { -+ putUnalignedBitString(toBitArray(bitString)); -+ } -+ -+ /** -+ * Marshals a DER bit string on the output stream. -+ * All trailing 0 bits will be stripped off in accordance with DER -+ * encoding. -+ * -+ * @param bits the bit string as an array of booleans. -+ */ -+ public void putUnalignedBitString(boolean[] bitString) throws IOException { -+ putUnalignedBitString(toBitArray(bitString)); -+ } -+ -+ /** -+ * DER-encodes an ASN.1 OCTET STRING value on the output stream. -+ * -+ * @param octets the octet string -+ */ -+ public void putOctetString(byte[] octets) throws IOException { -+ write(DerValue.tag_OctetString, octets); -+ } -+ -+ /** -+ * Marshals a DER "null" value on the output stream. These are -+ * often used to indicate optional values which have been omitted. -+ */ -+ public void putNull() throws IOException { -+ write(DerValue.tag_Null); -+ putLength(0); -+ } -+ -+ /** -+ * Marshals an object identifier (OID) on the output stream. -+ * Corresponds to the ASN.1 "OBJECT IDENTIFIER" construct. -+ */ -+ public void putOID(ObjectIdentifier oid) throws IOException { -+ oid.encode(this); -+ } -+ -+ /** -+ * Marshals a sequence on the output stream. This supports both -+ * the ASN.1 "SEQUENCE" (zero to N values) and "SEQUENCE OF" -+ * (one to N values) constructs. -+ */ -+ public void putSequence(DerValue[] seq) throws IOException { -+ DerOutputStream bytes = new DerOutputStream(); -+ int i; -+ -+ for (i = 0; i < seq.length; i++) -+ seq[i].encode(bytes); -+ -+ write(DerValue.tag_Sequence, bytes); -+ } -+ -+ /** -+ * Marshals the contents of a set on the output stream without -+ * ordering the elements. Ok for BER encoding, but not for DER -+ * encoding. -+ * -+ * For DER encoding, use orderedPutSet() or orderedPutSetOf(). -+ */ -+ public void putSet(DerValue[] set) throws IOException { -+ DerOutputStream bytes = new DerOutputStream(); -+ int i; -+ -+ for (i = 0; i < set.length; i++) -+ set[i].encode(bytes); -+ -+ write(DerValue.tag_Set, bytes); -+ } -+ -+ /** -+ * NSCP : -+ * Like putOrderSetOf, except not sorted. -+ * This may defy DER encoding but is needed for compatibility -+ * with communicator. -+ */ -+ public void putSet(byte tag, DerEncoder[] set) throws IOException { -+ putOrderedSet(tag, set, null); -+ } -+ -+ /** -+ * Marshals the contents of a set on the output stream. Sets -+ * are semantically unordered, but DER requires that encodings of -+ * set elements be sorted into ascending lexicographical order -+ * before being output. Hence sets with the same tags and -+ * elements have the same DER encoding. -+ * -+ * This method supports the ASN.1 "SET OF" construct, but not -+ * "SET", which uses a different order. -+ */ -+ public void putOrderedSetOf(byte tag, DerEncoder[] set) throws IOException { -+ putOrderedSet(tag, set, lexOrder); -+ } -+ -+ /** -+ * Marshals the contents of a set on the output stream. Sets -+ * are semantically unordered, but DER requires that encodings of -+ * set elements be sorted into ascending tag order -+ * before being output. Hence sets with the same tags and -+ * elements have the same DER encoding. -+ * -+ * This method supports the ASN.1 "SET" construct, but not -+ * "SET OF", which uses a different order. -+ */ -+ public void putOrderedSet(byte tag, DerEncoder[] set) throws IOException { -+ putOrderedSet(tag, set, tagOrder); -+ } -+ -+ /** -+ * Lexicographical order comparison on byte arrays, for ordering -+ * elements of a SET OF objects in DER encoding. -+ */ -+ private static ByteArrayLexOrder lexOrder = new ByteArrayLexOrder(); -+ -+ /** -+ * Tag order comparison on byte arrays, for ordering elements of -+ * SET objects in DER encoding. -+ */ -+ private static ByteArrayTagOrder tagOrder = new ByteArrayTagOrder(); -+ -+ /** -+ * Marshals a the contents of a set on the output stream with the -+ * encodings of its sorted in increasing order. -+ * -+ * @param order the order to use when sorting encodings of components. -+ */ -+ private void putOrderedSet(byte tag, DerEncoder[] set, -+ Comparator order) throws IOException { -+ DerOutputStream[] streams = new DerOutputStream[set.length]; -+ -+ for (int i = 0; i < set.length; i++) { -+ streams[i] = new DerOutputStream(); -+ set[i].derEncode(streams[i]); -+ } -+ -+ // order the element encodings -+ byte[][] bufs = new byte[streams.length][]; -+ for (int i = 0; i < streams.length; i++) { -+ bufs[i] = streams[i].toByteArray(); -+ } -+ if (order != null) { -+ Arrays.sort(bufs, order); -+ } -+ -+ DerOutputStream bytes = new DerOutputStream(); -+ for (int i = 0; i < streams.length; i++) { -+ bytes.write(bufs[i]); -+ } -+ write(tag, bytes); -+ -+ } -+ -+ /** -+ * Converts string to printable and writes to der output stream. -+ */ -+ public void putPrintableString(String s) throws IOException { -+ putStringType(DerValue.tag_PrintableString, s); -+ } -+ -+ public void putVisibleString(String s) throws IOException { -+ putStringType(DerValue.tag_VisibleString, s); -+ } -+ -+ /** -+ * Marshals a string which is consists of BMP (unicode) characters -+ */ -+ public void putBMPString(String s) throws IOException { -+ putStringType(DerValue.tag_BMPString, s); -+ } -+ -+ public void putGeneralString(String s) throws IOException { -+ putStringType(DerValue.tag_GeneralString, s); -+ } -+ -+ // /* -+ // * T61 is an 8 bit extension to ASCII, escapes e.g. to Japanese -+ // */ -+ // void putT61String(String s) throws IOException -+ // { -+ // // XXX IMPLEMENT ME -+ // -+ // throw new IOException("DerOutputStream.putT61String() NYI"); -+ // } -+ -+ // /* -+ // * Universal String. -+ // */ -+ // void putUniversalString(String s) throws IOException -+ // { -+ // // XXX IMPLEMENT ME -+ // -+ // throw new IOException("DerOutputStream.putUniversalString() NYI"); -+ // } -+ -+ /** -+ * Marshals a string which is consists of IA5(ASCII) characters -+ */ -+ public void putIA5String(String s) throws IOException { -+ putStringType(DerValue.tag_IA5String, s); -+ } -+ -+ public void putUTF8String(String s) throws IOException { -+ putStringType(DerValue.tag_UTF8String, s); -+ } -+ -+ public void putStringType(byte tag, String s) throws IOException { -+ try { -+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(tag); -+ if (encoder == null) -+ throw new IOException("No encoder for tag"); -+ -+ CharBuffer charBuffer = CharBuffer.wrap(s.toCharArray()); -+ ByteBuffer byteBuffer = encoder.encode(charBuffer); -+ -+ write(tag); -+ putLength(byteBuffer.limit()); -+ write(byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit()); -+ -+ } catch (CharacterCodingException e) { -+ throw new IOException("Not a valid string type " + tag, e); -+ } -+ } -+ -+ private void put2DateBytes(byte[] buffer, int value, int offset) { -+ int upper = value / 10; -+ int lower = value % 10; -+ buffer[offset] = (byte) ((byte) upper + (byte) '0'); -+ buffer[offset + 1] = (byte) ((byte) lower + (byte) '0'); -+ } -+ -+ private static Calendar GMTGregorianCalendar = null; -+ -+ private Calendar getGMTGregorianCalendar() { -+ if (GMTGregorianCalendar == null) { -+ TimeZone tz = TimeZone.getTimeZone("GMT"); -+ GMTGregorianCalendar = new GregorianCalendar(tz); -+ } -+ return (Calendar) GMTGregorianCalendar.clone(); -+ } -+ -+ public byte[] getDateBytes(Date d, boolean UTC) { -+ -+ byte[] datebytes; -+ -+ if (UTC) { -+ datebytes = new byte[13]; -+ } else { // generalized time has 4 digits for yr -+ datebytes = new byte[15]; -+ } -+ -+ Calendar cal = getGMTGregorianCalendar(); -+ cal.setTime(d); -+ -+ int i = 0; -+ if (!UTC) { -+ put2DateBytes(datebytes, cal.get(Calendar.YEAR) / 100, i); -+ i += 2; -+ } -+ put2DateBytes(datebytes, cal.get(Calendar.YEAR) % 100, i); -+ // Calendar's MONTH is zero-based -+ i += 2; -+ put2DateBytes(datebytes, cal.get(Calendar.MONTH) + 1, i); -+ i += 2; -+ put2DateBytes(datebytes, cal.get(Calendar.DAY_OF_MONTH), i); -+ i += 2; -+ put2DateBytes(datebytes, cal.get(Calendar.HOUR_OF_DAY), i); -+ i += 2; -+ put2DateBytes(datebytes, cal.get(Calendar.MINUTE), i); -+ i += 2; -+ put2DateBytes(datebytes, cal.get(Calendar.SECOND), i); -+ i += 2; -+ // datebytes[i] = 'Z'; -+ datebytes[i] = (byte) 'Z'; -+ -+ return datebytes; -+ } -+ -+ /** -+ * Marshals a DER UTC time/date value. -+ * -+ *

-+ * YYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time and with seconds (even if seconds=0) as per IETF-PKIX -+ * partI. -+ */ -+ public void putUTCTime(Date d) throws IOException { -+ /* -+ * Format the date. -+ */ -+ -+ // This was the old code. Way too slow to be usable (stevep) -+ -+ // String pattern = "yyMMddHHmmss'Z'"; -+ // SimpleDateFormat sdf = new SimpleDateFormat(pattern); -+ // TimeZone tz = TimeZone.getTimeZone("GMT"); -+ // sdf.setTimeZone(tz); -+ // byte[] utc = (sdf.format(d)).getBytes(); -+ -+ byte[] datebytes = getDateBytes(d, true); // UTC = true -+ -+ /* -+ * Write the formatted date. -+ */ -+ write(DerValue.tag_UtcTime); -+ putLength(datebytes.length); -+ write(datebytes); -+ } -+ -+ /** -+ * Marshals a DER Generalized Time/date value. -+ * -+ *

-+ * YYYYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time and with seconds (even if seconds=0) as per -+ * IETF-PKIX partI. -+ */ -+ public void putGeneralizedTime(Date d) throws IOException { -+ /* -+ * Format the date. -+ */ -+ TimeZone tz = TimeZone.getTimeZone("GMT"); -+ -+ // This is way too slow to be usable (stevep) -+ String pattern = "yyyyMMddHHmmss'Z'"; -+ SimpleDateFormat sdf = new SimpleDateFormat(pattern); -+ sdf.setTimeZone(tz); -+ byte[] gt = (sdf.format(d)).getBytes(); -+ -+ /* -+ * Write the formatted date. -+ */ -+ write(DerValue.tag_GeneralizedTime); -+ putLength(gt.length); -+ write(gt); -+ } -+ -+ /** -+ * Put the encoding of the length in the stream. -+ * -+ * @param len the length of the attribute. -+ * @exception IOException on writing errors. -+ */ -+ public void putLength(int len) throws IOException { -+ if (len < 128) { -+ write((byte) len); -+ -+ } else if (len < (1 << 8)) { -+ write((byte) 0x081); -+ write((byte) len); -+ -+ } else if (len < (1 << 16)) { -+ write((byte) 0x082); -+ write((byte) (len >> 8)); -+ write((byte) len); -+ -+ } else if (len < (1 << 24)) { -+ write((byte) 0x083); -+ write((byte) (len >> 16)); -+ write((byte) (len >> 8)); -+ write((byte) len); -+ -+ } else { -+ write((byte) 0x084); -+ write((byte) (len >> 24)); -+ write((byte) (len >> 16)); -+ write((byte) (len >> 8)); -+ write((byte) len); -+ } -+ } -+ -+ /** -+ * Put the tag of the attribute in the stream. -+ * -+ * @param class the tag class type, one of UNIVERSAL, CONTEXT, -+ * APPLICATION or PRIVATE -+ * @param form if true, the value is constructed, otherwise it is -+ * primitive. -+ * @param val the tag value -+ */ -+ public void putTag(byte tagClass, boolean form, byte val) { -+ byte tag = (byte) (tagClass | val); -+ if (form) { -+ tag |= (byte) 0x20; -+ } -+ write(tag); -+ } -+ -+ /** -+ * Write the current contents of this DerOutputStream to an OutputStream. -+ * -+ * @exception IOException on output error. -+ */ -+ public void derEncode(OutputStream out) throws IOException { -+ out.write(toByteArray()); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/DerValue.java b/org/mozilla/jss/netscape/security/util/DerValue.java -new file mode 100644 -index 00000000..8419690c ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/DerValue.java -@@ -0,0 +1,748 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.ByteArrayInputStream; -+import java.io.DataInputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.CharacterCodingException; -+import java.nio.charset.CharsetDecoder; -+import java.util.Arrays; -+ -+import org.mozilla.jss.netscape.security.x509.AVAValueConverter; -+import org.mozilla.jss.netscape.security.x509.GenericValueConverter; -+ -+/** -+ * Represents a single DER-encoded value. DER encoding rules are a subset -+ * of the "Basic" Encoding Rules (BER), but they only support a single way -+ * ("Definite" encoding) to encode any given value. -+ * -+ *

-+ * All DER-encoded data are triples {type, length, data}. This class represents such tagged values as they have -+ * been read (or constructed), and provides structured access to the encoded data. -+ * -+ *

-+ * At this time, this class supports only a subset of the types of DER data encodings which are defined. That subset is -+ * sufficient for parsing most X.509 certificates, and working with selected additional formats (such as PKCS #10 -+ * certificate requests, and some kinds of PKCS #7 data). -+ * -+ * @version 1.43 -+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class DerValue { -+ /** The tag class types */ -+ public static final byte TAG_UNIVERSAL = (byte) 0x000; -+ public static final byte TAG_APPLICATION = (byte) 0x040; -+ public static final byte TAG_CONTEXT = (byte) 0x080; -+ public static final byte TAG_PRIVATE = (byte) 0x0c0; -+ -+ /** The DER tag of the value; one of the tag_ constants. */ -+ public byte tag; -+ -+ protected DerInputBuffer buffer; -+ -+ /** -+ * The DER-encoded data of the value. -+ */ -+ public DerInputStream data; -+ -+ private int length; -+ -+ /* -+ * The type starts at the first byte of the encoding, and -+ * is one of these tag_* values. That may be all the type -+ * data that is needed. -+ */ -+ -+ /* -+ * These tags are the "universal" tags ... they mean the same -+ * in all contexts. (Mask with 0x1f -- five bits.) -+ */ -+ -+ /** Tag value indicating an ASN.1 "BOOLEAN" value. */ -+ public final static byte tag_Boolean = 0x01; -+ -+ /** Tag value indicating an ASN.1 "INTEGER" value. */ -+ public final static byte tag_Integer = 0x02; -+ -+ /** Tag value indicating an ASN.1 "BIT STRING" value. */ -+ public final static byte tag_BitString = 0x03; -+ -+ /** Tag value indicating an ASN.1 "OCTET STRING" value. */ -+ public final static byte tag_OctetString = 0x04; -+ -+ /** Tag value indicating an ASN.1 "NULL" value. */ -+ public final static byte tag_Null = 0x05; -+ -+ /** Tag value indicating an ASN.1 "OBJECT IDENTIFIER" value. */ -+ public final static byte tag_ObjectId = 0x06; -+ -+ /** Tag value including an ASN.1 "ENUMERATED" value */ -+ public final static byte tag_Enumerated = 0x0A; -+ -+ /** Tag value including a "printable" string */ -+ public final static byte tag_PrintableString = 0x13; -+ -+ public final static byte tag_VisibleString = 0x1A; -+ -+ /** Tag value including a "teletype" string */ -+ public final static byte tag_T61String = 0x14; -+ -+ /** Tag value including an ASCII string */ -+ public final static byte tag_IA5String = 0x16; -+ -+ /** Tag value indicating an ASN.1 "UTCTime" value. */ -+ public final static byte tag_UtcTime = 0x17; -+ -+ /** Tag value indicating an ASN.1 "GeneralizedTime" value. */ -+ public final static byte tag_GeneralizedTime = 0x18; -+ -+ /** Tag value indicating an ASN.1 "GeneralString" value. */ -+ public final static byte tag_GeneralString = 0x1B; -+ -+ /** Tag value indicating an ASN.1 "BMPString" value. */ -+ public final static byte tag_BMPString = 0x1E; -+ -+ /** Tag value indicating an ASN.1 "UniversalString" value. */ -+ public final static byte tag_UniversalString = 0x1C; -+ -+ /** Tag value indicating an ASN.1 "UTF8String" value. (since 1998) */ -+ public final static byte tag_UTF8String = 0x0C; -+ -+ public final static byte[] tags_DirectoryString = -+ { tag_T61String -+ , tag_PrintableString -+ , tag_UniversalString -+ , tag_UTF8String -+ , tag_BMPString }; -+ -+ // CONSTRUCTED seq/set -+ -+ /** -+ * Tag value indicating an ASN.1 -+ * "SEQUENCE" (zero to N elements, order is significant). -+ */ -+ public final static byte tag_Sequence = 0x30; -+ -+ /** -+ * Tag value indicating an ASN.1 -+ * "SEQUENCE OF" (one to N elements, order is significant). -+ */ -+ public final static byte tag_SequenceOf = 0x30; -+ -+ /** -+ * Tag value indicating an ASN.1 -+ * "SET" (zero to N members, order does not matter). -+ */ -+ public final static byte tag_Set = 0x31; -+ -+ /** -+ * Tag value indicating an ASN.1 -+ * "SET OF" (one to N members, order does not matter). -+ */ -+ public final static byte tag_SetOf = 0x31; -+ -+ /* -+ * These values are the high order bits for the other kinds of tags. -+ */ -+ boolean isUniversal() { -+ return ((tag & 0x0c0) == 0x000); -+ } -+ -+ boolean isApplication() { -+ return ((tag & 0x0c0) == 0x040); -+ } -+ -+ /** -+ * Returns true iff the CONTEXT SPECIFIC bit is set in the type tag. -+ * This is associated with the ASN.1 "DEFINED BY" syntax. -+ */ -+ public boolean isContextSpecific() { -+ return ((tag & 0x0c0) == 0x080); -+ } -+ -+ /** -+ * Returns true iff the CONTEXT SPECIFIC TAG matches the passed tag. -+ */ -+ public boolean isContextSpecific(byte cntxtTag) { -+ if (!isContextSpecific()) { -+ return false; -+ } -+ return ((tag & 0x01f) == cntxtTag); -+ } -+ -+ boolean isPrivate() { -+ return ((tag & 0x0c0) == 0x0c0); -+ } -+ -+ /** Returns true iff the CONSTRUCTED bit is set in the type tag. */ -+ public boolean isConstructed() { -+ return ((tag & 0x020) == 0x020); -+ } -+ -+ /** -+ * Creates a DER value from a string -+ * using a generic way of determining the proper tag for the string. -+ * Assumes the string is a Generic attribute value and uses -+ * the converter for generic string values to convert to the Der Value. -+ */ -+ public DerValue(String value) -+ throws IOException { -+ AVAValueConverter genericValue = new GenericValueConverter(); -+ DerValue val; -+ -+ val = genericValue.getValue(value); -+ tag = val.tag; -+ buffer = val.buffer; -+ length = val.length; -+ data = val.data; -+ data.mark(Integer.MAX_VALUE); -+ } -+ -+ /** -+ * Creates a DerValue from a tag and some DER-encoded data. -+ * -+ * @param tag the DER type tag -+ * @param data the DER-encoded data -+ */ -+ public DerValue(byte tag, byte[] data) { -+ this.tag = tag; -+ buffer = new DerInputBuffer(data.clone()); -+ length = data.length; -+ this.data = new DerInputStream(buffer); -+ this.data.mark(Integer.MAX_VALUE); -+ } -+ -+ /** -+ * Creates a DerValue from a tag and some DER-encoded data. -+ * -+ * @param tag the DER type tag -+ * @param data the DER-encoded data -+ * @param offset offset of the data -+ * @param length length of the data -+ */ -+ public DerValue(byte tag, byte[] data, int offset, int length) { -+ this(tag, Arrays.copyOfRange(data, offset, offset + length)); -+ } -+ -+ /* -+ * package private -+ */ -+ DerValue(DerInputBuffer in) throws IOException { -+ // NOTE: This must handle the special value used -+ // to terminate BER indefinite encodings (tag and -+ // length are both zero) -+ -+ // XXX must also parse BER-encoded constructed -+ // values such as sequences, sets... -+ -+ tag = (byte) in.read(); -+ length = DerInputStream.getLength(in); -+ -+ buffer = in.dup(); -+ buffer.truncate(length); -+ data = new DerInputStream(buffer); -+ -+ in.skip(length); -+ } -+ -+ /** -+ * Get an ASN.1/DER encoded datum from a buffer. The -+ * entire buffer must hold exactly one datum, including -+ * its tag and length. -+ * -+ * @param buf buffer holding a single DER-encoded datum. -+ */ -+ public DerValue(byte[] buf) throws IOException { -+ init(true, new ByteArrayInputStream(buf)); -+ } -+ -+ /** -+ * Get an ASN.1/DER encoded datum from part of a buffer. -+ * That part of the buffer must hold exactly one datum, including -+ * its tag and length. -+ * -+ * @param buf the buffer -+ * @param offset start point of the single DER-encoded dataum -+ * @param length how many bytes are in the encoded datum -+ */ -+ public DerValue(byte[] buf, int offset, int len) throws IOException { -+ init(true, new ByteArrayInputStream(buf, offset, len)); -+ } -+ -+ /** -+ * Get an ASN1/DER encoded datum from an input stream. The -+ * stream may have additional data following the encoded datum. -+ * -+ * @param in the input stream holding a single DER datum, -+ * which may be followed by additional data -+ */ -+ public DerValue(InputStream in) throws IOException { -+ init(false, in); -+ } -+ -+ /* -+ * helper routine -+ */ -+ private void init(boolean fullyBuffered, InputStream in) -+ throws IOException { -+ byte[] bytes; -+ -+ tag = (byte) in.read(); -+ length = DerInputStream.getLength(in); -+ -+ /* -+ if (length == 0) -+ return; -+ */ -+ -+ if (fullyBuffered && in.available() != length) -+ throw new IOException("extra DER value data (constructor)"); -+ -+ bytes = new byte[length]; -+ -+ // n.b. readFully not needed in normal fullyBuffered case -+ DataInputStream dis = new DataInputStream(in); -+ -+ dis.readFully(bytes); -+ buffer = new DerInputBuffer(bytes); -+ data = new DerInputStream(buffer); -+ } -+ -+ /** -+ * Encode an ASN1/DER encoded datum onto a DER output stream. -+ */ -+ public void encode(DerOutputStream out) -+ throws IOException { -+ out.write(tag); -+ out.putLength(length); -+ buffer.dump(out, length); -+ -+ } -+ -+ /** -+ * Returns an ASN.1 BOOLEAN -+ * -+ * @return the boolean held in this DER value -+ */ -+ public boolean getBoolean() throws IOException { -+ if (tag != tag_Boolean) { -+ throw new IOException("DerValue.getBoolean, not a BOOLEAN " + tag); -+ } -+ if (length != 1) { -+ throw new IOException("DerValue.getBoolean, invalid length " + length); -+ } -+ if (buffer.read() != 0) { -+ return true; -+ } -+ return false; -+ } -+ -+ /** -+ * Returns an ASN.1 OBJECT IDENTIFIER. -+ * -+ * @return the OID held in this DER value -+ */ -+ public ObjectIdentifier getOID() throws IOException { -+ if (tag != tag_ObjectId) -+ throw new IOException("DerValue.getOID, not an OID " + tag); -+ return new ObjectIdentifier(buffer); -+ } -+ -+ /** -+ * Returns an ASN.1 OCTET STRING -+ * -+ * @return the octet string held in this DER value -+ */ -+ public byte[] getOctetString() throws IOException { -+ if (tag != tag_OctetString) -+ throw new IOException( -+ "DerValue.getOctetString, not an Octet String: " + tag); -+ -+ byte[] bytes = new byte[length]; -+ -+ if (buffer.read(bytes) != length) -+ throw new IOException("short read on DerValue buffer"); -+ return bytes; -+ } -+ -+ /** -+ * Returns an ASN.1 unsigned integer value of enumerated value. -+ * -+ * @return the (unsigned) integer held in this DER value -+ */ -+ public int getEnumerated() -+ throws IOException { -+ if (tag != tag_Enumerated) -+ throw new IOException("DerValue.getEnumerated, not an ENUMERATED " + tag); -+ if (length == 0) -+ return 0; -+ if (length > 4 || length < 1) -+ throw new IOException("DerValue.getEnumerated, invalid length " + length + "(must be between 1 and 4)"); -+ -+ int value = 0; -+ int nextbyte = buffer.read(); -+ if (nextbyte == -1) -+ throw new IOException("short read on DerValue buffer"); -+ // perform sign extension -+ value = (byte) nextbyte; -+ -+ for (int i = length - 1; i > 0; --i) { -+ nextbyte = buffer.read(); -+ if (nextbyte == -1) -+ throw new IOException("short read on DerValue buffer"); -+ value = 256 * value + nextbyte; -+ } -+ return value; -+ } -+ -+ /** -+ * Returns an ASN.1 unsigned INTEGER value. -+ * -+ * @return the (unsigned) integer held in this DER value -+ */ -+ public BigInt getInteger() throws IOException { -+ if (tag != tag_Integer) -+ throw new IOException("DerValue.getInteger, not an int " + tag); -+ return buffer.getUnsigned(data.available()); -+ } -+ -+ /** -+ * Returns an ASN.1 unsigned INTEGER value, the parameter determining -+ * if the tag is implicit. -+ * -+ * @param tagImplicit if true, ignores the tag value as it is -+ * assumed implicit. -+ * @return the (unsigned) integer held in this DER value -+ */ -+ public BigInt getInteger(boolean tagImplicit) throws IOException { -+ if (!tagImplicit) { -+ if (tag != tag_Integer) { -+ throw new IOException("DerValue.getInteger, not an int " -+ + tag); -+ } -+ } -+ return buffer.getUnsigned(data.available()); -+ } -+ -+ /** -+ * Returns an ASN.1 BIT STRING value. The bit string must be byte-aligned. -+ * -+ * @return the bit string held in this value -+ */ -+ public byte[] getBitString() throws IOException { -+ if (tag != tag_BitString) -+ throw new IOException( -+ "DerValue.getBitString, not a bit string " + tag); -+ -+ return buffer.getBitString(); -+ } -+ -+ /** -+ * Returns an ASN.1 BIT STRING value that need not be byte-aligned. -+ * -+ * @return a BitArray representing the bit string held in this value -+ */ -+ public BitArray getUnalignedBitString() throws IOException { -+ if (tag != tag_BitString) -+ throw new IOException( -+ "DerValue.getBitString, not a bit string " + tag); -+ -+ return buffer.getUnalignedBitString(); -+ } -+ -+ /** -+ * Returns the name component as a Java string, regardless of its -+ * encoding restrictions (ASCII, T61, Printable, etc). -+ */ -+ public String getAsString() throws IOException { -+ AVAValueConverter genericValue = new GenericValueConverter(); -+ return genericValue.getAsString(this); -+ } -+ -+ /** -+ * Returns an ASN.1 BIT STRING value, with the tag assumed implicit -+ * based on the parameter. The bit string must be byte-aligned. -+ * -+ * @param tagImplicit if true, the tag is assumed implicit. -+ * @return the bit string held in this value -+ */ -+ public byte[] getBitString(boolean tagImplicit) throws IOException { -+ if (!tagImplicit) { -+ if (tag != tag_BitString) -+ throw new IOException("DerValue.getBitString, not a bit string " -+ + tag); -+ } -+ return buffer.getBitString(); -+ } -+ -+ /** -+ * Returns an ASN.1 BIT STRING value, with the tag assumed implicit -+ * based on the parameter. The bit string need not be byte-aligned. -+ * -+ * @param tagImplicit if true, the tag is assumed implicit. -+ * @return the bit string held in this value -+ */ -+ public BitArray getUnalignedBitString(boolean tagImplicit) -+ throws IOException { -+ if (!tagImplicit) { -+ if (tag != tag_BitString) -+ throw new IOException("DerValue.getBitString, not a bit string " -+ + tag); -+ } -+ return buffer.getUnalignedBitString(); -+ } -+ -+ /** -+ * Returns an ASN.1 STRING value -+ * -+ * @return the printable string held in this value -+ */ -+ public String getPrintableString() -+ throws IOException { -+ if (tag != tag_PrintableString) -+ throw new IOException( -+ "DerValue.getPrintableString, not a string " + tag); -+ -+ return getASN1CharString(); -+ } -+ -+ public String getDirectoryString() throws IOException { -+ boolean tagValid = false; -+ for (int i = 0; i < tags_DirectoryString.length; i++) { -+ if (tag == tags_DirectoryString[i]) { -+ tagValid = true; -+ break; -+ } -+ } -+ if (!tagValid) -+ throw new IOException( -+ "DerValue.getDirectoryString: invalid tag: " + tag); -+ -+ return getASN1CharString(); -+ } -+ -+ /* -+ * @eturns a string if the DerValue is a ASN.1 character string type and -+ * if there is a decoder for the type. Returns null otherwise. -+ */ -+ public String getASN1CharString() throws IOException { -+ try { -+ CharsetDecoder decoder = ASN1CharStrConvMap.getDefault().getDecoder(tag); -+ if (decoder == null) -+ return null; -+ -+ ByteBuffer byteBuffer = ByteBuffer.allocate(length); -+ -+ data.reset(); -+ data.getBytes(byteBuffer.array()); -+ -+ CharBuffer charBuffer = decoder.decode(byteBuffer); -+ return charBuffer.toString(); -+ -+ } catch (CharacterCodingException e) { -+ throw new IOException("Misformed DER value", e); -+ } -+ } -+ -+ /** -+ * Returns an ASN.1 T61 (Teletype) STRING value -+ * -+ * @return the teletype string held in this value -+ */ -+ public String getT61String() throws IOException { -+ if (tag != tag_T61String) -+ throw new IOException( -+ "DerValue.getT61String, not T61 " + tag); -+ -+ return getASN1CharString(); -+ } -+ -+ /** -+ * Returns an ASN.1 IA5 (ASCII) STRING value -+ * -+ * @return the ASCII string held in this value -+ */ -+ public String getIA5String() throws IOException { -+ if (tag != tag_IA5String) -+ throw new IOException( -+ "DerValue.getIA5String, not IA5 " + tag); -+ -+ return getASN1CharString(); -+ } -+ -+ public String getBMPString() -+ throws IOException { -+ if (tag != tag_BMPString) -+ throw new IOException( -+ "DerValue.getBMPString, not BMP " + tag); -+ -+ return getASN1CharString(); -+ } -+ -+ public String getUniversalString() -+ throws IOException { -+ if (tag != tag_UniversalString) -+ throw new IOException( -+ "DerValue.getUniversalString, not UniversalString " + tag); -+ -+ return getASN1CharString(); -+ } -+ -+ public String getUTF8String() -+ throws IOException { -+ if (tag != tag_UTF8String) -+ throw new IOException( -+ "DerValue.getUTF8String, not UTF8String " + tag); -+ -+ return getASN1CharString(); -+ } -+ -+ /** -+ * Returns true iff the other object is a DER value which -+ * is bitwise equal to this one. -+ * -+ * @param other the object being compared with this one -+ */ -+ public boolean equals(Object other) { -+ if (other instanceof DerValue) -+ return equals((DerValue) other); -+ else -+ return false; -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + ((buffer == null) ? 0 : buffer.hashCode()); -+ result = prime * result + ((data == null) ? 0 : data.hashCode()); -+ result = prime * result + length; -+ result = prime * result + tag; -+ return result; -+ } -+ -+ /** -+ * Bitwise equality comparison. DER encoded values have a single -+ * encoding, so that bitwise equality of the encoded values is an -+ * efficient way to establish equivalence of the unencoded values. -+ * -+ * @param other the object being compared with this one -+ */ -+ public boolean equals(DerValue other) { -+ data.reset(); -+ other.data.reset(); -+ if (this == other) -+ return true; -+ else if (tag != other.tag) { -+ return false; -+ } else { -+ return buffer.equals(other.buffer); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the value. -+ * -+ * @return printable representation of the value -+ */ -+ public String toString() { -+ try { -+ String s = getAsString(); -+ if (s != null) -+ return s; -+ if (tag == tag_Null) -+ return "[DerValue, null]"; -+ if (tag == tag_ObjectId) -+ return "OID." + getOID(); -+ -+ // integers -+ else -+ return "[DerValue, tag = " + tag -+ + ", length = " + length + "]"; -+ } catch (IOException e) { -+ throw new IllegalArgumentException("misformatted DER value"); -+ } -+ } -+ -+ /** -+ * Returns a DER-encoded value, such that if it's passed to the -+ * DerValue constructor, a value equivalent to "this" is returned. -+ * -+ * @return DER-encoded value, including tag and length. -+ */ -+ public byte[] toByteArray() throws IOException { -+ DerOutputStream out = new DerOutputStream(); -+ -+ encode(out); -+ data.reset(); -+ return out.toByteArray(); -+ } -+ -+ /** -+ * For "set" and "sequence" types, this function may be used -+ * to return a DER stream of the members of the set or sequence. -+ * This operation is not supported for primitive types such as -+ * integers or bit strings. -+ */ -+ public DerInputStream toDerInputStream() throws IOException { -+ if (tag == tag_Sequence || tag == tag_Set) -+ return new DerInputStream(buffer); -+ throw new IOException("toDerInputStream rejects tag type " + tag); -+ } -+ -+ /** -+ * Get the length of the encoded value. -+ */ -+ public int length() { -+ return length; -+ } -+ -+ /** -+ * Create the tag of the attribute. -+ * -+ * @param class the tag class type, one of UNIVERSAL, CONTEXT, -+ * APPLICATION or PRIVATE -+ * @param form if true, the value is constructed, otherwise it -+ * is primitive. -+ * @param val the tag value -+ */ -+ public static byte createTag(byte tagClass, boolean form, byte val) { -+ byte tag = (byte) (tagClass | val); -+ if (form) { -+ tag |= (byte) 0x20; -+ } -+ return (tag); -+ } -+ -+ /** -+ * Set the tag of the attribute. Commonly used to reset the -+ * tag value used for IMPLICIT encodings. -+ * -+ * @param tag the tag value -+ */ -+ public void resetTag(byte tag) { -+ this.tag = tag; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/ExtPrettyPrint.java b/org/mozilla/jss/netscape/security/util/ExtPrettyPrint.java -new file mode 100644 -index 00000000..83fe1996 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/ExtPrettyPrint.java -@@ -0,0 +1,1586 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.IOException; -+import java.math.BigInteger; -+import java.security.cert.CertificateException; -+import java.text.DateFormat; -+import java.util.Enumeration; -+import java.util.ResourceBundle; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.extensions.AccessDescription; -+import org.mozilla.jss.netscape.security.extensions.AuthInfoAccessExtension; -+import org.mozilla.jss.netscape.security.extensions.CertificateScopeEntry; -+import org.mozilla.jss.netscape.security.extensions.CertificateScopeOfUseExtension; -+import org.mozilla.jss.netscape.security.extensions.ExtendedKeyUsageExtension; -+import org.mozilla.jss.netscape.security.extensions.InhibitAnyPolicyExtension; -+import org.mozilla.jss.netscape.security.extensions.NSCertTypeExtension; -+import org.mozilla.jss.netscape.security.extensions.OCSPNoCheckExtension; -+import org.mozilla.jss.netscape.security.extensions.PresenceServerExtension; -+import org.mozilla.jss.netscape.security.extensions.SubjectInfoAccessExtension; -+import org.mozilla.jss.netscape.security.x509.Attribute; -+import org.mozilla.jss.netscape.security.x509.AuthorityKeyIdentifierExtension; -+import org.mozilla.jss.netscape.security.x509.BasicConstraintsExtension; -+import org.mozilla.jss.netscape.security.x509.CPSuri; -+import org.mozilla.jss.netscape.security.x509.CRLDistributionPoint; -+import org.mozilla.jss.netscape.security.x509.CRLDistributionPointsExtension; -+import org.mozilla.jss.netscape.security.x509.CRLDistributionPointsExtension.Reason; -+import org.mozilla.jss.netscape.security.x509.CRLNumberExtension; -+import org.mozilla.jss.netscape.security.x509.CRLReasonExtension; -+import org.mozilla.jss.netscape.security.x509.CertificateIssuerExtension; -+import org.mozilla.jss.netscape.security.x509.CertificatePoliciesExtension; -+import org.mozilla.jss.netscape.security.x509.CertificatePolicyInfo; -+import org.mozilla.jss.netscape.security.x509.CertificatePolicyMap; -+import org.mozilla.jss.netscape.security.x509.DeltaCRLIndicatorExtension; -+import org.mozilla.jss.netscape.security.x509.DisplayText; -+import org.mozilla.jss.netscape.security.x509.Extension; -+import org.mozilla.jss.netscape.security.x509.FreshestCRLExtension; -+import org.mozilla.jss.netscape.security.x509.GeneralName; -+import org.mozilla.jss.netscape.security.x509.GeneralNameInterface; -+import org.mozilla.jss.netscape.security.x509.GeneralNames; -+import org.mozilla.jss.netscape.security.x509.HoldInstructionExtension; -+import org.mozilla.jss.netscape.security.x509.InvalidityDateExtension; -+import org.mozilla.jss.netscape.security.x509.IssuerAlternativeNameExtension; -+import org.mozilla.jss.netscape.security.x509.IssuingDistributionPoint; -+import org.mozilla.jss.netscape.security.x509.IssuingDistributionPointExtension; -+import org.mozilla.jss.netscape.security.x509.KeyIdentifier; -+import org.mozilla.jss.netscape.security.x509.KeyUsageExtension; -+import org.mozilla.jss.netscape.security.x509.NSCCommentExtension; -+import org.mozilla.jss.netscape.security.x509.NameConstraintsExtension; -+import org.mozilla.jss.netscape.security.x509.NoticeReference; -+import org.mozilla.jss.netscape.security.x509.OIDMap; -+import org.mozilla.jss.netscape.security.x509.PolicyConstraintsExtension; -+import org.mozilla.jss.netscape.security.x509.PolicyMappingsExtension; -+import org.mozilla.jss.netscape.security.x509.PolicyQualifierInfo; -+import org.mozilla.jss.netscape.security.x509.PolicyQualifiers; -+import org.mozilla.jss.netscape.security.x509.PrivateKeyUsageExtension; -+import org.mozilla.jss.netscape.security.x509.Qualifier; -+import org.mozilla.jss.netscape.security.x509.RDN; -+import org.mozilla.jss.netscape.security.x509.SerialNumber; -+import org.mozilla.jss.netscape.security.x509.SubjectAlternativeNameExtension; -+import org.mozilla.jss.netscape.security.x509.SubjectDirAttributesExtension; -+import org.mozilla.jss.netscape.security.x509.SubjectKeyIdentifierExtension; -+import org.mozilla.jss.netscape.security.x509.UserNotice; -+ -+/** -+ * This class will display the certificate content in predefined -+ * format. -+ * -+ * @author Andrew Wnuk -+ * @version $Revision$, $Date$ -+ */ -+public class ExtPrettyPrint { -+ -+ /*========================================================== -+ * variables -+ *==========================================================*/ -+ private Extension mExt = null; -+ private ResourceBundle mResource = null; -+ private PrettyPrintFormat pp = null; -+ private int mIndentSize = 0; -+ -+ DateFormat dateFormater = null; -+ -+ /*========================================================== -+ * constructors -+ *==========================================================*/ -+ -+ public ExtPrettyPrint(Extension ext, int indentSize) { -+ mExt = ext; -+ mResource = ResourceBundle.getBundle(PrettyPrintResources.class.getName()); -+ mIndentSize = indentSize; -+ pp = new PrettyPrintFormat(":"); -+ } -+ -+ /*========================================================== -+ * public methods -+ *==========================================================*/ -+ -+ /** -+ * This method return string representation of the certificate -+ * in predefined format using specified client local. I18N Support. -+ * -+ * @param clientLocale Locale to be used for localization -+ * @return string representation of the certificate -+ */ -+ // public String toString(int indentSize) { -+ public String toString() { -+ -+ StringBuffer sb = new StringBuffer(); -+ -+ //check if the extension is known -+ if (mExt instanceof KeyUsageExtension) { -+ return getKeyUsage(); -+ } -+ if (mExt instanceof NSCertTypeExtension) { -+ return getCertType(); -+ } -+ if (mExt instanceof AuthorityKeyIdentifierExtension) { -+ return getAuthorityKeyIdentifier(); -+ } -+ if (mExt instanceof SubjectKeyIdentifierExtension) { -+ return getSubjectKeyIdentifier(); -+ } -+ if (mExt instanceof CRLReasonExtension) { -+ return getCRLReasonExtension(); -+ } -+ if (mExt instanceof BasicConstraintsExtension) { -+ return getBasicConstraintsExtension(); -+ } -+ if (mExt instanceof NSCCommentExtension) { -+ return getNSCCommentExtension(); -+ } -+ if (mExt instanceof NameConstraintsExtension) { -+ return getNameConstraintsExtension(); -+ } -+ if (mExt instanceof CRLNumberExtension) { -+ return getCRLNumberExtension(); -+ } -+ if (mExt instanceof DeltaCRLIndicatorExtension) { -+ return getDeltaCRLIndicatorExtension(); -+ } -+ if (mExt instanceof IssuerAlternativeNameExtension) { -+ return getIssuerAlternativeNameExtension(); -+ } -+ if (mExt instanceof SubjectAlternativeNameExtension) { -+ return getSubjectAlternativeNameExtension(); -+ } -+ if (mExt instanceof FreshestCRLExtension) { -+ return getFreshestCRLExtension(); -+ } -+ if (mExt instanceof CRLDistributionPointsExtension) { -+ return getCRLDistributionPointsExtension(); -+ } -+ if (mExt instanceof IssuingDistributionPointExtension) { -+ return getIssuingDistributionPointExtension(); -+ } -+ if (mExt instanceof ExtendedKeyUsageExtension) { -+ return getExtendedKeyUsageExtension(); -+ } -+ if (mExt instanceof AuthInfoAccessExtension) { -+ return getAuthInfoAccessExtension(); -+ } -+ if (mExt instanceof SubjectInfoAccessExtension) { -+ return getSubjectInfoAccessExtension(); -+ } -+ if (mExt instanceof OCSPNoCheckExtension) { -+ return getOCSPNoCheckExtension(); -+ } -+ if (mExt instanceof PrivateKeyUsageExtension) { -+ return getPrivateKeyUsageExtension(); -+ } -+ if (mExt instanceof InvalidityDateExtension) { -+ return getInvalidityDateExtension(); -+ } -+ if (mExt instanceof CertificateIssuerExtension) { -+ return getCertificateIssuerExtension(); -+ } -+ if (mExt instanceof HoldInstructionExtension) { -+ return getHoldInstructionExtension(); -+ } -+ if (mExt instanceof PolicyConstraintsExtension) { -+ return getPolicyConstraintsExtension(); -+ } -+ if (mExt instanceof PolicyMappingsExtension) { -+ return getPolicyMappingsExtension(); -+ } -+ if (mExt instanceof SubjectDirAttributesExtension) { -+ return getSubjectDirAttributesExtension(); -+ } -+ if (mExt instanceof CertificateScopeOfUseExtension) { -+ return getCertificateScopeOfUseExtension(); -+ } -+ if (mExt instanceof PresenceServerExtension) { -+ return getPresenceServerExtension(); -+ } -+ -+ if (mExt instanceof InhibitAnyPolicyExtension) { -+ return getInhibitAnyPolicyExtension(); -+ } -+ -+ if (mExt instanceof CertificatePoliciesExtension) { -+ return getCertificatePoliciesExtension(); -+ } -+ -+ //unknown cert extension -+ String extName = OIDMap.getName(mExt.getExtensionId()); -+ -+ if (extName == null) -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER) + -+ mExt.getExtensionId().toString() + "\n"); -+ else -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER) + " " + extName + " - " + -+ mExt.getExtensionId().toString() + "\n"); -+ -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_VALUE) + "\n"); -+ sb.append(pp.toHexString(mExt.getExtensionValue(), mIndentSize + 8, 16)); -+ -+ return sb.toString(); -+ -+ } -+ -+ /*========================================================== -+ * Private methods -+ *==========================================================*/ -+ -+ private String getNSCCommentExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NSC_COMMENT) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + ((NSCCommentExtension) mExt).toPrint(mIndentSize) + "\n"); -+ return sb.toString(); -+ } -+ -+ private String getNameConstraintsExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NAME_CONSTRAINTS) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ sb.append(pp.indent(mIndentSize + 4) + ((NameConstraintsExtension) mExt).toPrint(mIndentSize + 4)); -+ -+ return sb.toString(); -+ } -+ -+ private String getOCSPNoCheckExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_OCSP_NOCHECK) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ return sb.toString(); -+ } -+ -+ private String getSubjectInfoAccessExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_SIA) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_ACCESS_DESC) + "\n"); -+ SubjectInfoAccessExtension aia = (SubjectInfoAccessExtension) mExt; -+ -+ for (int i = 0; i < aia.numberOfAccessDescription(); i++) { -+ AccessDescription ad = aia.getAccessDescription(i); -+ ObjectIdentifier method = ad.getMethod(); -+ -+ if (method.equals(SubjectInfoAccessExtension.METHOD_OCSP)) { -+ sb.append(pp.indent(mIndentSize + 8) + "Method #" + i + ": " + -+ "ocsp" + "\n"); -+ } else { -+ sb.append(pp.indent(mIndentSize + 8) + "Method #" + i + ": " + -+ method.toString() + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 8) + "Location #" + i + ": " + -+ ad.getLocation().toString() + "\n"); -+ } -+ return sb.toString(); -+ } -+ -+ private String getAuthInfoAccessExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_AIA) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_ACCESS_DESC) + "\n"); -+ AuthInfoAccessExtension aia = (AuthInfoAccessExtension) mExt; -+ -+ for (int i = 0; i < aia.numberOfAccessDescription(); i++) { -+ AccessDescription ad = aia.getAccessDescription(i); -+ ObjectIdentifier method = ad.getMethod(); -+ -+ if (method.equals(AuthInfoAccessExtension.METHOD_OCSP)) { -+ sb.append(pp.indent(mIndentSize + 8) + "Method #" + i + ": " + -+ "ocsp" + "\n"); -+ } else { -+ sb.append(pp.indent(mIndentSize + 8) + "Method #" + i + ": " + -+ method.toString() + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 8) + "Location #" + i + ": " + -+ ad.getLocation().toString() + "\n"); -+ } -+ return sb.toString(); -+ } -+ -+ private String getPresenceServerExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_PRESENCE_SERVER) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ PresenceServerExtension pse = (PresenceServerExtension) mExt; -+ -+ sb.append(pp.indent(mIndentSize + 4) + "Version : " + pse.getVersion() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + "Street Address : " + pse.getStreetAddress() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + "Telephone Number : " + pse.getTelephoneNumber() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + "RFC822 Name : " + pse.getRFC822() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + "ID : " + pse.getID() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + "Host Name : " + pse.getHostName() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + "Port Number : " + pse.getPortNumber() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + "Max Users : " + pse.getMaxUsers() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + "Service Level : " + pse.getServiceLevel() + "\n"); -+ -+ return sb.toString(); -+ } -+ -+ private String getPrivateKeyUsageExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_PRIVATE_KEY_USAGE) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ PrivateKeyUsageExtension usage = (PrivateKeyUsageExtension) mExt; -+ -+ sb.append(pp.indent(mIndentSize + 4) + "Validity:\n"); -+ -+ if (dateFormater == null) { -+ dateFormater = DateFormat.getDateInstance(DateFormat.FULL); -+ } -+ String notBefore = dateFormater.format(usage.getNotBefore()); -+ String notAfter = dateFormater.format(usage.getNotAfter()); -+ -+ sb.append(pp.indent(mIndentSize + 8) + "Not Before: " + notBefore + "\n"); -+ sb.append(pp.indent(mIndentSize + 8) + "Not After: " + notAfter + "\n"); -+ -+ return sb.toString(); -+ } -+ -+ private String getExtendedKeyUsageExtension() { -+ StringBuffer sb = new StringBuffer(); -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_EXTENDED_KEY_USAGE) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_EXTENDED_KEY_USAGE) + "\n"); -+ ExtendedKeyUsageExtension usage = (ExtendedKeyUsageExtension) mExt; -+ Enumeration e = usage.getOIDs(); -+ -+ if (e != null) { -+ while (e.hasMoreElements()) { -+ ObjectIdentifier oid = e.nextElement(); -+ -+ if (oid.equals(ExtendedKeyUsageExtension.OID_OCSP_SIGNING)) { -+ sb.append(pp.indent(mIndentSize + 8) + "OCSPSigning" + "\n"); -+ } else { -+ sb.append(pp.indent(mIndentSize + 8) + oid.toString() + "\n"); -+ } -+ } -+ } -+ return sb.toString(); -+ } -+ -+ /** -+ * String Representation of KeyUsageExtension -+ */ -+ private String getKeyUsage() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_KEY_USAGE) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_KEY_USAGE) + "\n"); -+ KeyUsageExtension usage = (KeyUsageExtension) mExt; -+ -+ if (((Boolean) usage.get(KeyUsageExtension.DIGITAL_SIGNATURE)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.DIGITAL_SIGNATURE) + "\n"); -+ } -+ if (((Boolean) usage.get(KeyUsageExtension.NON_REPUDIATION)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.NON_REPUDIATION) + "\n"); -+ } -+ if (((Boolean) usage.get(KeyUsageExtension.KEY_ENCIPHERMENT)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.KEY_ENCIPHERMENT) + "\n"); -+ } -+ if (((Boolean) usage.get(KeyUsageExtension.DATA_ENCIPHERMENT)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.DATA_ENCIPHERMENT) + "\n"); -+ } -+ if (((Boolean) usage.get(KeyUsageExtension.KEY_AGREEMENT)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.KEY_AGREEMENT) + "\n"); -+ } -+ if (((Boolean) usage.get(KeyUsageExtension.KEY_CERTSIGN)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.KEY_CERTSIGN) + "\n"); -+ } -+ if (((Boolean) usage.get(KeyUsageExtension.CRL_SIGN)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.CRL_SIGN) + "\n"); -+ } -+ if (((Boolean) usage.get(KeyUsageExtension.ENCIPHER_ONLY)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.ENCIPHER_ONLY) + "\n"); -+ } -+ if (((Boolean) usage.get(KeyUsageExtension.DECIPHER_ONLY)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(KeyUsageExtension.DECIPHER_ONLY) + "\n"); -+ } -+ return sb.toString(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return sb.toString(); -+ } -+ -+ } -+ -+ /** -+ * String Representation of NSCertTypeExtension -+ */ -+ private String getCertType() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CERT_TYPE) -+ + "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CERT_USAGE) + "\n"); -+ NSCertTypeExtension type = (NSCertTypeExtension) mExt; -+ -+ if (((Boolean) type.get(NSCertTypeExtension.SSL_CLIENT)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.SSL_CLIENT) + "\n"); -+ } -+ if (((Boolean) type.get(NSCertTypeExtension.SSL_SERVER)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.SSL_SERVER) + "\n"); -+ } -+ if (((Boolean) type.get(NSCertTypeExtension.EMAIL)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.EMAIL) + "\n"); -+ } -+ if (((Boolean) type.get(NSCertTypeExtension.OBJECT_SIGNING)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.OBJECT_SIGNING) + "\n"); -+ } -+ if (((Boolean) type.get(NSCertTypeExtension.SSL_CA)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.SSL_CA) + "\n"); -+ } -+ if (((Boolean) type.get(NSCertTypeExtension.EMAIL_CA)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) + mResource.getString(NSCertTypeExtension.EMAIL_CA) + "\n"); -+ } -+ if (((Boolean) type.get(NSCertTypeExtension.OBJECT_SIGNING_CA)).booleanValue()) { -+ sb.append(pp.indent(mIndentSize + 8) -+ + mResource.getString(NSCertTypeExtension.OBJECT_SIGNING_CA) + "\n"); -+ } -+ return sb.toString(); -+ } catch (CertificateException e) { -+ e.printStackTrace(); -+ return ""; -+ } -+ -+ } -+ -+ /** -+ * String Representation of SubjectKeyIdentifierExtension -+ */ -+ private String getSubjectKeyIdentifier() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_SKI) -+ + "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ SubjectKeyIdentifierExtension id = (SubjectKeyIdentifierExtension) mExt; -+ KeyIdentifier keyId = (KeyIdentifier) id.get(SubjectKeyIdentifierExtension.KEY_ID); -+ -+ if (keyId != null) { -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_KEY_ID) + "\n"); -+ sb.append(pp.toHexString(keyId.getIdentifier(), 24, 16)); -+ } -+ return sb.toString(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return ""; -+ } -+ } -+ -+ /** -+ * String Representation of AuthorityKeyIdentifierExtension -+ */ -+ private String getAuthorityKeyIdentifier() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_AKI) -+ + "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ AuthorityKeyIdentifierExtension id = (AuthorityKeyIdentifierExtension) mExt; -+ KeyIdentifier keyId = (KeyIdentifier) id.get(AuthorityKeyIdentifierExtension.KEY_ID); -+ -+ if (keyId != null) { -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_KEY_ID) + "\n"); -+ sb.append(pp.toHexString(keyId.getIdentifier(), mIndentSize + 8, 16)); -+ // sb.append(pp.toHexString(keyId.getIdentifier(),24,16)); -+ } -+ GeneralNames authNames = (GeneralNames) id.get(AuthorityKeyIdentifierExtension.AUTH_NAME); -+ -+ if (authNames != null) { -+ for (int i = 0; i < authNames.size(); i++) { -+ GeneralName authName = (GeneralName) authNames.elementAt(i); -+ -+ if (authName != null) { -+ sb.append(pp.indent(mIndentSize + 4) -+ + mResource.getString(PrettyPrintResources.TOKEN_AUTH_NAME) + authName.toString() -+ + "\n"); -+ } -+ } -+ } -+ -+ SerialNumber serial = (SerialNumber) id.get(AuthorityKeyIdentifierExtension.SERIAL_NUMBER); -+ -+ if (serial != null) { -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_SERIAL) + -+ "0x" + serial.getNumber().toBigInteger().toString(16).toUpperCase() + "\n"); -+ } -+ return sb.toString(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return ""; -+ } -+ } -+ -+ /** -+ * String Representation of CRLReasonExtension -+ */ -+ private String getCRLReasonExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_REVOCATION_REASON) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ CRLReasonExtension ext = (CRLReasonExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_REASON) + -+ ext.getReason().toString() + "\n"); -+ -+ return sb.toString(); -+ } catch (Exception e) { -+ return ""; -+ } -+ } -+ -+ /** -+ * String Representation of InhibitAnyPolicyExtension -+ */ -+ private String getInhibitAnyPolicyExtension() { -+ StringBuffer sb = new StringBuffer(); -+ sb.append(pp.indent(mIndentSize) + -+ mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_INHIBIT_ANY_POLICY_EXT) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ InhibitAnyPolicyExtension ext = (InhibitAnyPolicyExtension) mExt; -+ if (mExt.isCritical()) -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ else -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_SKIP_CERTS)); -+ BigInt num = ext.getSkipCerts(); -+ sb.append("" + num.toInt() + "\n"); -+ return sb.toString(); -+ } -+ -+ /** -+ * String Representation of BasicConstraintsExtension -+ */ -+ private String getBasicConstraintsExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_BASIC_CONSTRAINTS) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ BasicConstraintsExtension ext = (BasicConstraintsExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_IS_CA)); -+ boolean isCA = ((Boolean) ext.get(BasicConstraintsExtension.IS_CA)).booleanValue(); -+ -+ if (isCA) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ Integer pathLength = (Integer) ext.get(BasicConstraintsExtension.PATH_LEN); -+ -+ if (pathLength != null) { -+ if (pathLength.longValue() >= 0) { -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN) + -+ pathLength.toString() + "\n"); -+ } else if (pathLength.longValue() == -1 || pathLength.longValue() == -2) { -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN) + -+ mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN_UNLIMITED) + "\n"); -+ } else { -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN) + -+ mResource.getString(PrettyPrintResources.TOKEN_PATH_LEN_INVALID) + -+ " (" + pathLength.toString() + ")\n"); -+ } -+ } -+ -+ return sb.toString(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return ""; -+ } -+ } -+ -+ /** -+ * String Representation of CRLNumberExtension -+ */ -+ private String getCRLNumberExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CRL_NUMBER) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ CRLNumberExtension ext = (CRLNumberExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ BigInteger crlNumber = (BigInteger) ext.get(CRLNumberExtension.NUMBER); -+ -+ if (crlNumber != null) { -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_NUMBER) + -+ crlNumber.toString() + "\n"); -+ } -+ -+ return sb.toString(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return ""; -+ } -+ } -+ -+ /** -+ * String Representation of DeltaCRLIndicatorExtension -+ */ -+ private String getDeltaCRLIndicatorExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_DELTA_CRL_INDICATOR) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ DeltaCRLIndicatorExtension ext = (DeltaCRLIndicatorExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ BigInteger crlNumber = (BigInteger) ext.get(DeltaCRLIndicatorExtension.NUMBER); -+ -+ if (crlNumber != null) { -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_BASE_CRL_NUMBER) + -+ crlNumber.toString() + "\n"); -+ } -+ -+ return sb.toString(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return ""; -+ } -+ } -+ -+ /** -+ * String Representation of IssuerAlternativeName Extension -+ */ -+ private String getIssuerAlternativeNameExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_ISSUER_ALT_NAME) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ IssuerAlternativeNameExtension ext = (IssuerAlternativeNameExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ GeneralNames issuerNames = (GeneralNames) ext.get(IssuerAlternativeNameExtension.ISSUER_NAME); -+ -+ if (issuerNames != null) { -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_ISSUER_NAMES) + "\n"); -+ for (int i = 0; i < issuerNames.size(); i++) { -+ GeneralName issuerName = (GeneralName) issuerNames.elementAt(i); -+ -+ if (issuerName != null) { -+ String nameType = ""; -+ -+ if (issuerName.getType() == GeneralNameInterface.NAME_DIRECTORY) -+ nameType = "DirectoryName: "; -+ sb.append(pp.indent(mIndentSize + 8) + nameType + issuerName.toString() + "\n"); -+ } -+ } -+ } -+ -+ return sb.toString(); -+ } catch (IOException e) { -+ return ""; -+ } -+ } -+ -+ /** -+ * String Representation of SubjectAlternativeName Extension -+ */ -+ private String getSubjectAlternativeNameExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_SUBJECT_ALT_NAME) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ SubjectAlternativeNameExtension ext = (SubjectAlternativeNameExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ GeneralNames subjectNames = (GeneralNames) ext.get(SubjectAlternativeNameExtension.SUBJECT_NAME); -+ -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_VALUE) + "\n"); -+ for (int i = 0; i < subjectNames.size(); i++) { -+ GeneralName subjectName = (GeneralName) subjectNames.elementAt(i); -+ -+ if (subjectName != null) { -+ String nameType = ""; -+ -+ if (subjectName.getType() == GeneralNameInterface.NAME_DIRECTORY) -+ nameType = "DirectoryName: "; -+ sb.append(pp.indent(mIndentSize + 8) + nameType + subjectName.toString() + "\n"); -+ } -+ } -+ -+ return sb.toString(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return ""; -+ } -+ } -+ -+ /** -+ * String Representation of CertificateScopeOfUse Extension -+ */ -+ private String getCertificateScopeOfUseExtension() { -+ StringBuffer sb = new StringBuffer(); -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CERT_SCOPE_OF_USE) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ CertificateScopeOfUseExtension ext = (CertificateScopeOfUseExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ Vector entries = ext.getCertificateScopeEntries(); -+ -+ if (entries != null) { -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_SCOPE_OF_USE) + "\n"); -+ for (int i = 0; i < entries.size(); i++) { -+ CertificateScopeEntry se = entries.elementAt(i); -+ GeneralName gn = se.getGeneralName(); -+ -+ if (gn != null) { -+ String nameType = ""; -+ -+ if (gn.getType() == GeneralNameInterface.NAME_DIRECTORY) -+ nameType = "DirectoryName: "; -+ sb.append(pp.indent(mIndentSize + 8) + nameType + gn.toString() + "\n"); -+ } -+ BigInt port = se.getPort(); -+ -+ if (port != null) { -+ sb.append(pp.indent(mIndentSize + 8) + PrettyPrintResources.TOKEN_PORT + -+ port.toBigInteger().toString() + "\n"); -+ } -+ } -+ } -+ return sb.toString(); -+ } -+ -+ /** -+ * String Representation of FreshestCRLExtension -+ */ -+ private String getFreshestCRLExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ // -+ // Generic stuff: name, OID, criticality -+ // -+ sb.append(pp.indent(mIndentSize) + -+ mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_FRESHEST_CRL_EXT) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ // -+ // Now the CRLDP-specific stuff -+ // -+ FreshestCRLExtension ext = (FreshestCRLExtension) mExt; -+ -+ int numPoints = ext.getNumPoints(); -+ -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRLDP_NUMPOINTS) -+ + numPoints + "\n"); -+ -+ for (int i = 0; i < numPoints; i++) { -+ -+ // -+ // print one individual CRL distribution point -+ // -+ -+ int idt; -+ -+ idt = mIndentSize + 4; // reset each time through loop -+ boolean isEmpty = true; -+ -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_POINTN) + -+ i + "\n"); -+ -+ CRLDistributionPoint pt = ext.getPointAt(i); -+ -+ idt += 4; // further indent rest of information -+ -+ if (pt.getFullName() != null) { -+ isEmpty = false; -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_DISTPOINT) -+ + pt.getFullName() + "\n"); -+ } -+ -+ if (pt.getRelativeName() != null) { -+ isEmpty = false; -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_DISTPOINT) -+ + pt.getRelativeName() + "\n"); -+ } -+ -+ if (pt.getReasons() != null) { -+ isEmpty = false; -+ byte[] reasonBits = pt.getReasons().toByteArray(); -+ String reasonList = reasonBitsToReasonList(reasonBits); -+ -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_REASONS) -+ + reasonList + "\n"); -+ } -+ -+ if (pt.getCRLIssuer() != null) { -+ isEmpty = false; -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_CRLISSUER) -+ + pt.getCRLIssuer() + "\n"); -+ } -+ -+ if (isEmpty) { -+ sb.append(pp.indent(idt) + "empty\n"); -+ } -+ -+ } -+ -+ return sb.toString(); -+ } -+ -+ /** -+ * String Representation of CRLDistributionPointsExtension -+ */ -+ private String getCRLDistributionPointsExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ // -+ // Generic stuff: name, OID, criticality -+ // -+ sb.append(pp.indent(mIndentSize) + -+ mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_CRL_DP_EXT) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ // -+ // Now the CRLDP-specific stuff -+ // -+ CRLDistributionPointsExtension ext = -+ (CRLDistributionPointsExtension) mExt; -+ -+ int numPoints = ext.getNumPoints(); -+ -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRLDP_NUMPOINTS) -+ + numPoints + "\n"); -+ -+ for (int i = 0; i < numPoints; i++) { -+ -+ // -+ // print one individual CRL distribution point -+ // -+ -+ int idt; -+ -+ idt = mIndentSize + 4; // reset each time through loop -+ boolean isEmpty = true; -+ -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_POINTN) + -+ i + "\n"); -+ -+ CRLDistributionPoint pt = ext.getPointAt(i); -+ -+ idt += 4; // further indent rest of information -+ -+ if (pt.getFullName() != null) { -+ isEmpty = false; -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_DISTPOINT) -+ + pt.getFullName() + "\n"); -+ } -+ -+ if (pt.getRelativeName() != null) { -+ isEmpty = false; -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_DISTPOINT) -+ + pt.getRelativeName() + "\n"); -+ } -+ -+ if (pt.getReasons() != null) { -+ isEmpty = false; -+ byte[] reasonBits = pt.getReasons().toByteArray(); -+ String reasonList = reasonBitsToReasonList(reasonBits); -+ -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_REASONS) -+ + reasonList + "\n"); -+ } -+ -+ if (pt.getCRLIssuer() != null) { -+ isEmpty = false; -+ sb.append(pp.indent(idt) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRLDP_CRLISSUER) -+ + pt.getCRLIssuer() + "\n"); -+ } -+ -+ if (isEmpty) { -+ sb.append(pp.indent(idt) + "empty\n"); -+ } -+ -+ } -+ -+ return sb.toString(); -+ } -+ -+ private static String reasonBitsToReasonList(byte[] reasonBits) { -+ -+ Reason[] reasons = Reason.bitArrayToReasonArray(reasonBits); -+ -+ if (reasons.length == 0) { -+ return ""; -+ } else { -+ StringBuffer buf = new StringBuffer(); -+ -+ buf.append(reasons[0].getName()); -+ for (int i = 1; i < reasons.length; i++) { -+ buf.append(", "); -+ buf.append(reasons[i].getName()); -+ } -+ return buf.toString(); -+ } -+ } -+ -+ /** -+ * String Representation of IssuerAlternativeName Extension -+ */ -+ private String getIssuingDistributionPointExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString(PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_ISSUING_DIST_POINT) + "- " + -+ mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ IssuingDistributionPointExtension ext = (IssuingDistributionPointExtension) mExt; -+ IssuingDistributionPoint issuingDistributionPoint = ext.getIssuingDistributionPoint(); -+ -+ if (issuingDistributionPoint != null) { -+ GeneralNames fullNames = issuingDistributionPoint.getFullName(); -+ RDN relativeName = issuingDistributionPoint.getRelativeName(); -+ -+ if (fullNames != null || relativeName != null) { -+ sb.append(pp.indent(mIndentSize + 4) -+ + mResource.getString(PrettyPrintResources.TOKEN_DIST_POINT_NAME) + "\n"); -+ if (fullNames != null) { -+ sb.append(pp.indent(mIndentSize + 8) -+ + mResource.getString(PrettyPrintResources.TOKEN_FULL_NAME) + "\n"); -+ for (int i = 0; i < fullNames.size(); i++) { -+ GeneralName fullName = (GeneralName) fullNames.elementAt(i); -+ -+ if (fullName != null) { -+ sb.append(pp.indent(mIndentSize + 12) + fullName.toString() + "\n"); -+ } -+ } -+ } -+ if (relativeName != null) { -+ sb.append(pp.indent(mIndentSize + 8) -+ + mResource.getString(PrettyPrintResources.TOKEN_RELATIVE_NAME) + -+ relativeName.toString() + "\n"); -+ } -+ } -+ -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_ONLY_USER_CERTS)); -+ if (issuingDistributionPoint.getOnlyContainsUserCerts()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_ONLY_CA_CERTS)); -+ if (issuingDistributionPoint.getOnlyContainsCACerts()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ BitArray onlySomeReasons = issuingDistributionPoint.getOnlySomeReasons(); -+ -+ if (onlySomeReasons != null) { -+ sb.append(pp.indent(mIndentSize + 4) -+ + mResource.getString(PrettyPrintResources.TOKEN_ONLY_SOME_REASONS)); -+ sb.append("0x" + pp.toHexString(onlySomeReasons.toByteArray())); -+ } -+ -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString(PrettyPrintResources.TOKEN_INDIRECT_CRL)); -+ if (issuingDistributionPoint.getIndirectCRL()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ } -+ -+ return sb.toString(); -+ } -+ -+ /** -+ * String Representation of InvalidityDateExtension -+ */ -+ private String getInvalidityDateExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_INVALIDITY_DATE) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ InvalidityDateExtension ext = (InvalidityDateExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_DATE_OF_INVALIDITY) + -+ ext.getInvalidityDate().toString() + "\n"); -+ return sb.toString(); -+ } -+ -+ /** -+ * String Representation of CertificateIssuerExtension -+ */ -+ private String getCertificateIssuerExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CERTIFICATE_ISSUER) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ CertificateIssuerExtension ext = (CertificateIssuerExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ GeneralNames issuerNames = (GeneralNames) ext.get( -+ CertificateIssuerExtension.CERTIFICATE_ISSUER); -+ -+ if (issuerNames != null) { -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_ISSUER_NAMES) + "\n"); -+ for (int i = 0; i < issuerNames.size(); i++) { -+ GeneralName issuerName = (GeneralName) issuerNames.elementAt(i); -+ -+ if (issuerName != null) { -+ String nameType = ""; -+ -+ if (issuerName.getType() == GeneralNameInterface.NAME_DIRECTORY) -+ nameType = "DirectoryName: "; -+ sb.append(pp.indent(mIndentSize + 8) + nameType + issuerName.toString() + "\n"); -+ } -+ } -+ } -+ -+ return sb.toString(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return ""; -+ } -+ } -+ -+ /** -+ * String Representation of HoldInstructionExtension -+ */ -+ private String getHoldInstructionExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_HOLD_INSTRUCTION) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ HoldInstructionExtension ext = (HoldInstructionExtension) mExt; -+ -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_HOLD_INSTRUCTION_CODE) + -+ ext.getHoldInstructionCodeDescription() + "\n"); -+ return sb.toString(); -+ } -+ -+ /** -+ * String Representation of PolicyConstraintsExtension -+ */ -+ private String getPolicyConstraintsExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append( -+ mResource.getString( -+ PrettyPrintResources.TOKEN_POLICY_CONSTRAINTS) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ PolicyConstraintsExtension ext = (PolicyConstraintsExtension) mExt; -+ int require = ext.getRequireExplicitMapping(); -+ int inhibit = ext.getInhibitPolicyMapping(); -+ -+ sb.append( -+ pp.indent(mIndentSize + 4) + -+ mResource.getString( -+ PrettyPrintResources.TOKEN_REQUIRE_EXPLICIT_POLICY) + -+ ((require == -1) ? -+ mResource.getString(PrettyPrintResources.TOKEN_NOT_SET) : -+ String.valueOf(require)) + "\n"); -+ sb.append( -+ pp.indent(mIndentSize + 4) + -+ mResource.getString( -+ PrettyPrintResources.TOKEN_INHIBIT_POLICY_MAPPING) + -+ ((inhibit == -1) ? -+ mResource.getString(PrettyPrintResources.TOKEN_NOT_SET) : -+ String.valueOf(inhibit)) + "\n"); -+ return sb.toString(); -+ } -+ -+ /** -+ * String Representation of PolicyMappingsExtension -+ */ -+ private String getPolicyMappingsExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_POLICY_MAPPINGS) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ PolicyMappingsExtension ext = (PolicyMappingsExtension) mExt; -+ Enumeration maps = ext.getMappings(); -+ -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_MAPPINGS)); -+ if (maps == null || !maps.hasMoreElements()) { -+ sb.append( -+ mResource.getString(PrettyPrintResources.TOKEN_NONE) + "\n"); -+ } else { -+ sb.append("\n"); -+ for (int i = 0; maps.hasMoreElements(); i++) { -+ sb.append(pp.indent(mIndentSize + 8) + -+ mResource.getString( -+ PrettyPrintResources.TOKEN_MAP) + i + ":" + "\n"); -+ CertificatePolicyMap m = -+ maps.nextElement(); -+ -+ sb.append(pp.indent(mIndentSize + 12) + -+ mResource.getString( -+ PrettyPrintResources.TOKEN_ISSUER_DOMAIN_POLICY) + -+ m.getIssuerIdentifier().getIdentifier().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 12) + -+ mResource.getString( -+ PrettyPrintResources.TOKEN_SUBJECT_DOMAIN_POLICY) + -+ m.getSubjectIdentifier().getIdentifier().toString() + "\n"); -+ } -+ } -+ return sb.toString(); -+ } -+ -+ /** -+ * String Representation of SubjectDirAttributesExtension -+ */ -+ private String getSubjectDirAttributesExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_SUBJECT_DIR_ATTR) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ -+ SubjectDirAttributesExtension ext = -+ (SubjectDirAttributesExtension) mExt; -+ -+ sb.append(pp.indent(mIndentSize + 4) + -+ mResource.getString(PrettyPrintResources.TOKEN_ATTRIBUTES)); -+ Enumeration attrs = ext.getAttributesList(); -+ -+ if (attrs == null || !attrs.hasMoreElements()) { -+ sb.append( -+ mResource.getString(PrettyPrintResources.TOKEN_NONE) + "\n"); -+ } else { -+ sb.append("\n"); -+ for (int j = 0; attrs.hasMoreElements(); j++) { -+ Attribute attr = attrs.nextElement(); -+ -+ sb.append(pp.indent(mIndentSize + 8) + -+ mResource.getString( -+ PrettyPrintResources.TOKEN_ATTRIBUTE) + j + ":" + "\n"); -+ sb.append(pp.indent(mIndentSize + 12) + -+ mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER) + -+ attr.getOid().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 12) + -+ mResource.getString( -+ PrettyPrintResources.TOKEN_VALUES)); -+ Enumeration values = attr.getValues(); -+ -+ if (values == null || !values.hasMoreElements()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NONE) + "\n"); -+ } else { -+ for (int k = 0; values.hasMoreElements(); k++) { -+ String v = values.nextElement(); -+ -+ if (k != 0) -+ sb.append(","); -+ sb.append(v); -+ } -+ } -+ sb.append("\n"); -+ } -+ } -+ return sb.toString(); -+ } catch (Throwable e) { -+ return ""; -+ } -+ } -+ -+ private String getCertificatePoliciesExtension() { -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ sb.append(pp.indent(mIndentSize) + mResource.getString( -+ PrettyPrintResources.TOKEN_IDENTIFIER)); -+ sb.append(mResource.getString(PrettyPrintResources.TOKEN_CERT_POLICIES) + -+ "- " + mExt.getExtensionId().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CRITICAL)); -+ if (mExt.isCritical()) { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_YES) + "\n"); -+ } else { -+ sb.append(mResource.getString( -+ PrettyPrintResources.TOKEN_NO) + "\n"); -+ } -+ sb.append(pp.indent(mIndentSize + 4) + mResource.getString( -+ PrettyPrintResources.TOKEN_CERT_POLICIES) + "\n"); -+ CertificatePoliciesExtension cp = (CertificatePoliciesExtension) mExt; -+ @SuppressWarnings("unchecked") -+ Vector cpv = (Vector) cp.get("infos"); -+ Enumeration e = cpv.elements(); -+ -+ if (e != null) { -+ while (e.hasMoreElements()) { -+ CertificatePolicyInfo cpi = e.nextElement(); -+ -+ sb.append(pp.indent(mIndentSize + 8) -+ + "Policy Identifier: " + cpi.getPolicyIdentifier().getIdentifier().toString() + "\n"); -+ PolicyQualifiers cpq = cpi.getPolicyQualifiers(); -+ if (cpq != null) { -+ for (int i = 0; i < cpq.size(); i++) { -+ PolicyQualifierInfo pq = cpq.getInfoAt(i); -+ Qualifier q = pq.getQualifier(); -+ if (q instanceof CPSuri) { -+ sb.append(pp.indent(mIndentSize + 12) -+ + "Policy Qualifier Identifier: CPS Pointer Qualifier - " -+ + pq.getId() + "\n"); -+ sb.append(pp.indent(mIndentSize + 12) -+ + "Policy Qualifier Data: " + ((CPSuri) q).getURI() + "\n"); -+ } else if (q instanceof UserNotice) { -+ sb.append(pp.indent(mIndentSize + 12) -+ + "Policy Qualifier Identifier: CPS User Notice Qualifier - " -+ + pq.getId() + "\n"); -+ NoticeReference nref = ((UserNotice) q).getNoticeReference(); -+ DisplayText dt = ((UserNotice) q).getDisplayText(); -+ sb.append(pp.indent(mIndentSize + 12) + "Policy Qualifier Data: \n"); -+ if (nref != null) { -+ sb.append(pp.indent(mIndentSize + 16) -+ + "Organization: " + nref.getOrganization().toString() + "\n"); -+ sb.append(pp.indent(mIndentSize + 16) + "Notice Numbers: "); -+ int[] nums = nref.getNumbers(); -+ for (int k = 0; k < nums.length; k++) { -+ if (k != 0) { -+ sb.append(","); -+ sb.append(nums[k]); -+ } else { -+ sb.append(nums[k]); -+ } -+ } -+ sb.append("\n"); -+ } -+ if (dt != null) { -+ sb.append(pp.indent(mIndentSize + 16) + "Explicit Text: " + dt.toString() + "\n"); -+ } -+ } -+ } -+ } -+ } -+ } -+ return sb.toString(); -+ } catch (IOException e) { -+ return sb.toString(); -+ } -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/util/IA5Charset.java b/org/mozilla/jss/netscape/security/util/IA5Charset.java -new file mode 100644 -index 00000000..03533661 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/IA5Charset.java -@@ -0,0 +1,24 @@ -+package org.mozilla.jss.netscape.security.util; -+ -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetDecoder; -+import java.nio.charset.CharsetEncoder; -+ -+public class IA5Charset extends Charset { -+ -+ public IA5Charset() { -+ super("ASN.1-IA5", null); -+ } -+ -+ public boolean contains(Charset cs) { -+ return false; -+ } -+ -+ public CharsetDecoder newDecoder() { -+ return new IA5CharsetDecoder(this); -+ } -+ -+ public CharsetEncoder newEncoder() { -+ return new IA5CharsetEncoder(this); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/IA5CharsetDecoder.java b/org/mozilla/jss/netscape/security/util/IA5CharsetDecoder.java -new file mode 100644 -index 00000000..8b9a05e8 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/IA5CharsetDecoder.java -@@ -0,0 +1,62 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetDecoder; -+import java.nio.charset.CoderResult; -+import java.nio.charset.CodingErrorAction; -+ -+/** -+ * Converts bytes in ASN.1 IA5String character set to IA5String characters. -+ * -+ * @author Lily Hsiao -+ * @author Slava Galperin -+ */ -+ -+public class IA5CharsetDecoder extends CharsetDecoder { -+ -+ public IA5CharsetDecoder(Charset cs) { -+ super(cs, 1, 1); -+ } -+ -+ protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { -+ -+ while (true) { -+ -+ if (in.remaining() < 1) -+ return CoderResult.UNDERFLOW; -+ -+ in.mark(); -+ byte b = in.get(); -+ -+ if (CodingErrorAction.REPORT == unmappableCharacterAction() && (b & 0x80) != 0) { -+ return CoderResult.unmappableForLength(1); -+ } -+ -+ if (out.remaining() < 1) { -+ in.reset(); -+ return CoderResult.OVERFLOW; -+ } -+ -+ out.put((char) (b & 0x7f)); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/IA5CharsetEncoder.java b/org/mozilla/jss/netscape/security/util/IA5CharsetEncoder.java -new file mode 100644 -index 00000000..3651ca85 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/IA5CharsetEncoder.java -@@ -0,0 +1,69 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetEncoder; -+import java.nio.charset.CoderResult; -+import java.nio.charset.CodingErrorAction; -+ -+/** -+ * Converts characters in ASN.1 IA5String character set to IA5String bytes. -+ * -+ * @author Lily Hsiao -+ * @author Slava Galperin -+ */ -+ -+public class IA5CharsetEncoder extends CharsetEncoder { -+ -+ public IA5CharsetEncoder(Charset cs) { -+ super(cs, 1, 1); -+ } -+ -+ /* -+ * Converts an array of Unicode characters into an array of IA5String -+ * bytes and returns the conversion result. -+ * @param in input character buffer to convert. -+ * @param out byte buffer to store output. -+ * @return encoding result. -+ */ -+ protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { -+ -+ while (true) { -+ -+ if (in.remaining() < 1) -+ return CoderResult.UNDERFLOW; -+ -+ in.mark(); -+ char c = in.get(); -+ -+ if (CodingErrorAction.REPORT == unmappableCharacterAction() && (c & 0xFF80) != 0) { -+ return CoderResult.unmappableForLength(1); -+ } -+ -+ if (out.remaining() < 1) { -+ in.reset(); -+ return CoderResult.OVERFLOW; -+ } -+ -+ out.put((byte) (c & 0x7f)); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/Makefile b/org/mozilla/jss/netscape/security/util/Makefile -new file mode 100644 -index 00000000..8fd7054b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/Makefile -@@ -0,0 +1,45 @@ -+#! gmake -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+####################################################################### -+# (1) Include initial platform-independent assignments (MANDATORY). # -+####################################################################### -+ -+include manifest.mn -+ -+####################################################################### -+# (2) Include "global" configuration information. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/config.mk -+ -+####################################################################### -+# (3) Include "component" configuration information. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (4) Include "local" platform-dependent assignments (OPTIONAL). # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (5) Execute "global" rules. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/rules.mk -+ -+####################################################################### -+# (6) Execute "component" rules. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -diff --git a/org/mozilla/jss/netscape/security/util/ObjectIdentifier.java b/org/mozilla/jss/netscape/security/util/ObjectIdentifier.java -new file mode 100644 -index 00000000..9b34f8b6 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/ObjectIdentifier.java -@@ -0,0 +1,533 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.IOException; -+import java.io.Serializable; -+import java.math.BigInteger; -+import java.util.Hashtable; -+import java.util.StringTokenizer; -+ -+/** -+ * Represent an ISO Object Identifier. -+ * -+ *

-+ * Object Identifiers are arbitrary length hierarchical identifiers. The individual components are numbers, and they -+ * define paths from the root of an ISO-managed identifier space. You will sometimes see a string name used instead of -+ * (or in addition to) the numerical id. These are synonyms for the numerical IDs, but are not widely used since most -+ * sites do not know all the requisite strings, while all sites can parse the numeric forms. -+ * -+ *

-+ * So for example, JavaSoft has the sole authority to assign the meaning to identifiers below the 1.3.6.1.4.42.2.17 node -+ * in the hierarchy, and other organizations can easily acquire the ability to assign such unique identifiers. -+ * -+ * @version 1.23 -+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+final public class ObjectIdentifier implements Serializable { -+ /** use serialVersionUID from JDK 1.1. for interoperability */ -+ private static final long serialVersionUID = 8697030238860181294L; -+ -+ /** -+ * Constructs an object identifier from a string. This string -+ * should be of the form 1.23.34.45.56 etc. -+ */ -+ public ObjectIdentifier(String oid) { -+ if (oid == null) -+ return; -+ -+ int ch = '.'; -+ int start = 0; -+ int end = 0; -+ -+ // Calculate length of oid -+ componentLen = 0; -+ while ((end = oid.indexOf(ch, start)) != -1) { -+ start = end + 1; -+ componentLen += 1; -+ } -+ componentLen += 1; -+ components = new BigInteger[componentLen]; -+ -+ start = 0; -+ int i = 0; -+ String comp = null; -+ while ((end = oid.indexOf(ch, start)) != -1) { -+ comp = oid.substring(start, end); -+ components[i++] = new BigInteger(comp); -+ start = end + 1; -+ } -+ comp = oid.substring(start); -+ components[i] = new BigInteger(comp); -+ } -+ -+ /** -+ * Constructs an object ID from an array of integers. This -+ * is used to construct constant object IDs. -+ */ -+ public ObjectIdentifier(int values[]) { -+ try { -+ componentLen = values.length; -+ BigInteger[] tmp = new BigInteger[componentLen]; -+ -+ for (int i = 0; i < componentLen; i++) { -+ tmp[i] = BigInteger.valueOf(values[i]); -+ } -+ -+ components = tmp.clone(); -+ } catch (Throwable t) { -+ System.out.println("X509.ObjectIdentifier(), no cloning!"); -+ } -+ } -+ -+ public ObjectIdentifier(BigInteger values[]) { -+ try { -+ componentLen = values.length; -+ -+ componentLen = values.length; -+ BigInteger[] tmp = new BigInteger[componentLen]; -+ -+ for (int i = 0; i < componentLen; i++) { -+ tmp[i] = new BigInteger(values[i].toString()); -+ } -+ -+ components = tmp.clone(); -+ -+ } catch(Throwable t) { -+ System.out.println("X509.ObjectIdentifier(), no cloning!"); -+ } -+ } -+ -+ /** -+ * Constructs an object ID from an array of longs This -+ * is used to construct constant object IDs. -+ */ -+ public ObjectIdentifier(long values[]) { -+ try { -+ componentLen = values.length; -+ BigInteger[] tmp = new BigInteger[componentLen]; -+ -+ for (int i = 0; i < componentLen; i++) { -+ tmp[i] = BigInteger.valueOf(values[i]); -+ } -+ -+ components = tmp.clone(); -+ } catch (Throwable t) { -+ System.out.println("X509.ObjectIdentifier(), no cloning!"); -+ } -+ } -+ -+ -+ /** -+ * Constructs an object ID from an ASN.1 encoded input stream. -+ * The encoding of the ID in the stream uses "DER", a BER/1 subset. -+ * In this case, that means a triple { typeId, length, data }. -+ * -+ *

-+ * NOTE: When an exception is thrown, the input stream has not been returned to its "initial" -+ * state. -+ * -+ * @param in DER-encoded data holding an object ID -+ * @exception IOException indicates a decoding error -+ */ -+ public ObjectIdentifier(DerInputStream in) -+ throws IOException { -+ byte type_id; -+ int bufferEnd; -+ -+ /* -+ * Object IDs are a "universal" type, and their tag needs only -+ * one byte of encoding. Verify that the tag of this datum -+ * is that of an object ID. -+ * -+ * Then get and check the length of the ID's encoding. We set -+ * up so that we can use in.available() to check for the end of -+ * this value in the data stream. -+ */ -+ type_id = (byte) in.getByte(); -+ if (type_id != DerValue.tag_ObjectId) -+ throw new IOException( -+ "X509.ObjectIdentifier() -- data isn't an object ID" -+ + " (tag = " + type_id + ")"); -+ -+ bufferEnd = in.available() - in.getLength() - 1; -+ if (bufferEnd < 0) -+ throw new IOException( -+ "X509.ObjectIdentifier() -- not enough data"); -+ -+ initFromEncoding(in, bufferEnd); -+ } -+ -+ /* -+ * Build the OID from the rest of a DER input buffer; the tag -+ * and length have been removed/verified -+ */ -+ ObjectIdentifier(DerInputBuffer buf) throws IOException { -+ initFromEncoding(new DerInputStream(buf), 0); -+ } -+ -+ -+ -+ /* -+ * Helper function -- get the OID from a stream, after tag and -+ * length are verified. -+ */ -+ private void initFromEncoding(DerInputStream in, int bufferEnd) -+ throws IOException { -+ -+ /* -+ * Now get the components ("sub IDs") one at a time. We fill a -+ * temporary buffer, resizing it as needed. -+ */ -+ BigInteger component; -+ boolean first_subid = true; -+ -+ for (components = new BigInteger[allocationQuantum], componentLen = 0; in.available() > bufferEnd;) { -+ component = getComponentBigInt(in); -+ -+ if (first_subid) { -+ long X, Y; -+ -+ /* -+ * The ISO root has three children (0, 1, 2) and those nodes -+ * aren't allowed to assign IDs larger than 39. These rules -+ * are memorialized by some special casing in the BER encoding -+ * of object IDs ... or maybe it's vice versa. -+ * -+ * NOTE: the allocation quantum is large enough that we know -+ * we don't have to reallocate here! -+ */ -+ if (component.intValue() < 40) -+ X = 0; -+ else if (component.intValue() < 80) -+ X = 1; -+ else -+ X = 2; -+ Y = component.intValue() - (X * 40); -+ -+ components[0] = BigInteger.valueOf(X); -+ components[1] = BigInteger.valueOf(Y); -+ componentLen = 2; -+ -+ first_subid = false; -+ -+ } else { -+ -+ /* -+ * Other components are encoded less exotically. The only -+ * potential trouble is the need to grow the array. -+ */ -+ if (componentLen >= components.length) { -+ BigInteger tmp_components[]; -+ -+ tmp_components = new BigInteger[components.length -+ + allocationQuantum]; -+ System.arraycopy(components, 0, tmp_components, 0, -+ components.length); -+ components = tmp_components; -+ } -+ components[componentLen++] = component; -+ } -+ } -+ -+ /* -+ * Final sanity check -- if we didn't use exactly the number of bytes -+ * specified, something's quite wrong. -+ */ -+ if (in.available() != bufferEnd) { -+ throw new IOException( -+ "X509.ObjectIdentifier() -- malformed input data"); -+ } -+ } -+ -+ /* -+ * n.b. the only public interface is DerOutputStream.putOID() -+ */ -+ void encode(DerOutputStream out) throws IOException { -+ DerOutputStream bytes = new DerOutputStream(); -+ int i; -+ -+ /* We can use the int here because we know we are dealing -+ with small numbers for the first byte -+ */ -+ bytes.write((components[0].intValue() * 40) + components[1].intValue()); -+ for (i = 2; i < componentLen; i++) -+ putComponentBigInt(bytes, components[i]); -+ -+ /* -+ * Now that we've constructed the component, encode -+ * it in the stream we were given. -+ */ -+ out.write(DerValue.tag_ObjectId, bytes); -+ } -+ -+ /* -+ * Tricky OID component parsing technique ... note that one bit -+ * per octet is lost, this returns at most 28 bits of component. -+ * Also, notice this parses in big-endian format. -+ */ -+ private static BigInteger getComponentBigInt(DerInputStream in) -+ throws IOException { -+ -+ BigInteger retval = BigInteger.valueOf(0); -+ int tmp; -+ -+ while (true) { -+ retval = retval.shiftLeft(7); -+ tmp = in.getByte(); -+ retval = retval.or(BigInteger.valueOf(tmp & 0x07f)); -+ if ((tmp & 0x080) == 0) -+ return retval; -+ } -+ -+ } -+ -+ /* -+ * Reverse of the above routine. Notice it needs to emit in -+ * big-endian form, so it buffers the output until it's ready. -+ * (Minimum length encoding is a DER requirement.) -+ */ -+ private static void putComponentBigInt(DerOutputStream out, BigInteger val) -+ throws IOException { -+ int i; -+ int blockSize = 100; -+ byte buf[] = new byte[blockSize]; -+ -+ BigInteger bigInt7f = BigInteger.valueOf(0x7f); -+ -+ BigInteger cur = new BigInteger(val.toString()); -+ for (i = 0;; i++) { -+ buf[i] = (cur.and(bigInt7f).byteValue()); -+ cur = cur.shiftRight(7); -+ if (cur.compareTo(BigInteger.ZERO) == 0 ) -+ break; -+ } -+ for (; i > 0; --i) -+ out.write(buf[i] | 0x080); -+ out.write(buf[0]); -+ } -+ -+ // XXX this API should probably facilitate the JDK sort utility -+ -+ /** -+ * Compares this identifier with another, for sorting purposes. -+ * An identifier does not precede itself. -+ * -+ * @param other identifer that may precede this one. -+ * @return true iff other precedes this one -+ * in a particular sorting order. -+ */ -+ public boolean precedes(ObjectIdentifier other) { -+ int i; -+ -+ // shorter IDs go first -+ if (other == this || componentLen < other.componentLen) -+ return false; -+ if (other.componentLen < componentLen) -+ return true; -+ -+ // for each component, the lesser component goes first -+ for (i = 0; i < componentLen; i++) { -+ if (other.components[i].compareTo(components[i]) > 0) -+ return true; -+ } -+ -+ // identical IDs don't precede each other -+ return false; -+ } -+ -+ public boolean equals(Object other) { -+ if (other instanceof ObjectIdentifier) -+ return equals((ObjectIdentifier) other); -+ else -+ return false; -+ } -+ -+ /** -+ * Compares this identifier with another, for equality. -+ * -+ * @return true iff the names are identical. -+ */ -+ public boolean equals(ObjectIdentifier other) { -+ int i; -+ -+ if (other == this) -+ return true; -+ if (componentLen != other.componentLen) -+ return false; -+ for (i = 0; i < componentLen; i++) { -+ if (components[i].compareTo(other.components[i]) != 0 ) -+ return false; -+ } -+ return true; -+ } -+ -+ public int hashCode() { -+ int h = 0; -+ int oflow = 0; -+ -+ for (int i = 0; i < componentLen; i++) { -+ oflow = (h & 0xff800000) >> 23; -+ h <<= 9; -+ h += components[i].intValue(); -+ h ^= oflow; -+ } -+ return h; -+ } -+ -+ /** -+ * Returns a string form of the object ID. The format is the -+ * conventional "dot" notation for such IDs, without any -+ * user-friendly descriptive strings, since those strings -+ * will not be understood everywhere. -+ */ -+ public String toString() { -+ StringBuffer retval = new StringBuffer(); -+ -+ int i; -+ -+ for (i = 0; i < componentLen; i++) { -+ if (i != 0) -+ retval.append("."); -+ retval.append(components[i]); -+ } -+ return retval.toString(); -+ } -+ -+ /* -+ * To simplify, we assume no individual component of an object ID is -+ * larger than 64 bits. Then we represent the path from the root as -+ * an array that's (usually) only filled at the beginning. -+ */ -+ private BigInteger components[]; // path from root -+ private int componentLen; // how much is used. -+ -+ private static final int allocationQuantum = 5; // >= 2 -+ -+ /** -+ * Netscape Enhancement: -+ * This function implements a object identifier factory. It -+ * should help reduces in-memory Object Identifier object. -+ * This function also provide additional checking on the OID. -+ * A valid OID should start with 0, 1, or 2. -+ * -+ * Notes: -+ * This function never returns null. IOException is raised -+ * in error conditions. -+ */ -+ public static Hashtable mOIDs = new Hashtable(); -+ -+ public static ObjectIdentifier getObjectIdentifier(String oid) -+ throws IOException { -+ int value; -+ -+ if (oid == null) -+ throw new IOException("empty object identifier"); -+ -+ oid = oid.trim(); -+ -+ ObjectIdentifier thisOID = mOIDs.get(oid); -+ if (thisOID != null) -+ return thisOID; -+ -+ StringTokenizer token = new StringTokenizer(oid, "."); -+ value = new Integer(token.nextToken()).intValue(); -+ /* First token should be 0, 1, 2 */ -+ if (value >= 0 && value <= 2) { -+ value = new Integer(token.nextToken()).intValue(); -+ /* Second token should be 0 <= && >= 39 */ -+ if (value >= 0 && value <= 39) { -+ thisOID = new ObjectIdentifier(oid); -+ if (thisOID.toString().equals(oid)) { -+ mOIDs.put(oid, thisOID); -+ return thisOID; -+ } -+ throw new IOException("invalid oid " + oid); -+ } else -+ throw new IOException("invalid oid " + oid); -+ } else -+ throw new IOException("invalid oid " + oid); -+ } -+ -+ public static ObjectIdentifier getObjectIdentifier(int values[]) -+ throws IOException { -+ StringBuffer retval = new StringBuffer(); -+ int i; -+ -+ for (i = 0; i < values.length; i++) { -+ if (i != 0) -+ retval.append("."); -+ retval.append(values[i]); -+ } -+ return getObjectIdentifier(retval.toString()); -+ } -+ -+ public static void main(String[] args) { -+ -+ long[] oid_components_long = { 1L, 3L,6L,1L,4L,1L,5000L,9L,1L,1L,1526913300628L, 1L}; -+ int[] oid_components_int = { 1, 3,6,1,4,1,2312,9,1,1,15269, 1, 1}; -+ BigInteger[] oid_components_big_int = { new BigInteger("1"), new BigInteger("3"), new BigInteger("6"), new BigInteger("1"), -+ new BigInteger("4"), new BigInteger("1"), new BigInteger("2312"), -+ new BigInteger("9"), new BigInteger("1"), -+ new BigInteger("152691330062899999999999997777788888888888888889999999999999999"), new BigInteger("1") -+ }; -+ -+ String oidIn = "1.3.6.1.4.1.2312.9.1.152691330062899999999999997777788888888888888889999999999999999.1"; -+ ObjectIdentifier oid = new ObjectIdentifier(oidIn); -+ -+ ObjectIdentifier fromDer = null; -+ ObjectIdentifier fromStaticMethod = null; -+ ObjectIdentifier fromComponentList = null; -+ ObjectIdentifier fromComponentListInt = null; -+ ObjectIdentifier fromComponentListBigInt = null; -+ -+ System.out.println("oid: " + oid.toString()); -+ -+ DerOutputStream out = new DerOutputStream(); -+ -+ try { -+ oid.encode(out); -+ DerInputStream in = new DerInputStream(out.toByteArray()); -+ fromDer = new ObjectIdentifier(in); -+ -+ System.out.println("fromDer: " + fromDer.toString()); -+ -+ fromStaticMethod = ObjectIdentifier.getObjectIdentifier(oidIn); -+ -+ System.out.println("fromStaticMethod: " + fromStaticMethod.toString()); -+ -+ fromComponentList = new ObjectIdentifier(oid_components_long); -+ -+ System.out.println("fromComponentList: " + fromComponentList.toString()); -+ -+ fromComponentListInt = new ObjectIdentifier(oid_components_int); -+ -+ System.out.println("fromComponentListInt: " + fromComponentListInt); -+ -+ fromComponentListBigInt = new ObjectIdentifier(oid_components_big_int); -+ -+ System.out.println("fromComponentListBigInt: " + fromComponentListBigInt); -+ -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/PrettyPrintFormat.java b/org/mozilla/jss/netscape/security/util/PrettyPrintFormat.java -new file mode 100644 -index 00000000..9bd8b43f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/PrettyPrintFormat.java -@@ -0,0 +1,164 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+ -+/** -+ * This class will display the certificate content in predefined -+ * format. -+ * -+ * @author Andrew Wnuk -+ * @version $Revision$, $Date$ -+ */ -+public class PrettyPrintFormat { -+ -+ /*========================================================== -+ * variables -+ *==========================================================*/ -+ private String mSeparator = ""; -+ private int mIndentSize = 0; -+ private int mLineLen = 0; -+ -+ /*========================================================== -+ * constants -+ * -+ *==========================================================*/ -+ private final static String spaces = -+ " " + -+ " " + -+ " " + -+ " " + -+ " "; -+ -+ /*========================================================== -+ * constructors -+ *==========================================================*/ -+ -+ public PrettyPrintFormat(String separator) { -+ mSeparator = separator; -+ } -+ -+ public PrettyPrintFormat(String separator, int lineLen) { -+ mSeparator = separator; -+ mLineLen = lineLen; -+ } -+ -+ public PrettyPrintFormat(String separator, int lineLen, int indentSize) { -+ mSeparator = separator; -+ mLineLen = lineLen; -+ mIndentSize = indentSize; -+ } -+ -+ /*========================================================== -+ * Private methods -+ *==========================================================*/ -+ -+ /*========================================================== -+ * public methods -+ *==========================================================*/ -+ -+ /** -+ * Provide white space indention -+ * stevep - speed improvements. Factor of 10 improvement -+ * -+ * @param numSpace number of white space to be returned -+ * @return white spaces -+ */ -+ public String indent(int size) { -+ return spaces.substring(0, size); -+ } -+ -+ private static final char[] hexdigits = { -+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', -+ 'A', 'B', 'C', 'D', 'E', 'F' -+ }; -+ -+ /** -+ * Convert Byte Array to Hex String Format -+ * stevep - speedup by factor of 8 -+ * -+ * @param byte array of data to hexify -+ * @param indentSize number of spaces to prepend before each line -+ * @param lineLen number of bytes to output on each line (0 -+ * means: put everything on one line -+ * @param separator the first character of this string will be used as -+ * the separator between bytes. -+ * @return string representation -+ */ -+ -+ public String toHexString(byte[] in, int indentSize, -+ int lineLen, String separator) { -+ if (in == null) { -+ return ""; -+ } -+ StringBuffer sb = new StringBuffer(); -+ int hexCount = 0; -+ char c[]; -+ int j = 0; -+ -+ if (lineLen == 0) { -+ c = new char[in.length * 3 + 1]; -+ } else { -+ c = new char[lineLen * 3 + 1]; -+ } -+ -+ char sep = separator.charAt(0); -+ -+ sb.append(indent(indentSize)); -+ for (int i = 0; i < in.length; i++) { -+ if (lineLen > 0 && hexCount == lineLen) { -+ c[j++] = '\n'; -+ sb.append(c, 0, j); -+ sb.append(indent(indentSize)); -+ hexCount = 0; -+ j = 0; -+ } -+ byte x = in[i]; -+ -+ // output hex digits to buffer -+ c[j++] = hexdigits[(char) ((x >> 4) & 0xf)]; -+ c[j++] = hexdigits[(char) (x & 0xf)]; -+ -+ // if not last char, output separator -+ if (i != in.length - 1) { -+ c[j++] = sep; -+ } -+ -+ hexCount++; -+ } -+ if (j > 0) { -+ c[j++] = '\n'; -+ sb.append(c, 0, j); -+ } -+ // sb.append("\n"); -+ -+ return sb.toString(); -+ } -+ -+ public String toHexString(byte[] in, int indentSize, int lineLen) { -+ return toHexString(in, indentSize, lineLen, mSeparator); -+ } -+ -+ public String toHexString(byte[] in, int indentSize) { -+ return toHexString(in, indentSize, mLineLen); -+ } -+ -+ public String toHexString(byte[] in) { -+ return toHexString(in, mIndentSize); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/PrettyPrintResources.java b/org/mozilla/jss/netscape/security/util/PrettyPrintResources.java -new file mode 100644 -index 00000000..5b4b6230 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/PrettyPrintResources.java -@@ -0,0 +1,301 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.util.ListResourceBundle; -+ -+import org.mozilla.jss.netscape.security.extensions.NSCertTypeExtension; -+import org.mozilla.jss.netscape.security.x509.KeyUsageExtension; -+ -+/** -+ * Resource Boundle for the Pretty Print -+ * -+ * @author Jack Pan-Chen -+ * @version $Revision$, $Date$ -+ */ -+ -+public class PrettyPrintResources extends ListResourceBundle { -+ -+ /** -+ * Returns content -+ */ -+ public Object[][] getContents() { -+ return contents; -+ } -+ -+ /** -+ * Constants. The suffix represents the number of -+ * possible parameters. -+ */ -+ -+ //certificate pretty print -+ public final static String TOKEN_CERTIFICATE = "tokenCertificate"; -+ public final static String TOKEN_DATA = "tokenData"; -+ public final static String TOKEN_VERSION = "tokenVersion"; -+ public final static String TOKEN_SERIAL = "tokenSerial"; -+ public final static String TOKEN_SIGALG = "tokenSignatureAlgorithm"; -+ public final static String TOKEN_ISSUER = "tokenIssuer"; -+ public final static String TOKEN_VALIDITY = "tokenValidity"; -+ public final static String TOKEN_NOT_BEFORE = "tokenNotBefore"; -+ public final static String TOKEN_NOT_AFTER = "tokenNotAfter"; -+ public final static String TOKEN_SUBJECT = "tokenSubject"; -+ public final static String TOKEN_SPKI = "tokenSPKI"; -+ public final static String TOKEN_ALGORITHM = "tokenAlgorithm"; -+ public final static String TOKEN_PUBLIC_KEY = "tokenPublicKey"; -+ public final static String TOKEN_PUBLIC_KEY_MODULUS = "tokenPublicKeyModulus"; -+ public final static String TOKEN_PUBLIC_KEY_EXPONENT = "tokenPublicKeyExponent"; -+ public final static String TOKEN_EXTENSIONS = "tokenExtensions"; -+ public final static String TOKEN_SIGNATURE = "tokenSignature"; -+ -+ //extension pretty print -+ public final static String TOKEN_YES = "tokenYes"; -+ public final static String TOKEN_NO = "tokenNo"; -+ public final static String TOKEN_IDENTIFIER = "tokenIdentifier"; -+ public final static String TOKEN_CRITICAL = "tokenCritical"; -+ public final static String TOKEN_VALUE = "tokenValue"; -+ -+ //specific extension token -+ public final static String TOKEN_KEY_TYPE = "tokenKeyType"; -+ public final static String TOKEN_CERT_TYPE = "tokenCertType"; -+ public final static String TOKEN_SKI = "tokenSKI"; -+ public final static String TOKEN_AKI = "tokenAKI"; -+ public final static String TOKEN_ACCESS_DESC = "tokenAccessDesc"; -+ public final static String TOKEN_OCSP_NOCHECK = "tokenOcspNoCheck"; -+ public final static String TOKEN_EXTENDED_KEY_USAGE = "tokenExtendedKeyUsage"; -+ public final static String TOKEN_PRIVATE_KEY_USAGE = "tokenPrivateKeyUsage"; -+ public final static String TOKEN_PRESENCE_SERVER = "tokenPresenceServer"; -+ public final static String TOKEN_AIA = "tokenAIA"; -+ public final static String TOKEN_CERT_POLICIES = "tokenCertPolicies"; -+ public final static String TOKEN_SIA = "tokenSIA"; -+ public final static String TOKEN_KEY_USAGE = "tokenKeyUsage"; -+ public final static String TOKEN_CERT_USAGE = "tokenCertUsage"; -+ public final static String TOKEN_KEY_ID = "tokenKeyId"; -+ public final static String TOKEN_AUTH_NAME = "tokenAuthName"; -+ -+ public final static String TOKEN_CRL = "tokenCRL"; -+ public final static String TOKEN_THIS_UPDATE = "tokenThisUpdate"; -+ public final static String TOKEN_NEXT_UPDATE = "tokenNextUpdate"; -+ public final static String TOKEN_REVOKED_CERTIFICATES = "revokedCerts"; -+ public final static String TOKEN_REVOCATION_DATE = "revocationDate"; -+ -+ public final static String TOKEN_REVOCATION_REASON = "revocationReason"; -+ public final static String TOKEN_REASON = "reason"; -+ -+ public final static String TOKEN_BASIC_CONSTRAINTS = "basicConstraints"; -+ public final static String TOKEN_NAME_CONSTRAINTS = "tokenNameConstraints"; -+ public final static String TOKEN_NSC_COMMENT = "tokenNSCComment"; -+ public final static String TOKEN_IS_CA = "isCA"; -+ public final static String TOKEN_PATH_LEN = "pathLen"; -+ public final static String TOKEN_PATH_LEN_UNLIMITED = "pathLenUnlimited"; -+ public final static String TOKEN_PATH_LEN_UNDEFINED = "pathLenUndefined"; -+ public final static String TOKEN_PATH_LEN_INVALID = "pathLenInvalid"; -+ -+ public final static String TOKEN_CRL_NUMBER = "CRLNumber"; -+ public final static String TOKEN_NUMBER = "Number"; -+ -+ public final static String TOKEN_DELTA_CRL_INDICATOR = "DeltaCRLIndicator"; -+ public final static String TOKEN_BASE_CRL_NUMBER = "BaseCRLNumber"; -+ -+ public final static String TOKEN_CERT_SCOPE_OF_USE = "CertificateScopeOfUse"; -+ public final static String TOKEN_SCOPE_OF_USE = "ScopeOfUse"; -+ public final static String TOKEN_PORT = "Port"; -+ -+ public final static String TOKEN_ISSUER_ALT_NAME = "IssuerAlternativeName"; -+ public final static String TOKEN_ISSUER_NAMES = "IssuerNames"; -+ -+ public final static String TOKEN_SUBJECT_ALT_NAME = "SubjectAlternativeName"; -+ public final static String TOKEN_SUBJECT_NAME = "SubjectName"; -+ -+ public final static String TOKEN_DECODING_ERROR = "decodingError"; -+ -+ public final static String TOKEN_FRESHEST_CRL_EXT = "FreshestCRL"; -+ public final static String TOKEN_INHIBIT_ANY_POLICY_EXT = "InhibitAnyPolicy"; -+ public final static String TOKEN_SKIP_CERTS = "SkipCerts"; -+ -+ public final static String TOKEN_CRL_DP_EXT = "CRLDistributionPoints"; -+ public final static String TOKEN_CRLDP_NUMPOINTS = "CRLDP_NUMPOINTS"; -+ public final static String TOKEN_CRLDP_POINTN = "CRLDP_POINTN"; -+ public final static String TOKEN_CRLDP_DISTPOINT = "CRLDP_DISTPOINT"; -+ public final static String TOKEN_CRLDP_REASONS = "CRLDP_REASONS"; -+ public final static String TOKEN_CRLDP_CRLISSUER = "CRLDP_CRLISSUER"; -+ -+ public final static String TOKEN_ISSUING_DIST_POINT = "IssuingDistributionPoint"; -+ public final static String TOKEN_DIST_POINT_NAME = "DistributionPointName"; -+ public final static String TOKEN_FULL_NAME = "FullName"; -+ public final static String TOKEN_RELATIVE_NAME = "NameRelativeToCRLIssuer"; -+ public final static String TOKEN_ONLY_USER_CERTS = "OnlyContainsUserCerts"; -+ public final static String TOKEN_ONLY_CA_CERTS = "OnlyContainsCACerts"; -+ public final static String TOKEN_ONLY_SOME_REASONS = "OnlySomeReasons"; -+ public final static String TOKEN_INDIRECT_CRL = "IndirectCRL"; -+ -+ public final static String TOKEN_INVALIDITY_DATE = "invalidityDate"; -+ public final static String TOKEN_DATE_OF_INVALIDITY = "dateOfInvalidity"; -+ -+ public final static String TOKEN_CERTIFICATE_ISSUER = "CertificateIssuer"; -+ -+ public final static String TOKEN_HOLD_INSTRUCTION = "HoldInstruction"; -+ public final static String TOKEN_HOLD_INSTRUCTION_CODE = "HoldInstructionCode"; -+ public final static String TOKEN_POLICY_CONSTRAINTS = "PolicyConstraints"; -+ public final static String TOKEN_POLICY_MAPPINGS = "PolicyMappings"; -+ public final static String TOKEN_SUBJECT_DIR_ATTR = "SubjectDirectoryAttributes"; -+ -+ // policy constriants extension fields -+ public final static String TOKEN_INHIBIT_POLICY_MAPPING = "inhibitPolicyMapping"; -+ public final static String TOKEN_REQUIRE_EXPLICIT_POLICY = "requireExplicitPolicy"; -+ -+ // policy mappings extension fields -+ public final static String TOKEN_MAPPINGS = "mappings"; -+ public final static String TOKEN_MAP = "map"; -+ public final static String TOKEN_ISSUER_DOMAIN_POLICY = "issuerDomainPolicy"; -+ public final static String TOKEN_SUBJECT_DOMAIN_POLICY = "subjectDomainPolicy"; -+ -+ // subject directory attribute fields -+ public final static String TOKEN_ATTRIBUTES = "Attributes"; -+ public final static String TOKEN_ATTRIBUTE = "Attribute"; -+ public final static String TOKEN_VALUES = "Values"; -+ -+ // field values -+ public final static String TOKEN_NOT_SET = "notSet"; -+ public final static String TOKEN_NONE = "none"; -+ -+ public final static String TOKEN_CACHE_NOT_AVAILABLE = "cacheNotAvailable"; -+ public final static String TOKEN_CACHE_IS_EMPTY = "cacheIsEmpty"; -+ -+ //Tokens should have blank_space as trailer -+ static final Object[][] contents = { -+ { TOKEN_CERTIFICATE, "Certificate: " }, -+ { TOKEN_DATA, "Data: " }, -+ { TOKEN_VERSION, "Version: " }, -+ { TOKEN_SERIAL, "Serial Number: " }, -+ { TOKEN_SIGALG, "Signature Algorithm: " }, -+ { TOKEN_ISSUER, "Issuer: " }, -+ { TOKEN_VALIDITY, "Validity: " }, -+ { TOKEN_NOT_BEFORE, "Not Before: " }, -+ { TOKEN_NOT_AFTER, "Not After: " }, -+ { TOKEN_SUBJECT, "Subject: " }, -+ { TOKEN_SPKI, "Subject Public Key Info: " }, -+ { TOKEN_ALGORITHM, "Algorithm: " }, -+ { TOKEN_PUBLIC_KEY, "Public Key: " }, -+ { TOKEN_PUBLIC_KEY_MODULUS, "Public Key Modulus: " }, -+ { TOKEN_PUBLIC_KEY_EXPONENT, "Exponent: " }, -+ { TOKEN_EXTENSIONS, "Extensions: " }, -+ { TOKEN_SIGNATURE, "Signature: " }, -+ { TOKEN_YES, "yes " }, -+ { TOKEN_NO, "no " }, -+ { TOKEN_IDENTIFIER, "Identifier: " }, -+ { TOKEN_CRITICAL, "Critical: " }, -+ { TOKEN_VALUE, "Value: " }, -+ { TOKEN_KEY_TYPE, "Key Type " }, -+ { TOKEN_CERT_TYPE, "Netscape Certificate Type " }, -+ { TOKEN_SKI, "Subject Key Identifier " }, -+ { TOKEN_AKI, "Authority Key Identifier " }, -+ { TOKEN_ACCESS_DESC, "Access Description: " }, -+ { TOKEN_OCSP_NOCHECK, "OCSP NoCheck: " }, -+ { TOKEN_EXTENDED_KEY_USAGE, "Extended Key Usage: " }, -+ { TOKEN_PRIVATE_KEY_USAGE, "Private Key Usage: " }, -+ { TOKEN_PRESENCE_SERVER, "Presence Server: " }, -+ { TOKEN_AIA, "Authority Info Access: " }, -+ { TOKEN_CERT_POLICIES, "Certificate Policies: " }, -+ { TOKEN_SIA, "Subject Info Access: " }, -+ { TOKEN_KEY_USAGE, "Key Usage: " }, -+ { KeyUsageExtension.DIGITAL_SIGNATURE, "Digital Signature " }, -+ { KeyUsageExtension.NON_REPUDIATION, "Non Repudiation " }, -+ { KeyUsageExtension.KEY_ENCIPHERMENT, "Key Encipherment " }, -+ { KeyUsageExtension.DATA_ENCIPHERMENT, "Data Encipherment " }, -+ { KeyUsageExtension.KEY_AGREEMENT, "Key Agreement " }, -+ { KeyUsageExtension.KEY_CERTSIGN, "Key CertSign " }, -+ { KeyUsageExtension.CRL_SIGN, "Crl Sign " }, -+ { KeyUsageExtension.ENCIPHER_ONLY, "Encipher Only " }, -+ { KeyUsageExtension.DECIPHER_ONLY, "Decipher Only " }, -+ { TOKEN_CERT_USAGE, "Certificate Usage: " }, -+ { NSCertTypeExtension.SSL_CLIENT, "SSL Client " }, -+ { NSCertTypeExtension.SSL_SERVER, "SSL Server " }, -+ { NSCertTypeExtension.EMAIL, "Secure Email " }, -+ { NSCertTypeExtension.OBJECT_SIGNING, "Object Signing " }, -+ { NSCertTypeExtension.SSL_CA, "SSL CA " }, -+ { NSCertTypeExtension.EMAIL_CA, "Secure Email CA " }, -+ { NSCertTypeExtension.OBJECT_SIGNING_CA, "ObjectSigning CA " }, -+ { TOKEN_KEY_ID, "Key Identifier: " }, -+ { TOKEN_AUTH_NAME, "Authority Name: " }, -+ { TOKEN_CRL, "Certificate Revocation List: " }, -+ { TOKEN_THIS_UPDATE, "This Update: " }, -+ { TOKEN_NEXT_UPDATE, "Next Update: " }, -+ { TOKEN_REVOKED_CERTIFICATES, "Revoked Certificates: " }, -+ { TOKEN_REVOCATION_DATE, "Revocation Date: " }, -+ { TOKEN_REVOCATION_REASON, "Revocation Reason " }, -+ { TOKEN_REASON, "Reason: " }, -+ { TOKEN_BASIC_CONSTRAINTS, "Basic Constraints " }, -+ { TOKEN_NAME_CONSTRAINTS, "Name Constraints " }, -+ { TOKEN_NSC_COMMENT, "Netscape Comment " }, -+ { TOKEN_IS_CA, "Is CA: " }, -+ { TOKEN_PATH_LEN, "Path Length Constraint: " }, -+ { TOKEN_PATH_LEN_UNLIMITED, "UNLIMITED" }, -+ { TOKEN_PATH_LEN_UNDEFINED, "UNDEFINED" }, -+ { TOKEN_PATH_LEN_INVALID, "INVALID" }, -+ { TOKEN_CRL_NUMBER, "CRL Number " }, -+ { TOKEN_NUMBER, "Number: " }, -+ { TOKEN_DELTA_CRL_INDICATOR, "Delta CRL Indicator " }, -+ { TOKEN_BASE_CRL_NUMBER, "Base CRL Number: " }, -+ { TOKEN_CERT_SCOPE_OF_USE, "Certificate Scope of Use " }, -+ { TOKEN_SCOPE_OF_USE, "Scope of Use: " }, -+ { TOKEN_PORT, "Port: " }, -+ { TOKEN_ISSUER_ALT_NAME, "Issuer Alternative Name " }, -+ { TOKEN_ISSUER_NAMES, "Issuer Names: " }, -+ { TOKEN_SUBJECT_ALT_NAME, "Subject Alternative Name " }, -+ { TOKEN_DECODING_ERROR, "Decoding Error" }, -+ { TOKEN_FRESHEST_CRL_EXT, "Freshest CRL " }, -+ { TOKEN_INHIBIT_ANY_POLICY_EXT, "Inhibit Any-Policy " }, -+ { TOKEN_SKIP_CERTS, "Skip Certs: " }, -+ { TOKEN_CRL_DP_EXT, "CRL Distribution Points " }, -+ { TOKEN_CRLDP_NUMPOINTS, "Number of Points: " }, -+ { TOKEN_CRLDP_POINTN, "Point " }, -+ { TOKEN_CRLDP_DISTPOINT, "Distribution Point: " }, -+ { TOKEN_CRLDP_REASONS, "Reason Flags: " }, -+ { TOKEN_CRLDP_CRLISSUER, "CRL Issuer: " }, -+ { TOKEN_ISSUING_DIST_POINT, "Issuing Distribution Point " }, -+ { TOKEN_DIST_POINT_NAME, "Distribution Point: " }, -+ { TOKEN_FULL_NAME, "Full Name: " }, -+ { TOKEN_RELATIVE_NAME, "Name Relative To CRL Issuer: " }, -+ { TOKEN_ONLY_USER_CERTS, "Only Contains User Certificates: " }, -+ { TOKEN_ONLY_CA_CERTS, "Only Contains CA Certificates: " }, -+ { TOKEN_ONLY_SOME_REASONS, "Only Some Reasons: " }, -+ { TOKEN_INDIRECT_CRL, "Indirect CRL: " }, -+ { TOKEN_INVALIDITY_DATE, "Invalidity Date " }, -+ { TOKEN_DATE_OF_INVALIDITY, "Invalidity Date: " }, -+ { TOKEN_CERTIFICATE_ISSUER, "Certificate Issuer " }, -+ { TOKEN_HOLD_INSTRUCTION, "Hold Instruction Code " }, -+ { TOKEN_HOLD_INSTRUCTION_CODE, "Hold Instruction Code: " }, -+ { TOKEN_POLICY_CONSTRAINTS, "Policy Constraints " }, -+ { TOKEN_INHIBIT_POLICY_MAPPING, "Inhibit Policy Mapping: " }, -+ { TOKEN_REQUIRE_EXPLICIT_POLICY, "Require Explicit Policy: " }, -+ { TOKEN_POLICY_MAPPINGS, "Policy Mappings " }, -+ { TOKEN_MAPPINGS, "Mappings: " }, -+ { TOKEN_MAP, "Map " }, -+ { TOKEN_ISSUER_DOMAIN_POLICY, "Issuer Domain Policy: " }, -+ { TOKEN_SUBJECT_DOMAIN_POLICY, "Subject Domain Policy: " }, -+ { TOKEN_SUBJECT_DIR_ATTR, "Subject Directory Attributes " }, -+ { TOKEN_ATTRIBUTES, "Attributes:" }, -+ { TOKEN_ATTRIBUTE, "Attribute " }, -+ { TOKEN_VALUES, "Values: " }, -+ { TOKEN_NOT_SET, "not set" }, -+ { TOKEN_NONE, "none" }, -+ { TOKEN_CACHE_NOT_AVAILABLE, "CRL cache is not available. " }, -+ { TOKEN_CACHE_IS_EMPTY, "CRL cache is empty. " }, -+ }; -+ -+} -diff --git a/org/mozilla/jss/netscape/security/util/PrintableCharset.java b/org/mozilla/jss/netscape/security/util/PrintableCharset.java -new file mode 100644 -index 00000000..53777001 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/PrintableCharset.java -@@ -0,0 +1,46 @@ -+package org.mozilla.jss.netscape.security.util; -+ -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetDecoder; -+import java.nio.charset.CharsetEncoder; -+ -+public class PrintableCharset extends Charset { -+ -+ public PrintableCharset() { -+ super("ASN.1-Printable", null); -+ } -+ -+ public static boolean isPrintableChar(char c) { -+ if ((c < 'A' || c > 'Z') && -+ (c < 'a' || c > 'z') && -+ (c < '0' || c > '9') && -+ (c != ' ') && -+ (c != '\'') && -+ (c != '(') && -+ (c != ')') && -+ (c != '+') && -+ (c != ',') && -+ (c != '-') && -+ (c != '.') && -+ (c != '/') && -+ (c != ':') && -+ (c != '=') && -+ (c != '?')) { -+ return false; -+ } else { -+ return true; -+ } -+ } -+ -+ public boolean contains(Charset cs) { -+ return false; -+ } -+ -+ public CharsetDecoder newDecoder() { -+ return new PrintableCharsetDecoder(this); -+ } -+ -+ public CharsetEncoder newEncoder() { -+ return new PrintableCharsetEncoder(this); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/PrintableCharsetDecoder.java b/org/mozilla/jss/netscape/security/util/PrintableCharsetDecoder.java -new file mode 100644 -index 00000000..3c680a0e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/PrintableCharsetDecoder.java -@@ -0,0 +1,69 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetDecoder; -+import java.nio.charset.CoderResult; -+import java.nio.charset.CodingErrorAction; -+ -+/** -+ * Converts bytes in ASN.1 PrintableString character set to PrintableString -+ * characters. -+ * -+ * @author Lily Hsiao -+ * @author Slava Galperin -+ */ -+ -+public class PrintableCharsetDecoder extends CharsetDecoder { -+ -+ public PrintableCharsetDecoder(Charset cs) { -+ super(cs, 1, 1); -+ } -+ -+ protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { -+ -+ while (true) { -+ -+ if (in.remaining() < 1) -+ return CoderResult.UNDERFLOW; -+ -+ in.mark(); -+ byte b = in.get(); -+ char c = (char) (b & 0x7f); -+ -+ if (CodingErrorAction.REPORT == unmappableCharacterAction() && -+ !PrintableCharset.isPrintableChar(c)) { -+ /* -+ "bug" fix for 359010 -+ return CoderResult.unmappableForLength(1); -+ */ -+ continue; -+ } -+ -+ if (out.remaining() < 1) { -+ in.reset(); -+ return CoderResult.OVERFLOW; -+ } -+ -+ out.put(c); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/PrintableCharsetEncoder.java b/org/mozilla/jss/netscape/security/util/PrintableCharsetEncoder.java -new file mode 100644 -index 00000000..f527020b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/PrintableCharsetEncoder.java -@@ -0,0 +1,71 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetEncoder; -+import java.nio.charset.CoderResult; -+import java.nio.charset.CodingErrorAction; -+ -+/** -+ * Converts characters in ASN.1 PrintableString character set to PrintableString -+ * bytes. -+ * -+ * @author Lily Hsiao -+ * @author Slava Galperin -+ */ -+ -+public class PrintableCharsetEncoder extends CharsetEncoder { -+ -+ public PrintableCharsetEncoder(Charset cs) { -+ super(cs, 1, 1); -+ } -+ -+ /* -+ * Converts an array of Unicode characters into an array of PrintableString -+ * bytes and returns the conversion result. -+ * @param in input character buffer to convert. -+ * @param out byte buffer to store output. -+ * @return encoding result. -+ */ -+ protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { -+ -+ while (true) { -+ -+ if (in.remaining() < 1) -+ return CoderResult.UNDERFLOW; -+ -+ in.mark(); -+ char c = in.get(); -+ -+ if (CodingErrorAction.REPORT == unmappableCharacterAction() && -+ !PrintableCharset.isPrintableChar(c)) { -+ return CoderResult.unmappableForLength(1); -+ } -+ -+ if (out.remaining() < 1) { -+ in.reset(); -+ return CoderResult.OVERFLOW; -+ } -+ -+ out.put((byte) (c & 0x7f)); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/PubKeyPrettyPrint.java b/org/mozilla/jss/netscape/security/util/PubKeyPrettyPrint.java -new file mode 100644 -index 00000000..fde659ae ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/PubKeyPrettyPrint.java -@@ -0,0 +1,123 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.security.InvalidKeyException; -+import java.security.PublicKey; -+import java.util.Locale; -+import java.util.ResourceBundle; -+ -+import org.mozilla.jss.netscape.security.provider.RSAPublicKey; -+import org.mozilla.jss.netscape.security.x509.X509Key; -+ -+/** -+ * This class will display the certificate content in predefined -+ * format. -+ * -+ * @author Jack Pan-Chen -+ * @author Andrew Wnuk -+ * @version $Revision$, $Date$ -+ */ -+public class PubKeyPrettyPrint { -+ -+ /*========================================================== -+ * variables -+ *==========================================================*/ -+ private X509Key mX509Key = null; -+ private PrettyPrintFormat pp = null; -+ -+ /*========================================================== -+ * constructors -+ *==========================================================*/ -+ -+ public PubKeyPrettyPrint(PublicKey key) { -+ if (key instanceof X509Key) -+ mX509Key = (X509Key) key; -+ -+ pp = new PrettyPrintFormat(":"); -+ } -+ -+ /*========================================================== -+ * public methods -+ *==========================================================*/ -+ -+ /** -+ * This method return string representation of the certificate -+ * in predefined format using specified client local. I18N Support. -+ * -+ * @param clientLocale Locale to be used for localization -+ * @return string representation of the certificate -+ */ -+ public String toString(Locale clientLocale, int indentSize, int lineLen) { -+ -+ if (mX509Key != null) -+ return X509toString(clientLocale, indentSize, lineLen); -+ else -+ return null; -+ } -+ -+ public String X509toString(Locale clientLocale, int indentSize, int lineLen) { -+ -+ //get I18N resources -+ ResourceBundle resource = ResourceBundle.getBundle( -+ PrettyPrintResources.class.getName()); -+ -+ StringBuffer sb = new StringBuffer(); -+ -+ try { -+ String alg = mX509Key.getAlgorithm(); -+ -+ //XXX I18N Algorithm Name ? -+ sb.append(pp.indent(indentSize) + resource.getString( -+ PrettyPrintResources.TOKEN_ALGORITHM) + -+ alg + " - " + -+ mX509Key.getAlgorithmId().getOID().toString() + "\n"); -+ -+ if (alg.equals("RSA")) { -+ -+ RSAPublicKey rsakey = new RSAPublicKey(mX509Key.getEncoded()); -+ -+ sb.append(pp.indent(indentSize) + resource.getString( -+ PrettyPrintResources.TOKEN_PUBLIC_KEY) + "\n"); -+ sb.append(pp.indent(indentSize + 4) + resource.getString( -+ PrettyPrintResources.TOKEN_PUBLIC_KEY_EXPONENT) + -+ rsakey.getPublicExponent().toInt() + "\n"); -+ sb.append(pp.indent(indentSize + 4) + resource.getString( -+ PrettyPrintResources.TOKEN_PUBLIC_KEY_MODULUS) + -+ "(" + rsakey.getKeySize() + " bits) :\n"); -+ sb.append(pp.toHexString( -+ rsakey.getModulus().toByteArray(), -+ indentSize + 8, lineLen)); -+ } else { -+ -+ // DSAPublicKey is more complicated to decode, since -+ // the DSAParams (PQG) is not fully decoded. -+ // So, we just print the entire public key blob -+ -+ sb.append(pp.indent(indentSize) + resource.getString( -+ PrettyPrintResources.TOKEN_PUBLIC_KEY) + "\n"); -+ sb.append(pp.toHexString(mX509Key.getKey(), indentSize + 4, lineLen)); -+ } -+ -+ } catch(InvalidKeyException e){ -+ e.printStackTrace(); -+ } -+ -+ return sb.toString(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/UniversalCharset.java b/org/mozilla/jss/netscape/security/util/UniversalCharset.java -new file mode 100644 -index 00000000..3d2b2a03 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/UniversalCharset.java -@@ -0,0 +1,24 @@ -+package org.mozilla.jss.netscape.security.util; -+ -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetDecoder; -+import java.nio.charset.CharsetEncoder; -+ -+public class UniversalCharset extends Charset { -+ -+ public UniversalCharset() { -+ super("ASN.1-Universal", null); -+ } -+ -+ public boolean contains(Charset cs) { -+ return false; -+ } -+ -+ public CharsetDecoder newDecoder() { -+ return new UniversalCharsetDecoder(this); -+ } -+ -+ public CharsetEncoder newEncoder() { -+ return new UniversalCharsetEncoder(this); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/UniversalCharsetDecoder.java b/org/mozilla/jss/netscape/security/util/UniversalCharsetDecoder.java -new file mode 100644 -index 00000000..d1df9a47 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/UniversalCharsetDecoder.java -@@ -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. -+// -+// (C) 2007 Red Hat, Inc. -+// All rights reserved. -+// --- END COPYRIGHT BLOCK --- -+package org.mozilla.jss.netscape.security.util; -+ -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetDecoder; -+import java.nio.charset.CoderResult; -+import java.nio.charset.CodingErrorAction; -+ -+/** -+ * Converts bytes in ASN.1 UniversalString character set to UniversalString -+ * characters. -+ * -+ * @author Lily Hsiao -+ * @author Slava Galperin -+ */ -+ -+public class UniversalCharsetDecoder extends CharsetDecoder { -+ -+ public UniversalCharsetDecoder(Charset cs) { -+ super(cs, 0.25f, 1); -+ } -+ -+ protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { -+ -+ while (true) { -+ // XXX we do not know what to do with truly UCS-4 characters here -+ // we also assumed network byte order -+ -+ if (in.remaining() < 4) -+ return CoderResult.UNDERFLOW; -+ -+ in.mark(); -+ byte b0 = in.get(); -+ byte b1 = in.get(); -+ byte b2 = in.get(); -+ byte b3 = in.get(); -+ -+ if (CodingErrorAction.REPORT == unmappableCharacterAction() && -+ !((b0 == 0 && b1 == 0) || (b2 == 0 && b3 == 0))) { -+ return CoderResult.unmappableForLength(4); -+ } -+ -+ char c; -+ if (b2 == 0 && b3 == 0) { -+ // Try to be a bit forgiving. If the byte order is -+ // reversed, we still try handle it. -+ -+ // Sample Date Set (1): -+ // 0000000 f 0 \0 \0 213 0 \0 \0 S 0 \0 \0 -+ // 0000014 -+ -+ // Sample Date Set (2): -+ // 0000000 w \0 \0 \0 w \0 \0 \0 w \0 \0 \0 . \0 \0 \0 -+ // 0000020 ( \0 \0 \0 t \0 \0 \0 o \0 \0 \0 b \0 \0 \0 -+ // 0000040 e \0 \0 \0 | \0 \0 \0 n \0 \0 \0 o \0 \0 \0 -+ // 0000060 t \0 \0 \0 t \0 \0 \0 o \0 \0 \0 b \0 \0 \0 -+ // 0000100 e \0 \0 \0 ) \0 \0 \0 . \0 \0 \0 c \0 \0 \0 -+ // 0000120 o \0 \0 \0 m \0 \0 \0 -+ // 0000130 -+ c = (char) (((b1 << 8) & 0xff00) + (b0 & 0x00ff)); -+ -+ } else { // (b0 == 0 && b1 == 0) -+ // This should be the right order. -+ // -+ // 0000000 0000 00c4 0000 0064 0000 006d 0000 0069 -+ // 0000020 0000 006e 0000 0020 0000 0051 0000 0041 -+ // 0000040 -+ -+ c = (char) (((b2 << 8) & 0xff00) + (b3 & 0x00ff)); -+ } -+ -+ if (out.remaining() < 1) { -+ in.reset(); -+ return CoderResult.OVERFLOW; -+ } -+ -+ out.put(c); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/UniversalCharsetEncoder.java b/org/mozilla/jss/netscape/security/util/UniversalCharsetEncoder.java -new file mode 100644 -index 00000000..1dc6e25c ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/UniversalCharsetEncoder.java -@@ -0,0 +1,68 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetEncoder; -+import java.nio.charset.CoderResult; -+ -+/** -+ * Converts characters in ASN.1 UniversalString character set to UniversalString -+ * bytes. -+ * -+ * @author Lily Hsiao -+ * @author Slava Galperin -+ */ -+ -+public class UniversalCharsetEncoder extends CharsetEncoder { -+ -+ public UniversalCharsetEncoder(Charset cs) { -+ super(cs, 4, 4, new byte[] { 0, 0, 0, 0 }); -+ } -+ -+ /* -+ * Converts an array of Unicode characters into an array of UniversalString -+ * bytes and returns the conversion result. -+ * @param in input character buffer to convert. -+ * @param out byte buffer to store output. -+ * @return encoding result. -+ */ -+ protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { -+ -+ while (true) { -+ -+ if (in.remaining() < 1) -+ return CoderResult.UNDERFLOW; -+ -+ in.mark(); -+ char c = in.get(); -+ -+ if (out.remaining() < 4) { -+ in.reset(); -+ return CoderResult.OVERFLOW; -+ } -+ -+ out.put((byte) 0); -+ out.put((byte) 0); -+ out.put((byte) ((c >> 8) & 0xff)); -+ out.put((byte) (c & 0xff)); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/Utils.java b/org/mozilla/jss/netscape/security/util/Utils.java -new file mode 100644 -index 00000000..f9692315 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/Utils.java -@@ -0,0 +1,356 @@ -+// --- 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 org.mozilla.jss.netscape.security.util; -+ -+import java.io.BufferedReader; -+import java.io.BufferedWriter; -+import java.io.ByteArrayOutputStream; -+import java.io.File; -+import java.io.FileReader; -+import java.io.FileWriter; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.io.OutputStreamWriter; -+import java.io.PrintWriter; -+import java.net.InetAddress; -+import java.net.UnknownHostException; -+import java.text.SimpleDateFormat; -+import java.util.Date; -+import java.util.StringTokenizer; -+import java.util.Vector; -+ -+import org.apache.commons.codec.binary.Base64; -+ -+public class Utils { -+ /** -+ * Checks if this is NT. -+ */ -+ public static boolean isNT() { -+ return File.separator.equals("\\"); -+ } -+ -+ public static boolean isUnix() { -+ return File.separator.equals("/"); -+ } -+ -+ public static boolean exec(String cmd) { -+ try { -+ String cmds[] = null; -+ if (isNT()) { -+ // NT -+ cmds = new String[3]; -+ cmds[0] = "cmd"; -+ cmds[1] = "/c"; -+ cmds[2] = cmd; -+ } else { -+ // UNIX -+ cmds = new String[3]; -+ cmds[0] = "/bin/sh"; -+ cmds[1] = "-c"; -+ cmds[2] = cmd; -+ } -+ Process process = Runtime.getRuntime().exec(cmds); -+ process.waitFor(); -+ -+ if (process.exitValue() == 0) { -+ /** -+ * pOut = new BufferedReader( -+ * new InputStreamReader(process.getInputStream())); -+ * while ((l = pOut.readLine()) != null) { -+ * System.out.println(l); -+ * } -+ **/ -+ return true; -+ } else { -+ /** -+ * pOut = new BufferedReader( -+ * new InputStreamReader(process.getErrorStream())); -+ * l = null; -+ * while ((l = pOut.readLine()) != null) { -+ * System.out.println(l); -+ * } -+ **/ -+ return false; -+ } -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } catch (InterruptedException e) { -+ Thread.currentThread().interrupt(); -+ } -+ return false; -+ } -+ -+ public static String SpecialURLDecode(String s) { -+ if (s == null) -+ return null; -+ ByteArrayOutputStream out = new ByteArrayOutputStream(s.length()); -+ -+ for (int i = 0; i < s.length(); i++) { -+ int c = 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 byte[] SpecialDecode(String s) { -+ if (s == null) -+ return null; -+ ByteArrayOutputStream out = new ByteArrayOutputStream(s.length()); -+ -+ for (int i = 0; i < s.length(); i++) { -+ int c = 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.toByteArray(); -+ } -+ -+ public static String SpecialEncode(byte data[]) { -+ StringBuffer sb = new StringBuffer(); -+ for (int i = 0; i < data.length; i++) { -+ sb.append("%"); -+ if ((data[i] & 0xff) < 16) { -+ sb.append("0"); -+ } -+ sb.append(Integer.toHexString((data[i] & 0xff))); -+ } -+ return sb.toString().toUpperCase(); -+ } -+ -+ public static void checkHost(String hostname) throws UnknownHostException { -+ InetAddress.getByName(hostname); -+ } -+ -+ public static void copy(String orig, String dest) throws Exception { -+ BufferedReader in = null; -+ PrintWriter out = null; -+ try { -+ in = new BufferedReader(new FileReader(orig)); -+ out = new PrintWriter( -+ new BufferedWriter(new FileWriter(dest))); -+ String line = ""; -+ while (in.ready()) { -+ line = in.readLine(); -+ if (line != null) -+ out.println(line); -+ } -+ } catch (Exception ee) { -+ ee.printStackTrace(); -+ throw ee; -+ } finally { -+ if (in != null) { -+ try { -+ in.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ if (out != null) { -+ out.close(); -+ } -+ } -+ } -+ -+ public static void copyStream(InputStream in, OutputStream out) throws IOException { -+ byte[] buf = new byte[4096]; -+ int len; -+ -+ while ((len = in.read(buf)) != -1) { -+ out.write(buf, 0, len); -+ } -+ } -+ -+ public static void copyStream(BufferedReader in, OutputStreamWriter out) throws IOException { -+ char[] buf = new char[4096]; -+ int len; -+ -+ while ((len = in.read(buf)) != -1) { -+ out.write(buf, 0, len); -+ } -+ } -+ -+ /// Sorts an array of Strings. -+ // Java currently has no general sort function. Sorting Strings is -+ // common enough that it's worth making a special case. -+ public static void sortStrings(String[] strings) { -+ // Just does a bubblesort. -+ for (int i = 0; i < strings.length - 1; ++i) { -+ for (int j = i + 1; j < strings.length; ++j) { -+ if (strings[i].compareTo(strings[j]) > 0) { -+ String t = strings[i]; -+ -+ strings[i] = strings[j]; -+ strings[j] = t; -+ } -+ } -+ } -+ } -+ -+ /// Returns a date string formatted in Unix ls style - if it's within -+ // six months of now, Mmm dd hh:ss, else Mmm dd yyyy. -+ public static String lsDateStr(Date date) { -+ long dateTime = date.getTime(); -+ -+ if (dateTime == -1L) -+ return "------------"; -+ long nowTime = System.currentTimeMillis(); -+ SimpleDateFormat formatter = new SimpleDateFormat(); -+ -+ if (Math.abs(nowTime - dateTime) < 183L * 24L * 60L * 60L * 1000L) -+ formatter.applyPattern("MMM dd hh:ss"); -+ else -+ formatter.applyPattern("MMM dd yyyy"); -+ return formatter.format(date); -+ } -+ -+ /** -+ * compares contents two byte arrays returning true if exactly same. -+ */ -+ static public boolean byteArraysAreEqual(byte[] a, byte[] b) { -+ if (a.length != b.length) -+ return false; -+ for (int i = 0; i < a.length; i++) { -+ if (a[i] != b[i]) -+ return false; -+ } -+ return true; -+ } -+ -+ /** -+ * strips out double quotes around String parameter -+ * -+ * @param s the string potentially bracketed with double quotes -+ * @return string stripped of surrounding double quotes -+ */ -+ public static String stripQuotes(String s) { -+ if (s == null) { -+ return s; -+ } -+ -+ if ((s.startsWith("\"")) && (s.endsWith("\""))) { -+ return (s.substring(1, (s.length() - 1))); -+ } -+ -+ return s; -+ } -+ -+ /** -+ * returns an array of strings from a vector of Strings -+ * there'll be trouble if the Vector contains something other -+ * than just Strings -+ */ -+ public static String[] getStringArrayFromVector(Vector v) { -+ String s[] = new String[v.size()]; -+ -+ v.copyInto(s); -+ return s; -+ } -+ -+ /** -+ * Converts a byte array into a Base-64 encoded string. -+ * If the chunked option is true, the output will be split into -+ * multiple lines. Otherwise, the output will be a single line. -+ * -+ * @param bytes byte array -+ * @param chunked generate chunked output -+ * @return base-64 encoded data -+ */ -+ public static String base64encode(byte[] bytes, boolean chunked) { -+ if (chunked) { -+ return base64encodeMultiLine(bytes); -+ } else { -+ return base64encodeSingleLine(bytes); -+ } -+ } -+ -+ /** -+ * Converts a byte array into a multi-line Base-64 encoded string. -+ * Each line is at most 64-character long and terminated with CRLF. -+ * -+ * @param bytes byte array -+ * @param chunked TODO -+ * @return base-64 encoded data -+ */ -+ public static String base64encodeMultiLine(byte[] bytes) { -+ return new Base64(64).encodeToString(bytes); -+ } -+ -+ -+ /** -+ * Converts a byte array into a single-line Base-64 encoded string. -+ * The line is not terminated with CRLF. -+ * -+ * @param bytes byte array -+ * @return base-64 encoded data -+ */ -+ public static String base64encodeSingleLine(byte[] bytes) { -+ return new Base64().encodeToString(bytes); -+ } -+ -+ /** -+ * Converts a Base-64 encoded string into a byte array. -+ * -+ * @param string base-64 encoded data -+ * @return byte array -+ */ -+ public static byte[] base64decode(String string) { -+ return Base64.decodeBase64(string); -+ } -+ -+ /** -+ * Normalize B64 input String -+ * -+ * @pram string base-64 string -+ * @return normalized string -+ */ -+ public static String normalizeString(String string) { -+ if (string == null) { -+ return string; -+ } -+ -+ StringBuffer sb = new StringBuffer(); -+ StringTokenizer st = new StringTokenizer(string, "\r\n "); -+ -+ while (st.hasMoreTokens()) { -+ String nextLine = st.nextToken(); -+ nextLine = nextLine.trim(); -+ sb.append(nextLine); -+ } -+ return sb.toString(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/util/manifest.mn b/org/mozilla/jss/netscape/security/util/manifest.mn -new file mode 100644 -index 00000000..995d2082 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/util/manifest.mn -@@ -0,0 +1,9 @@ -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+CORE_DEPTH = ../../../../../.. -+ -+PACKAGE = org/mozilla/jss/netscape/security/util -+MODULE = jss -diff --git a/org/mozilla/jss/netscape/security/x509/ACertAttrSet.java b/org/mozilla/jss/netscape/security/x509/ACertAttrSet.java -new file mode 100755 -index 00000000..34598a41 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/ACertAttrSet.java -@@ -0,0 +1,141 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * A plain certattr set used by pkcs10 to parse an unknown attribute. -+ * -+ * @author Lily Hsiao -+ */ -+public class ACertAttrSet implements CertAttrSet { -+ -+ protected DerValue mDerValue = null; -+ -+ public ACertAttrSet(DerValue derValue) throws IOException { -+ mDerValue = derValue; -+ } -+ -+ public DerValue getDerValue() { -+ return mDerValue; -+ } -+ -+ /** -+ * Returns a short string describing this certificate attribute. -+ * -+ * @return value of this certificate attribute in -+ * printable form. -+ */ -+ public String toString() { -+ return "ACertAttrSet value " + (mDerValue == null ? "null" : "not null"); -+ } -+ -+ /** -+ * Encodes the attribute to the output stream in a format -+ * that can be parsed by the decode method. -+ * -+ * @param out the OutputStream to encode the attribute to. -+ * -+ * @exception CertificateException on encoding or validity errors. -+ * @exception IOException on other errors. -+ */ -+ public void encode(OutputStream out) -+ throws CertificateException, IOException { -+ mDerValue.encode((DerOutputStream) out); -+ } -+ -+ /** -+ * Decodes the attribute in the input stream. -+ * -+ * @param in the InputStream to read the encoded attribute from. -+ * -+ * @exception CertificateException on decoding or validity errors. -+ * @exception IOException on other errors. -+ */ -+ public void decode(InputStream in) -+ throws CertificateException, IOException { -+ throw new IOException("not supported"); -+ } -+ -+ /** -+ * Sets an attribute value within this CertAttrSet. -+ * -+ * @param name the name of the attribute (e.g. "x509.info.key") -+ * @param obj the attribute object. -+ * -+ * @exception CertificateException on attribute handling errors. -+ * @exception IOException on other errors. -+ */ -+ public void set(String name, Object obj) -+ throws CertificateException, IOException { -+ throw new IOException("not supported"); -+ } -+ -+ /** -+ * Gets an attribute value for this CertAttrSet. -+ * -+ * @param name the name of the attribute to return. -+ * -+ * @exception CertificateException on attribute handling errors. -+ * @exception IOException on other errors. -+ */ -+ public Object get(String name) -+ throws CertificateException, IOException { -+ throw new IOException("not supported"); -+ } -+ -+ /** -+ * Deletes an attribute value from this CertAttrSet. -+ * -+ * @param name the name of the attribute to delete. -+ * -+ * @exception CertificateException on attribute handling errors. -+ * @exception IOException on other errors. -+ */ -+ public void delete(String name) -+ throws CertificateException, IOException { -+ throw new IOException("not supported"); -+ } -+ -+ /** -+ * Returns an enumeration of the names of the attributes existing within -+ * this attribute. -+ * -+ * @return an enumeration of the attribute names. -+ */ -+ public Enumeration getAttributeNames() { -+ return null; -+ } -+ -+ /** -+ * Returns the name (identifier) of this CertAttrSet. -+ * -+ * @return the name of this CertAttrSet. -+ */ -+ public String getName() { -+ return "Generic Extension"; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/AVA.java b/org/mozilla/jss/netscape/security/x509/AVA.java -new file mode 100644 -index 00000000..d3c76126 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/AVA.java -@@ -0,0 +1,311 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetDecoder; -+import java.nio.charset.UnsupportedCharsetException; -+ -+import org.mozilla.jss.netscape.security.util.DerEncoder; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * X.500 Attribute-Value-Assertion (AVA): an attribute, as identified by -+ * some attribute ID, has some particular value. Values are as a rule ASN.1 -+ * printable strings. A conventional set of type IDs is recognized when -+ * parsing (and generating) RFC 1779 syntax strings. -+ * -+ *

-+ * AVAs are components of X.500 relative names. Think of them as being individual fields of a database record. The -+ * attribute ID is how you identify the field, and the value is part of a particular record. -+ * -+ * @see X500Name -+ * @see RDN -+ * @see LdapDNStrConverter -+ * -+ * @version 1.14 -+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+// public ... when RDN is public and X.500Names can be -+// constructed using RDNs, and all three classes are cleaner -+public final class AVA implements DerEncoder { -+ ObjectIdentifier oid; -+ DerValue value; -+ -+ /** -+ * Constructs an AVA from a Ldap DN string with one AVA component -+ * using the global default LdapDNStrConverter. -+ * -+ * @see LdapDNStrConverter -+ * @param avaString a Ldap DN string with one AVA component. -+ */ -+ public AVA(String avaString) -+ throws IOException { -+ AVA ava; -+ ava = LdapDNStrConverter.getDefault().parseAVA(avaString); -+ oid = ava.getOid(); -+ value = ava.getValue(); -+ } -+ -+ /** -+ * Like AVA(String) with a DER encoding order given for Directory Strings. -+ */ -+ public AVA(String avaString, byte[] tags) -+ throws IOException { -+ AVA ava; -+ ava = LdapDNStrConverter.getDefault().parseAVA(avaString, tags); -+ oid = ava.getOid(); -+ value = ava.getValue(); -+ } -+ -+ /** -+ * Constructs an AVA from a Ldap DN string containing one AVA -+ * component using the specified LdapDNStrConverter. -+ * -+ * @see LdapDNStrConverter -+ * @param avaString a Ldap DN string containing one AVA. -+ * @param ldapDNStrConverter a LdapDNStrConverter -+ */ -+ public AVA(String avaString, LdapDNStrConverter ldapDNStrConverter) -+ throws IOException { -+ AVA ava; -+ ava = ldapDNStrConverter.parseAVA(avaString); -+ oid = ava.getOid(); -+ value = ava.getValue(); -+ } -+ -+ /** -+ * Constructs an AVA from an OID and DerValue. -+ * -+ * @param type an ObjectIdentifier -+ * @param val a DerValue -+ */ -+ public AVA(ObjectIdentifier type, DerValue val) -+ throws IOException { -+ oid = type; -+ value = val; -+ } -+ -+ /** -+ * Constructs an AVA from an input stream of UTF8 bytes that form -+ * a Ldap DN string. Then parse the Ldap DN string using the global -+ * default LdapDNStrConverter.
-+ * Parses an RFC 1779 style AVA string: CN=fee fie foe fum -+ * or perhaps with quotes. Not all defined AVA tags are supported; -+ * of current note are X.400 related ones (PRMD, ADMD, etc). -+ * -+ * This terminates at unescaped AVA separators ("+") or RDN -+ * separators (",", ";"), or DN terminators (">"), and removes -+ * cosmetic whitespace at the end of values. -+ * -+ * @see LdapDNStrConverter -+ * @param in the input stream. -+ */ -+ public AVA(InputStream in) throws IOException { -+ try { -+ // convert from UTF8 bytes to java string then parse it. -+ byte[] buffer = new byte[in.available()]; -+ in.read(buffer); -+ -+ Charset charset = Charset.forName("UTF-8"); -+ CharsetDecoder decoder = charset.newDecoder(); -+ -+ CharBuffer charBuffer = decoder.decode(ByteBuffer.wrap(buffer)); -+ -+ AVA a = LdapDNStrConverter.getDefault().parseAVA(charBuffer.toString()); -+ oid = a.getOid(); -+ value = a.getValue(); -+ -+ } catch (UnsupportedCharsetException e) { -+ throw new IOException("UTF8 encoding not supported", e); -+ } -+ } -+ -+ /** -+ * Constructs an AVA from a Der Input Stream. -+ * -+ * @param in the Der Input Stream. -+ */ -+ public AVA(DerInputStream in) throws IOException { -+ DerValue assertion = in.getDerValue(); -+ -+ /* -+ * Individual attribute value assertions are SEQUENCE of two values. -+ * That'd be a "struct" outside of ASN.1. -+ */ -+ if (assertion.tag != DerValue.tag_Sequence) -+ throw new CertParseError("X500 AVA, not a sequence"); -+ -+ ObjectIdentifier o = assertion.data.getOID(); -+ oid = X500NameAttrMap.getDefault().getOid(o); -+ if (oid == null) { -+ // NSCP #329837 -+ // if this OID is not recongized in our map (table), -+ // it is fine. we just store it as regular OID. -+ oid = o; -+ } -+ value = assertion.data.getDerValue(); -+ -+ if (assertion.data.available() != 0) -+ throw new CertParseError("AVA, extra bytes = " -+ + assertion.data.available()); -+ } -+ -+ // other public methods. -+ -+ /** -+ * Returns true if another AVA has the same OID and DerValue. -+ * -+ * @param other the other AVA. -+ * @return ture iff other AVA has same oid and value. -+ */ -+ public boolean equals(AVA other) { -+ return oid.equals(other.oid) && value.equals(other.value); -+ } -+ -+ /** -+ * Compares the AVA with an Object, returns true if the object is -+ * an AVA and has the same OID and value. -+ * -+ * @param other the other object. -+ * @return true iff other object is an AVA and has same oid and value. -+ */ -+ public boolean equals(Object other) { -+ if (other instanceof AVA) -+ return equals((AVA) other); -+ else -+ return false; -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + ((oid == null) ? 0 : oid.hashCode()); -+ result = prime * result + ((value == null) ? 0 : value.hashCode()); -+ return result; -+ } -+ -+ /** -+ * Encodes the AVA to a Der output stream. -+ * AVAs are encoded as a SEQUENCE of two elements. -+ * -+ * @param out The Der output stream. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ derEncode(out); -+ } -+ -+ /** -+ * DER encode this object onto an output stream. -+ * Implements the DerEncoder interface. -+ * -+ * @param out -+ * the output stream on which to write the DER encoding. -+ * -+ * @exception IOException on encoding error. -+ */ -+ public void derEncode(OutputStream out) throws IOException { -+ try (DerOutputStream tmp2 = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ tmp.putOID(oid); -+ value.encode(tmp); -+ tmp2.write(DerValue.tag_Sequence, tmp); -+ out.write(tmp2.toByteArray()); -+ } -+ } -+ -+ /** -+ * Returns a Ldap DN string with one AVA component using -+ * the global default LdapDNStrConverter. -+ * -+ * @return a Ldap DN string -+ * @exception IOException if an error occurs during conversion. -+ * @see LdapDNStrConverter -+ */ -+ public String toLdapDNString() -+ throws IOException { -+ LdapDNStrConverter v = LdapDNStrConverter.getDefault(); -+ return v.encodeAVA(this); -+ } -+ -+ /** -+ * Returns a Ldap DN string with one AVA component using the specified -+ * LdapDNStrConverter. -+ * -+ * @return a Ldap DN string -+ * @param ldapDNStrConverter a Ldap DN String Converter -+ * @exception IOException if an error occurs during the conversion. -+ * @see LdapDNStrConverter -+ */ -+ public String toLdapDNString(LdapDNStrConverter ldapDNStrConverter) -+ throws IOException { -+ return ldapDNStrConverter.encodeAVA(this); -+ } -+ -+ /** -+ * Returns a Ldap DN string with the AVA component using the global -+ * default LdapDNStrConverter, or null if an error occurs in conversion. -+ * -+ * @return a Ldap DN string containing the AVA, or null if an -+ * error occurs in the conversion. -+ */ -+ public String toString() { -+ String s; -+ try { -+ // NOTE that a LdapDNString is returned here to match the -+ // original source from sun. Could also return the raw value -+ // (before Ldap escaping) here. -+ s = toLdapDNString(); -+ } catch (IOException e) { -+ return null; -+ } -+ return s; -+ } -+ -+ /** -+ * Returns the OID in the AVA. -+ * -+ * @return the ObjectIdentifier in this AVA. -+ */ -+ public ObjectIdentifier getOid() { -+ return oid; -+ } -+ -+ /** -+ * Returns the value in this AVA as a DerValue -+ * -+ * @return attribute value in this AVA. -+ */ -+ public DerValue getValue() { -+ return value; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/AVAValueConverter.java b/org/mozilla/jss/netscape/security/x509/AVAValueConverter.java -new file mode 100644 -index 00000000..3438cb88 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/AVAValueConverter.java -@@ -0,0 +1,86 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Interface for classes that convert a attribute value string to a -+ * DER encoded ASN.1 value and vice versa. -+ * The converters are associated with attribute types, such as -+ * directory string, ia5string, etc. -+ * -+ *

-+ * For example, to convert a string, such as an organization name for the "O" attribute to a DerValue, the "O" attribute -+ * is mapped to the DirStrConverter which is used to convert the organization name to a DER encoded Directory String -+ * which is a DerValue of a ASN.1 PrintableString, T.61String or UniversalString for the organization name. -+ * -+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc. -+ */ -+ -+public interface AVAValueConverter { -+ /** -+ * Converts a string to a DER encoded attribute value. -+ * -+ * @param valueString An AVA value string not encoded in any form. -+ * -+ * @return A DerValue object. -+ * -+ * @exception IOException if an error occurs during the conversion. -+ */ -+ public DerValue getValue(String valueString) -+ throws IOException; -+ -+ /** -+ * Converts a string to a DER encoded attribute value. -+ * Specify the order of DER tags to use if more than one encoding is -+ * possible. Currently Directory Strings can have different order -+ * for backwards compatibility. By 2003 all should be UTF8String. -+ * -+ * @param valueString An AVA value string not encoded in any form. -+ * -+ * @return A DerValue object. -+ * -+ * @exception IOException if an error occurs during the conversion. -+ */ -+ public DerValue getValue(String valueString, byte[] tags) -+ throws IOException; -+ -+ /** -+ * Converts a BER encoded value to a DER encoded attribute value. -+ * -+ * @param berStream A byte array of the BER encoded AVA value. -+ * @return A DerValue object. -+ */ -+ public DerValue getValue(byte[] berStream) -+ throws IOException; -+ -+ /** -+ * Converts a DER encoded value to a string, not encoded in any form. -+ * -+ * @param avaValue A DerValue object. -+ * -+ * @return A string for the value or null if it can't be converted. -+ * -+ * @exception IOException if an error occurs during the conversion. -+ */ -+ public String getAsString(DerValue avaValue) -+ throws IOException; -+} -diff --git a/org/mozilla/jss/netscape/security/x509/AlgIdDSA.java b/org/mozilla/jss/netscape/security/x509/AlgIdDSA.java -new file mode 100644 -index 00000000..c706209f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/AlgIdDSA.java -@@ -0,0 +1,215 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.math.BigInteger; -+import java.security.ProviderException; -+import java.security.interfaces.DSAParams; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class identifies DSS/DSA Algorithm variants, which are distinguished -+ * by using different algorithm parameters P, Q, G. It uses the -+ * NIST/IETF standard DER encoding. These are used to implement the Digital -+ * Signature Standard (DSS), FIPS 186. -+ * -+ *

-+ * NOTE: At this time, DSS/DSA Algorithm IDs must always -+ * include these parameters. Use of DSS/DSA in modes where parameters are -+ * either implicit (e.g. a default applicable to a site or a larger scope), -+ * or are derived from some Certificate Authority's DSS certificate, is -+ * not currently supported. -+ * -+ * @version 1.31 -+ * @author David Brownell -+ */ -+public final class AlgIdDSA extends AlgorithmId implements DSAParams { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 5978220691806461631L; -+ /* -+ * The three unsigned integer parameters. -+ */ -+ private BigInteger p, q, g; -+ -+ /** Returns the DSS/DSA parameter "P" */ -+ public BigInteger getP() { -+ return p; -+ } -+ -+ /** Returns the DSS/DSA parameter "Q" */ -+ public BigInteger getQ() { -+ return q; -+ } -+ -+ /** Returns the DSS/DSA parameter "G" */ -+ public BigInteger getG() { -+ return g; -+ } -+ -+ AlgIdDSA(DerValue val) throws IOException { -+ super(val.getOID()); -+ } -+ -+ /** -+ * Construct an AlgIdDSA from an X.509 encoded byte array. -+ */ -+ public AlgIdDSA(byte[] encodedAlg) throws IOException { -+ super(new DerValue(encodedAlg).getOID()); -+ } -+ -+ /** -+ * Constructs a DSS/DSA Algorithm ID from unsigned integers that -+ * define the algorithm parameters. Those integers are encoded -+ * as big-endian byte arrays. -+ * -+ * @param p the DSS/DSA paramter "P" -+ * @param q the DSS/DSA paramter "Q" -+ * @param g the DSS/DSA paramter "G" -+ */ -+ public AlgIdDSA(byte p[], byte q[], byte g[]) -+ throws IOException { -+ this(new BigInteger(1, p), -+ new BigInteger(1, q), -+ new BigInteger(1, g)); -+ } -+ -+ /** -+ * Constructs a DSS/DSA Algorithm ID from numeric parameters. -+ * -+ * @param p the DSS/DSA paramter "P" -+ * @param q the DSS/DSA paramter "Q" -+ * @param g the DSS/DSA paramter "G" -+ */ -+ public AlgIdDSA(BigInteger p, BigInteger q, BigInteger g) { -+ super(DSA_oid); -+ -+ try { -+ this.p = p; -+ this.q = q; -+ this.g = g; -+ initializeParams(); -+ -+ } catch (IOException e) { -+ /* this should not happen */ -+ throw new ProviderException("Construct DSS/DSA Algorithm ID"); -+ } -+ } -+ -+ /** -+ * Returns "DSA", indicating the Digital Signature Algorithm (DSA) as -+ * defined by the Digital Signature Standard (DSS), FIPS 186. -+ */ -+ public String getName() { -+ return "DSA"; -+ } -+ -+ /* -+ * For algorithm IDs which haven't been created from a DER encoded -+ * value, "params" must be created. -+ */ -+ private void initializeParams() -+ throws IOException { -+ try (DerOutputStream out = new DerOutputStream()) { -+ out.putInteger(new BigInt(p.toByteArray())); -+ out.putInteger(new BigInt(q.toByteArray())); -+ out.putInteger(new BigInt(g.toByteArray())); -+ params = new DerValue(DerValue.tag_Sequence, out.toByteArray()); -+ } -+ } -+ -+ /** -+ * Parses algorithm parameters P, Q, and G. They're found -+ * in the "params" member, which never needs to be changed. -+ */ -+ protected void decodeParams() -+ throws IOException { -+ if (params == null || params.tag != DerValue.tag_Sequence) -+ throw new IOException("DSA alg parsing error"); -+ -+ params.data.reset(); -+ -+ this.p = params.data.getInteger().toBigInteger(); -+ this.q = params.data.getInteger().toBigInteger(); -+ this.g = params.data.getInteger().toBigInteger(); -+ -+ if (params.data.available() != 0) -+ throw new IOException("AlgIdDSA params, extra=" + -+ params.data.available()); -+ } -+ -+ /* -+ * Returns a formatted string describing the parameters. -+ */ -+ public String toString() { -+ return paramsToString(); -+ } -+ -+ /* -+ * Returns a string describing the parameters. -+ */ -+ protected String paramsToString() { -+ return "\n p:\n" + (new BigInt(p)).toString() + -+ "\n q:\n" + (new BigInt(q)).toString() + -+ "\n g:\n" + (new BigInt(g)).toString() + -+ "\n"; -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + ((g == null) ? 0 : g.hashCode()); -+ result = prime * result + ((p == null) ? 0 : p.hashCode()); -+ result = prime * result + ((q == null) ? 0 : q.hashCode()); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (!super.equals(obj)) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ AlgIdDSA other = (AlgIdDSA) obj; -+ if (g == null) { -+ if (other.g != null) -+ return false; -+ } else if (!g.equals(other.g)) -+ return false; -+ if (p == null) { -+ if (other.p != null) -+ return false; -+ } else if (!p.equals(other.p)) -+ return false; -+ if (q == null) { -+ if (other.q != null) -+ return false; -+ } else if (!q.equals(other.q)) -+ return false; -+ return true; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/AlgorithmId.java b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java -new file mode 100644 -index 00000000..5ea7f5e5 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java -@@ -0,0 +1,805 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.security.AlgorithmParameters; -+import java.security.NoSuchAlgorithmException; -+ -+import org.mozilla.jss.netscape.security.util.DerEncoder; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * This class identifies algorithms, such as cryptographic transforms, each -+ * of which may be associated with parameters. Instances of this base class -+ * are used when this runtime environment has no special knowledge of the -+ * algorithm type, and may also be used in other cases. Equivalence is -+ * defined according to OID and (where relevant) parameters. -+ * -+ *

-+ * Subclasses may be used, for example when when the algorithm ID has associated parameters which some code (e.g. code -+ * using public keys) needs to have parsed. Two examples of such algorithms are Diffie-Hellman key exchange, and the -+ * Digital Signature Standard Algorithm (DSS/DSA). -+ * -+ *

-+ * The OID constants defined in this class correspond to some widely used algorithms, for which conventional string -+ * names have been defined. This class is not a general repository for OIDs, or for such string names. Note that the -+ * mappings between algorithm IDs and algorithm names is not one-to-one. -+ * -+ * @version 1.70 -+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class AlgorithmId implements Serializable, DerEncoder { -+ -+ /** use serialVersionUID from JDK 1.1. for interoperability */ -+ private static final long serialVersionUID = 7205873507486557157L; -+ -+ /** -+ * The object identitifer being used for this algorithm. -+ */ -+ private ObjectIdentifier algid = null; -+ -+ // The (parsed) parameters -+ private AlgorithmParameters algParams; -+ -+ /** -+ * Parameters for this algorithm. These are stored in unparsed -+ * DER-encoded form; subclasses can be made to automaticaly parse -+ * them so there is fast access to these parameters. -+ */ -+ protected DerValue params = null; -+ -+ protected String paramsString = null; -+ -+ public AlgorithmParameters getParameters() { -+ return this.algParams; -+ } -+ -+ public String getParametersString() { -+ return this.paramsString; -+ } -+ -+ public void setParametersString(String paramStr) { -+ -+ this.paramsString = paramStr; -+ } -+ -+ /** -+ * Returns one of the algorithm IDs most commonly associated -+ * with this algorithm name. -+ * -+ * @param algname the name being used -+ * @exception NoSuchAlgorithmException on error. -+ */ -+ public static AlgorithmId get(String algname) -+ throws NoSuchAlgorithmException { -+ ObjectIdentifier oid = algOID(algname); -+ -+ if (oid == null) -+ throw new NoSuchAlgorithmException("unrecognized algorithm name: " + algname); -+ -+ return new AlgorithmId(oid); -+ } -+ -+ /** -+ * Parse (unmarshal) an ID from a DER sequence input value. This form -+ * parsing might be used when expanding a value which has already been -+ * partially unmarshaled as a set or sequence member. -+ * -+ * @exception IOException on error. -+ * @param val the input value, which contains the algid and, if -+ * there are any parameters, those parameters. -+ * @return an ID for the algorithm. If the system is configured -+ * appropriately, this may be an instance of a class -+ * with some kind of special support for this algorithm. -+ * In that case, you may "narrow" the type of the ID. -+ */ -+ public static AlgorithmId parse(DerValue val) -+ throws IOException { -+ if (val.tag != DerValue.tag_Sequence) -+ throw new IOException("algid parse error, not a sequence"); -+ -+ /* -+ * Get the algorithm ID and any parameters. -+ */ -+ ObjectIdentifier algid; -+ DerValue params; -+ DerInputStream in = val.toDerInputStream(); -+ -+ algid = in.getOID(); -+ if (in.available() == 0) -+ params = null; -+ else { -+ params = in.getDerValue(); -+ if (params.tag == DerValue.tag_Null) -+ params = null; -+ } -+ -+ /* -+ * Figure out what class (if any) knows about this oid's -+ * parameters. Make one, and give it the data to decode. -+ */ -+ AlgorithmId alg = new AlgorithmId(algid, params); -+ if (params != null) -+ alg.decodeParams(); -+ -+ /* -+ * Set the raw params string in case -+ * higher level code might want the info -+ */ -+ -+ String paramStr = null; -+ -+ if (params != null) { -+ paramStr = params.toString(); -+ } -+ -+ alg.setParametersString(paramStr); -+ -+ return alg; -+ } -+ -+ public static AlgorithmId parse(byte[] val) -+ throws IOException { -+ return null; -+ } -+ -+ /** -+ * Constructs a parameterless algorithm ID. -+ * -+ * @param oid the identifier for the algorithm -+ */ -+ public AlgorithmId(ObjectIdentifier oid) { -+ algid = oid; -+ } -+ -+ private AlgorithmId(ObjectIdentifier oid, DerValue params) -+ throws IOException { -+ this.algid = oid; -+ this.params = params; -+ if (this.params != null) -+ decodeParams(); -+ } -+ -+ /** -+ * Constructs an algorithm ID which will be initialized -+ * separately, for example by deserialization. -+ * -+ * @deprecated use one of the other constructors. -+ */ -+ public AlgorithmId() { -+ } -+ -+ protected void decodeParams() throws IOException { -+ try { -+ this.algParams = AlgorithmParameters.getInstance -+ (this.algid.toString()); -+ } catch (NoSuchAlgorithmException e) { -+ /* -+ * This algorithm parameter type is not supported, so we cannot -+ * parse the parameters. -+ */ -+ this.algParams = null; -+ return; -+ } -+ // Decode (parse) the parameters -+ this.algParams.init(this.params.toByteArray()); -+ } -+ -+ /** -+ * Marshal a DER-encoded "AlgorithmID" sequence on the DER stream. -+ */ -+ public final void encode(DerOutputStream out) -+ throws IOException { -+ derEncode(out); -+ } -+ -+ /** -+ * DER encode this object onto an output stream. -+ * Implements the DerEncoder interface. -+ * -+ * @param out -+ * the output stream on which to write the DER encoding. -+ * -+ * @exception IOException on encoding error. -+ */ -+ public void derEncode(OutputStream out) throws IOException { -+ try (DerOutputStream tmp = new DerOutputStream()) { -+ DerOutputStream bytes = new DerOutputStream(); -+ bytes.putOID(algid); -+ -+ // omit parameter field for ECDSA -+ if (!algid.equals(sha224WithEC_oid) && -+ !algid.equals(sha256WithEC_oid) && -+ !algid.equals(sha384WithEC_oid) && -+ !algid.equals(sha512WithEC_oid)) { -+ if (params == null) { -+ bytes.putNull(); -+ } else -+ bytes.putDerValue(params); -+ } -+ -+ tmp.write(DerValue.tag_Sequence, bytes); -+ out.write(tmp.toByteArray()); -+ } -+ } -+ -+ // XXXX cleaning required -+ /** -+ * Returns the DER-encoded X.509 AlgorithmId as a byte array. -+ */ -+ public final byte[] encode() throws IOException { -+ try (DerOutputStream out = new DerOutputStream()) { -+ DerOutputStream bytes = new DerOutputStream(); -+ bytes.putOID(algid); -+ -+ // omit parameter field for ECDSA -+ if (!algid.equals(sha224WithEC_oid) && -+ !algid.equals(sha256WithEC_oid) && -+ !algid.equals(sha384WithEC_oid) && -+ !algid.equals(sha512WithEC_oid)) { -+ if (params == null) { -+ bytes.putNull(); -+ } else -+ bytes.putDerValue(params); -+ } -+ -+ out.write(DerValue.tag_Sequence, bytes); -+ return out.toByteArray(); -+ } -+ } -+ -+ /** -+ * Returns list of signing algorithms for a key algorithm such as -+ * RSA or DSA. -+ */ -+ public static String[] getSigningAlgorithms(AlgorithmId alg) { -+ ObjectIdentifier algOid = alg.getOID(); -+ //System.out.println("Key Alg oid "+algOid.toString()); -+ if (algOid.equals(DSA_oid) || algOid.equals(DSA_OIW_oid)) { -+ return DSA_SIGNING_ALGORITHMS; -+ } else if (algOid.equals(RSA_oid) || algOid.equals(RSAEncryption_oid)) { -+ return RSA_SIGNING_ALGORITHMS; -+ } else if (algOid.equals(ANSIX962_EC_Public_Key_oid) || algOid.equals(ANSIX962_SHA1_With_EC_oid)) { -+ return EC_SIGNING_ALGORITHMS; -+ } else { -+ return null; -+ } -+ } -+ -+ /* -+ * Translates from some common algorithm names to the -+ * OID with which they're usually associated ... this mapping -+ * is the reverse of the one below, except in those cases -+ * where synonyms are supported or where a given algorithm -+ * is commonly associated with multiple OIDs. -+ */ -+ private static ObjectIdentifier algOID(String name) { -+ // Digesting algorithms -+ -+ if (name.equals("MD5")) -+ return AlgorithmId.MD5_oid; -+ if (name.equals("MD2")) -+ return AlgorithmId.MD2_oid; -+ if (name.equals("SHA") || name.equals("SHA1") -+ || name.equals("SHA-1")) -+ return AlgorithmId.SHA_oid; -+ if (name.equals("SHA256") || name.equals("SHA-256")) -+ return AlgorithmId.SHA256_oid; -+ if (name.equals("SHA512") || name.equals("SHA-512")) -+ return AlgorithmId.SHA512_oid; -+ -+ // Various public key algorithms -+ -+ if (name.equals("RSA")) -+ return AlgorithmId.RSA_oid; -+ -+ if (name.equals("RSAEncryption")) -+ return AlgorithmId.RSAEncryption_oid; -+ if (name.equals("Diffie-Hellman") || name.equals("DH")) -+ return AlgorithmId.DH_oid; -+ if (name.equals("DSA")) -+ return AlgorithmId.DSA_oid; -+ -+ // Common signature types -+ -+ if (name.equals("SHA1withEC") || name.equals("SHA1/EC") -+ || name.equals("1.2.840.10045.4.1")) -+ return AlgorithmId.sha1WithEC_oid; -+ if (name.equals("SHA224withEC") || name.equals("SHA224/EC") -+ || name.equals("1.2.840.10045.4.3.1")) -+ return AlgorithmId.sha224WithEC_oid; -+ if (name.equals("SHA256withEC") || name.equals("SHA256/EC") -+ || name.equals("1.2.840.10045.4.3.2")) -+ return AlgorithmId.sha256WithEC_oid; -+ if (name.equals("SHA384withEC") || name.equals("SHA384/EC") -+ || name.equals("1.2.840.10045.4.3.3")) -+ return AlgorithmId.sha384WithEC_oid; -+ if (name.equals("SHA512withEC") || name.equals("SHA512/EC") -+ || name.equals("1.2.840.10045.4.3.4")) -+ return AlgorithmId.sha512WithEC_oid; -+ if (name.equals("SHA1withRSA") || name.equals("SHA1/RSA") -+ || name.equals("1.2.840.113549.1.1.5")) -+ return AlgorithmId.sha1WithRSAEncryption_oid; -+ if (name.equals("SHA256withRSA") || name.equals("SHA256/RSA") -+ || name.equals("1.2.840.113549.1.1.11")) -+ return AlgorithmId.sha256WithRSAEncryption_oid; -+ if (name.equals("SHA384withRSA") || name.equals("SHA384/RSA") -+ || name.equals("1.2.840.113549.1.1.12")) -+ return AlgorithmId.sha384WithRSAEncryption_oid; -+ if (name.equals("SHA512withRSA") || name.equals("SHA512/RSA") -+ || name.equals("1.2.840.113549.1.1.13")) -+ return AlgorithmId.sha512WithRSAEncryption_oid; -+ if (name.equals("MD5withRSA") || name.equals("MD5/RSA")) -+ return AlgorithmId.md5WithRSAEncryption_oid; -+ if (name.equals("MD2withRSA") || name.equals("MD2/RSA")) -+ return AlgorithmId.md2WithRSAEncryption_oid; -+ if (name.equals("SHAwithDSA") || name.equals("SHA1withDSA") -+ || name.equals("SHA/DSA") || name.equals("SHA1/DSA")) -+ return AlgorithmId.sha1WithDSA_oid; -+ -+ return null; -+ } -+ -+ /* -+ * For the inevitable cases where key or signature types are not -+ * configured in an environment which encounters such keys or -+ * signatures, we still attempt to provide user-friendly names -+ * for some of the most common algorithms. Subclasses can of -+ * course override getName(). -+ * -+ * Wherever possible, the names are those defined by the IETF. -+ * Such names are noted below. -+ */ -+ private String algName() { -+ // Common message digest algorithms -+ -+ if (algid.equals(AlgorithmId.MD5_oid)) -+ return "MD5"; // RFC 1423 -+ if (algid.equals(AlgorithmId.MD2_oid)) -+ return "MD2"; // RFC 1423 -+ if (algid.equals(AlgorithmId.SHA_oid)) -+ return "SHA"; -+ if (algid.equals(AlgorithmId.SHA256_oid)) -+ return "SHA256"; -+ if (algid.equals(AlgorithmId.SHA384_oid)) -+ return "SHA384"; -+ if (algid.equals(AlgorithmId.SHA512_oid)) -+ return "SHA512"; -+ -+ // Common key types -+ -+ if (algid.equals(AlgorithmId.ANSIX962_EC_Public_Key_oid)) -+ return "EC"; -+ if (algid.equals(AlgorithmId.RSAEncryption_oid) -+ || algid.equals(AlgorithmId.RSA_oid)) -+ return "RSA"; -+ if (algid.equals(AlgorithmId.DH_oid) -+ || algid.equals(AlgorithmId.DH_PKIX_oid)) -+ return "Diffie-Hellman"; -+ if (algid.equals(AlgorithmId.DSA_oid) -+ || algid.equals(AlgorithmId.DSA_OIW_oid)) -+ return "DSA"; -+ -+ // Common signature types -+ -+ if (algid.equals(AlgorithmId.sha1WithEC_oid)) -+ return "SHA1withEC"; -+ if (algid.equals(AlgorithmId.sha256WithEC_oid)) -+ return "SHA256withEC"; -+ if (algid.equals(AlgorithmId.sha384WithEC_oid)) -+ return "SHA384withEC"; -+ if (algid.equals(AlgorithmId.sha512WithEC_oid)) -+ return "SHA512withEC"; -+ if (algid.equals(AlgorithmId.md5WithRSAEncryption_oid)) -+ return "MD5withRSA"; -+ if (algid.equals(AlgorithmId.md2WithRSAEncryption_oid)) -+ return "MD2withRSA"; -+ if (algid.equals(AlgorithmId.sha1WithRSAEncryption_oid)) -+ return "SHA1withRSA"; -+ if (algid.equals(AlgorithmId.sha256WithRSAEncryption_oid)) -+ return "SHA256withRSA"; -+ if (algid.equals(AlgorithmId.sha384WithRSAEncryption_oid)) -+ return "SHA384withRSA"; -+ if (algid.equals(AlgorithmId.sha512WithRSAEncryption_oid)) -+ return "SHA512withRSA"; -+ if (algid.equals(AlgorithmId.sha1WithDSA_oid) -+ || algid.equals(AlgorithmId.sha1WithDSA_OIW_oid) -+ || algid.equals(AlgorithmId.shaWithDSA_OIW_oid)) -+ return "SHA1withDSA"; -+ -+ // default returns a dot-notation ID -+ -+ return "OID." + algid.toString(); -+ } -+ -+ /** -+ * Returns the ISO OID for this algorithm. This is usually converted -+ * to a string and used as part of an algorithm name, for example -+ * "OID.1.3.14.3.2.13" style notation. Use the getName call when you do not need to ensure cross-system -+ * portability -+ * of algorithm names, or need a user friendly name. -+ */ -+ final public ObjectIdentifier getOID() { -+ return algid; -+ } -+ -+ /** -+ * Returns a name for the algorithm which may be more intelligible -+ * to humans than the algorithm's OID, but which won't necessarily -+ * be comprehensible on other systems. For example, this might -+ * return a name such as "MD5withRSA" for a signature algorithm on -+ * some systems. It also returns names like "OID.1.2.3.4", when -+ * no particular name for the algorithm is known. -+ */ -+ public String getName() { -+ return algName(); -+ } -+ -+ /** -+ * Returns a string describing the algorithm and its parameters. -+ */ -+ public String toString() { -+ return (algName() + paramsToString()); -+ } -+ -+ /** -+ * Returns the DER encoded parameter, which can then be -+ * used to initialize java.security.AlgorithmParamters. -+ * -+ * @return DER encoded parameters, or null not present. -+ */ -+ public byte[] getEncodedParams() throws IOException { -+ if (params == null) -+ return null; -+ else -+ return params.toByteArray(); -+ } -+ -+ /** -+ * Provides a human-readable description of the algorithm parameters. -+ * This may be redefined by subclasses which parse those parameters. -+ */ -+ protected String paramsToString() { -+ if (params == null) { -+ return ""; -+ } else if (algParams != null) { -+ return algParams.toString(); -+ } else { -+ return ", params unparsed"; -+ } -+ } -+ -+ /** -+ * Returns true iff the argument indicates the same algorithm -+ * with the same parameters. -+ */ -+ public boolean equals(AlgorithmId other) { -+ if (!algid.equals(other.algid)) -+ return false; -+ else if (params == null && other.params == null) -+ return true; -+ else if (params == null) -+ return false; -+ else -+ return params.equals(other.params); -+ } -+ -+ /** -+ * Compares this AlgorithmID to another. If algorithm parameters are -+ * available, they are compared. Otherwise, just the object IDs -+ * for the algorithm are compared. -+ * -+ * @param other preferably an AlgorithmId, else an ObjectIdentifier -+ */ -+ public boolean equals(Object other) { -+ if (other instanceof AlgorithmId) -+ return equals((AlgorithmId) other); -+ else if (other instanceof ObjectIdentifier) -+ return equals((ObjectIdentifier) other); -+ else -+ return false; -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + ((algParams == null) ? 0 : algParams.hashCode()); -+ result = prime * result + ((algid == null) ? 0 : algid.hashCode()); -+ result = prime * result + ((params == null) ? 0 : params.hashCode()); -+ result = prime * result + ((paramsString == null) ? 0 : paramsString.hashCode()); -+ return result; -+ } -+ -+ /** -+ * Compares two algorithm IDs for equality. Returns true iff -+ * they are the same algorithm, ignoring algorithm parameters. -+ */ -+ public final boolean equals(ObjectIdentifier id) { -+ return algid.equals(id); -+ } -+ -+ -+ -+ /*****************************************************************/ -+ -+ /* -+ * HASHING ALGORITHMS -+ */ -+ private static final int MD2_data[] = { 1, 2, 840, 113549, 2, 2 }; -+ private static final int MD5_data[] = { 1, 2, 840, 113549, 2, 5 }; -+ // sha = { 1, 3, 14, 3, 2, 18 }; -+ private static final int SHA1_OIW_data[] = { 1, 3, 14, 3, 2, 26 }; -+ private static final int SHA256_data[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }; -+ private static final int SHA384_data[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 }; -+ private static final int SHA512_data[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 }; -+ -+ /** -+ * Algorithm ID for the MD2 Message Digest Algorthm, from RFC 1319. -+ * OID = 1.2.840.113549.2.2 -+ */ -+ public static final ObjectIdentifier MD2_oid = new ObjectIdentifier(MD2_data); -+ -+ /** -+ * Algorithm ID for the MD5 Message Digest Algorthm, from RFC 1321. -+ * OID = 1.2.840.113549.2.5 -+ */ -+ public static final ObjectIdentifier MD5_oid = new ObjectIdentifier(MD5_data); -+ -+ /** -+ * Algorithm ID for the SHA1 Message Digest Algorithm, from FIPS 180-1. -+ * This is sometimes called "SHA", though that is often confusing since -+ * many people refer to FIPS 180 (which has an error) as defining SHA. -+ * OID = 1.3.14.3.2.26 -+ */ -+ public static final ObjectIdentifier SHA_oid = new ObjectIdentifier(SHA1_OIW_data); -+ -+ public static final ObjectIdentifier SHA256_oid = new ObjectIdentifier(SHA256_data); -+ public static final ObjectIdentifier SHA384_oid = new ObjectIdentifier(SHA384_data); -+ -+ public static final ObjectIdentifier SHA512_oid = new ObjectIdentifier(SHA512_data); -+ -+ /* -+ * COMMON PUBLIC KEY TYPES -+ */ -+ private static final int DH_data[] = { 1, 2, 840, 113549, 1, 3, 1 }; -+ private static final int DH_PKIX_data[] = { 1, 2, 840, 10046, 2, 1 }; -+ private static final int DSA_OIW_data[] = { 1, 3, 14, 3, 2, 12 }; -+ private static final int DSA_PKIX_data[] = { 1, 2, 840, 10040, 4, 1 }; -+ private static final int RSA_data[] = { 1, 2, 5, 8, 1, 1 }; -+ private static final int RSAEncryption_data[] = -+ { 1, 2, 840, 113549, 1, 1, 1 }; -+ private static final int ANSI_X962_public_key_data[] = -+ { 1, 2, 840, 10045, 2, 1 }; -+ private static final int ANSI_X962_sha1_with_ec_data[] = -+ { 1, 2, 840, 10045, 4, 1 }; -+ -+ public static final ObjectIdentifier ANSIX962_EC_Public_Key_oid = new ObjectIdentifier(ANSI_X962_public_key_data); -+ public static final ObjectIdentifier ANSIX962_SHA1_With_EC_oid = new ObjectIdentifier(ANSI_X962_sha1_with_ec_data); -+ -+ /* -+ * Note the preferred OIDs are named simply with no "OIW" or -+ * "PKIX" in them, even though they may point to data from these -+ * specs; e.g. SHA_oid, DH_oid, DSA_oid, SHA1WithDSA_oid... -+ */ -+ /** -+ * Algorithm ID for Diffie Hellman Key agreement, from PKCS #3. -+ * Parameters include public values P and G, and may optionally specify -+ * the length of the private key X. Alternatively, algorithm parameters -+ * may be derived from another source such as a Certificate Authority's -+ * certificate. -+ * OID = 1.2.840.113549.1.3.1 -+ */ -+ public static final ObjectIdentifier DH_oid = new ObjectIdentifier(DH_data); -+ -+ /** -+ * Algorithm ID for the Diffie Hellman Key Agreement (DH), from the -+ * IETF PKIX IPKI Part I. -+ * Parameters may include public values P and G. -+ * OID = 1.2.840.10046.2.1 -+ */ -+ public static final ObjectIdentifier DH_PKIX_oid = new ObjectIdentifier(DH_PKIX_data); -+ -+ /** -+ * Algorithm ID for the Digital Signing Algorithm (DSA), from the -+ * NIST OIW Stable Agreements part 12. -+ * Parameters may include public values P, Q, and G; or these may be -+ * derived from -+ * another source such as a Certificate Authority's certificate. -+ * OID = 1.3.14.3.2.12 -+ */ -+ public static final ObjectIdentifier DSA_OIW_oid = new ObjectIdentifier(DSA_OIW_data); -+ -+ /** -+ * Algorithm ID for the Digital Signing Algorithm (DSA), from the -+ * IETF PKIX IPKI Part I. -+ * Parameters may include public values P, Q, and G; or these may be -+ * derived from -+ * another source such as a Certificate Authority's certificate. -+ * OID = 1.2.840.10040.4.1 -+ */ -+ public static final ObjectIdentifier DSA_oid = new ObjectIdentifier(DSA_PKIX_data); -+ -+ /** -+ * Algorithm ID for RSA keys used for any purpose, as defined in X.509. -+ * The algorithm parameter is a single value, the number of bits in the -+ * public modulus. -+ * OID = 1.2.5.8.1.1 -+ */ -+ public static final ObjectIdentifier RSA_oid = new ObjectIdentifier(RSA_data); -+ -+ /** -+ * Algorithm ID for RSA keys used with RSA encryption, as defined -+ * in PKCS #1. There are no parameters associated with this algorithm. -+ * OID = 1.2.840.113549.1.1.1 -+ */ -+ public static final ObjectIdentifier RSAEncryption_oid = new ObjectIdentifier(RSAEncryption_data); -+ -+ /* -+ * COMMON SIGNATURE ALGORITHMS -+ */ -+ private static final int sha1WithEC_data[] = -+ { 1, 2, 840, 10045, 4, 1 }; -+ private static final int sha224WithEC_data[] = -+ { 1, 2, 840, 10045, 4, 3, 1 }; -+ private static final int sha256WithEC_data[] = -+ { 1, 2, 840, 10045, 4, 3, 2 }; -+ private static final int sha384WithEC_data[] = -+ { 1, 2, 840, 10045, 4, 3, 3 }; -+ private static final int sha512WithEC_data[] = -+ { 1, 2, 840, 10045, 4, 3, 4 }; -+ private static final int md2WithRSAEncryption_data[] = -+ { 1, 2, 840, 113549, 1, 1, 2 }; -+ private static final int md5WithRSAEncryption_data[] = -+ { 1, 2, 840, 113549, 1, 1, 4 }; -+ private static final int sha1WithRSAEncryption_data[] = -+ { 1, 2, 840, 113549, 1, 1, 5 }; -+ private static final int sha256WithRSAEncryption_data[] = -+ { 1, 2, 840, 113549, 1, 1, 11 }; -+ private static final int sha384WithRSAEncryption_data[] = -+ { 1, 2, 840, 113549, 1, 1, 12 }; -+ private static final int sha512WithRSAEncryption_data[] = -+ { 1, 2, 840, 113549, 1, 1, 13 }; -+ private static final int sha1WithRSAEncryption_OIW_data[] = -+ { 1, 3, 14, 3, 2, 29 }; -+ private static final int shaWithDSA_OIW_data[] = -+ { 1, 3, 14, 3, 2, 13 }; -+ private static final int sha1WithDSA_OIW_data[] = -+ { 1, 3, 14, 3, 2, 27 }; -+ private static final int dsaWithSHA1_PKIX_data[] = -+ { 1, 2, 840, 10040, 4, 3 }; -+ -+ public static final ObjectIdentifier sha1WithEC_oid = new -+ ObjectIdentifier(sha1WithEC_data); -+ -+ public static final ObjectIdentifier sha224WithEC_oid = new -+ ObjectIdentifier(sha224WithEC_data); -+ -+ public static final ObjectIdentifier sha256WithEC_oid = new -+ ObjectIdentifier(sha256WithEC_data); -+ -+ public static final ObjectIdentifier sha384WithEC_oid = new -+ ObjectIdentifier(sha384WithEC_data); -+ -+ public static final ObjectIdentifier sha512WithEC_oid = new -+ ObjectIdentifier(sha512WithEC_data); -+ -+ /** -+ * Identifies a signing algorithm where an MD2 digest is encrypted -+ * using an RSA private key; defined in PKCS #1. Use of this -+ * signing algorithm is discouraged due to MD2 vulnerabilities. -+ * OID = 1.2.840.113549.1.1.2 -+ */ -+ public static final ObjectIdentifier md2WithRSAEncryption_oid = new -+ ObjectIdentifier(md2WithRSAEncryption_data); -+ -+ /** -+ * Identifies a signing algorithm where an MD5 digest is -+ * encrypted using an RSA private key; defined in PKCS #1. -+ * OID = 1.2.840.113549.1.1.4 -+ */ -+ public static final ObjectIdentifier md5WithRSAEncryption_oid = new -+ ObjectIdentifier(md5WithRSAEncryption_data); -+ -+ /** -+ * The proper one for sha1/rsa -+ */ -+ public static final ObjectIdentifier sha1WithRSAEncryption_oid = new -+ ObjectIdentifier(sha1WithRSAEncryption_data); -+ -+ /** -+ * The proper one for sha256/rsa -+ */ -+ public static final ObjectIdentifier sha256WithRSAEncryption_oid = new -+ ObjectIdentifier(sha256WithRSAEncryption_data); -+ -+ /** -+ * The proper one for sha384/rsa -+ */ -+ public static final ObjectIdentifier sha384WithRSAEncryption_oid = new -+ ObjectIdentifier(sha384WithRSAEncryption_data); -+ -+ /** -+ * The proper one for sha512/rsa -+ */ -+ public static final ObjectIdentifier sha512WithRSAEncryption_oid = new -+ ObjectIdentifier(sha512WithRSAEncryption_data); -+ -+ /** -+ * Identifies a signing algorithm where an SHA1 digest is -+ * encrypted using an RSA private key; defined in NIST OIW. -+ * OID = 1.3.14.3.2.29 -+ */ -+ public static final ObjectIdentifier sha1WithRSAEncryption_OIW_oid = new -+ ObjectIdentifier(sha1WithRSAEncryption_OIW_data); -+ -+ /** -+ * Identifies the FIPS 186 "Digital Signature Standard" (DSS), where a -+ * SHA digest is signed using the Digital Signing Algorithm (DSA). -+ * This should not be used. -+ * OID = 1.3.14.3.2.13 -+ */ -+ public static final ObjectIdentifier shaWithDSA_OIW_oid = new ObjectIdentifier(shaWithDSA_OIW_data); -+ -+ /** -+ * Identifies the FIPS 186 "Digital Signature Standard" (DSS), where a -+ * SHA1 digest is signed using the Digital Signing Algorithm (DSA). -+ * OID = 1.3.14.3.2.27 -+ */ -+ public static final ObjectIdentifier sha1WithDSA_OIW_oid = new ObjectIdentifier(sha1WithDSA_OIW_data); -+ -+ /** -+ * Identifies the FIPS 186 "Digital Signature Standard" (DSS), where a -+ * SHA1 digest is signed using the Digital Signing Algorithm (DSA). -+ * OID = 1.2.840.10040.4.3 -+ */ -+ public static final ObjectIdentifier sha1WithDSA_oid = new ObjectIdentifier(dsaWithSHA1_PKIX_data); -+ -+ /** -+ * Supported signing algorithms for a DSA key. -+ */ -+ public static final String[] DSA_SIGNING_ALGORITHMS = new String[] -+ { "SHA1withDSA" }; -+ -+ /** -+ * Supported signing algorithms for a RSA key. -+ */ -+ public static final String[] RSA_SIGNING_ALGORITHMS = new String[] -+ { "SHA1withRSA", "SHA256withRSA", "SHA384withRSA", "SHA512withRSA", "MD5withRSA", "MD2withRSA" }; -+ -+ public static final String[] EC_SIGNING_ALGORITHMS = new String[] -+ { "SHA1withEC", "SHA256withEC", "SHA384withEC", "SHA512withEC" }; -+ -+ /** -+ * All supported signing algorithms. -+ */ -+ public static final String[] ALL_SIGNING_ALGORITHMS = new String[] -+ { -+ "SHA1withRSA", "MD5withRSA", "MD2withRSA", "SHA1withDSA", "SHA256withRSA", "SHA384withRSA", "SHA512withRSA", "SHA1withEC", -+ "SHA256withEC", "SHA384withEC", "SHA512withEC" }; -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/Attribute.java b/org/mozilla/jss/netscape/security/x509/Attribute.java -new file mode 100644 -index 00000000..f6deca5f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/Attribute.java -@@ -0,0 +1,327 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerEncoder; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * An attribute, as identified by some attribute ID, has some particular values. -+ * Values are as a rule ASN.1 printable strings. A conventional set of type IDs -+ * is recognized when parsing. The following shows the syntax: -+ * -+ *

-+ *
-+ *    Attribute	::= SEQUENCE {
-+ * type		AttributeType,
-+ * 	value		SET OF AttributeValue
-+ *              	-- at least one value is required --}
-+ *
-+ *    AttributeType	::= OBJECT IDENTIFIER
-+ *
-+ *    AttributeValue	::= ANY
-+ *
-+ * 
-+ * -+ * Refer to draft-ietf-pkix-ipki-part1-11 for the support attributes listed on -+ * page 96 of the internet draft. The are listed here for easy reference: name, -+ * common name, surname, given name, initials, generation qualifier, dn qualifier, -+ * country name, locality name, state or province name, organization name, organization -+ * unit name, title, pkcs9 email. Not all the attributes are supported. Please check -+ * the X500NameAttrMap for defined attributes. -+ * -+ * @author Christine Ho -+ */ -+ -+public final class Attribute implements Serializable, DerEncoder { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -931486084625476764L; -+ //private variables -+ ObjectIdentifier oid; -+ Vector valueSet = new Vector(); -+ transient protected X500NameAttrMap attrMap; -+ -+ //========== CONSTRUCTOR ================================== -+ -+ /** -+ * Construct an attribute from attribute type and attribute value -+ * -+ * @param oid the object identifier of the attribute type -+ * @param value the value string -+ */ -+ public Attribute(ObjectIdentifier oid, String value) -+ throws IOException { -+ -+ //pre-condition verification -+ if ((oid == null) || (value == null)) -+ throw new IOException("Invalid Input - null passed"); -+ -+ attrMap = X500NameAttrMap.getDefault(); -+ this.oid = oid; -+ valueSet.addElement(value); -+ } -+ -+ /** -+ * Construct an attribute from attribute type and attribute values -+ * -+ * @param oid the object identifier of the attribute type -+ * @param values String value vector -+ */ -+ public Attribute(ObjectIdentifier oid, Vector values) -+ throws IOException { -+ -+ //pre-condition verification -+ if ((oid == null) || (values == null)) -+ throw new IOException("Invalid Input - null passed"); -+ -+ attrMap = X500NameAttrMap.getDefault(); -+ this.oid = oid; -+ -+ //copy the value into the valueSet list -+ Enumeration vals = values.elements(); -+ while (vals.hasMoreElements()) { -+ valueSet.addElement(vals.nextElement()); -+ } -+ } -+ -+ /** -+ * Construct an attribute from attribute type and attribute values -+ * -+ * @param oid attribute type string CN,OU,O,C,L,TITLE,ST,STREET,UID,MAIL,E,DC -+ * @param values String value vector -+ */ -+ public Attribute(String attr, Vector values) -+ throws IOException { -+ -+ //pre-condition verification -+ if ((attr == null) || (values == null)) -+ throw new IOException("Invalid Input - null passed"); -+ -+ ObjectIdentifier identifier = null; -+ try { -+ identifier = new ObjectIdentifier(attr); -+ } catch (Exception e) { -+ } -+ -+ ObjectIdentifier id = identifier; -+ if (identifier == null) { -+ attrMap = X500NameAttrMap.getDefault(); -+ id = attrMap.getOid(attr); -+ if (id == null) -+ throw new IOException("Attr is not supported - does not contain in attr map"); -+ } -+ this.oid = id; -+ -+ //copy the value into the valueSet list -+ Enumeration vals = values.elements(); -+ while (vals.hasMoreElements()) { -+ valueSet.addElement(vals.nextElement()); -+ } -+ } -+ -+ /** -+ * Construct an attribute from a der encoded object. This der -+ * der encoded value should represent the attribute object. -+ * -+ * @param value the attribute object in der encode form. -+ */ -+ public Attribute(DerValue val) -+ throws IOException { -+ -+ //pre-condition verification -+ if (val == null) -+ throw new IOException("Invalid Input - null passed"); -+ -+ attrMap = X500NameAttrMap.getDefault(); -+ -+ decodeThis(val); -+ -+ } -+ -+ //========== PUBLIC METHODS ================================== -+ -+ /** -+ * Returns the OID in the Attribute. -+ * -+ * @return the ObjectIdentifier in this Attribute. -+ */ -+ public ObjectIdentifier getOid() { -+ return oid; -+ } -+ -+ /** -+ * Returns enumeration of values in this attribute. -+ * -+ * @return Enumeration of values of this Attribute. -+ */ -+ public Enumeration getValues() { -+ if (valueSet == null) -+ return null; -+ return valueSet.elements(); -+ } -+ -+ /** -+ * Encodes the Attribute to a Der output stream. -+ * Attribute are encoded as a SEQUENCE of two elements. -+ * -+ * @param out The Der output stream. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ encodeThis(out); -+ } -+ -+ /** -+ * DER encode this object onto an output stream. -+ * Implements the DerEncoder interface. -+ * -+ * @param out -+ * the output stream on which to write the DER encoding. -+ * -+ * @exception IOException on encoding error. -+ */ -+ public void derEncode(OutputStream out) throws IOException { -+ encodeThis(out); -+ } -+ -+ /** -+ * Prints a string version of this extension. -+ */ -+ public String toString() { -+ String theoid = "Attribute: " + oid + "\n"; -+ StringBuffer values = new StringBuffer("Values: "); -+ Enumeration n = valueSet.elements(); -+ if (n.hasMoreElements()) { -+ values.append(n.nextElement()); -+ while (n.hasMoreElements()) -+ values.append("," + n.nextElement()); -+ } -+ return theoid + values.toString() + "\n"; -+ } -+ -+ //========== PRIVATE METHODS ================================== -+ -+ //encode the attribute object -+ private void encodeThis(OutputStream out) -+ throws IOException { -+ try (DerOutputStream tmp2 = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ tmp.putOID(oid); -+ encodeValueSet(tmp); -+ tmp2.write(DerValue.tag_Sequence, tmp); -+ out.write(tmp2.toByteArray()); -+ } -+ } -+ -+ //encode the attribute object -+ private void encodeValueSet(OutputStream out) -+ throws IOException { -+ try (DerOutputStream tmp2 = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ //get the attribute converter -+ AVAValueConverter converter = attrMap.getValueConverter(oid); -+ if (converter == null) { -+ converter = new GenericValueConverter(); -+ //throw new IOException("Converter not found: unsupported attribute type"); -+ } -+ -+ //loop through all the values and encode -+ Enumeration vals = valueSet.elements(); -+ while (vals.hasMoreElements()) { -+ String val = vals.nextElement(); -+ DerValue derobj = converter.getValue(val); -+ derobj.encode(tmp); -+ } -+ -+ tmp2.write(DerValue.tag_SetOf, tmp); -+ out.write(tmp2.toByteArray()); -+ } -+ } -+ -+ //decode the attribute object -+ private void decodeThis(DerValue val) -+ throws IOException { -+ -+ //pre-condition verification -+ if (val == null) { -+ throw new IOException("Invalid Input - null passed."); -+ } -+ -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for Attribute."); -+ } -+ -+ if (val.data.available() == 0) { -+ throw new IOException("No data available in " -+ + "passed DER encoded value."); -+ } -+ this.oid = val.data.getDerValue().getOID(); -+ -+ if (val.data.available() == 0) { -+ throw new IOException("Invalid encoding for Attribute - value missing"); -+ } -+ decodeValueSet(val.data.getDerValue()); -+ -+ if (this.oid == null) -+ throw new IOException("Invalid encoding for Attribute - OID missing"); -+ -+ } -+ -+ //decode the attribute value set -+ private void decodeValueSet(DerValue val) -+ throws IOException { -+ //pre-condition verification -+ if (val == null) { -+ throw new IOException("Invalid Input - null passed."); -+ } -+ -+ AVAValueConverter converter = attrMap.getValueConverter(this.oid); -+ if (converter == null) { -+ converter = new GenericValueConverter(); -+ //throw new IOException("Attribute is not supported - not in attr map"); -+ } -+ -+ if (val.tag != DerValue.tag_SetOf) { -+ throw new IOException("Invalid encoding for Attribute Value Set."); -+ } -+ -+ if (val.data.available() == 0) { -+ throw new IOException("No data available in " -+ + "passed DER encoded attribute value set."); -+ } -+ -+ //get the value set -+ while (val.data.available() != 0) { -+ DerValue value = val.data.getDerValue(); -+ valueSet.addElement(converter.getAsString(value)); -+ } -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/AuthorityKeyIdentifierExtension.java b/org/mozilla/jss/netscape/security/x509/AuthorityKeyIdentifierExtension.java -new file mode 100644 -index 00000000..cee776be ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/AuthorityKeyIdentifierExtension.java -@@ -0,0 +1,342 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class represents the Authority Key Identifier Extension. -+ * -+ *

-+ * The authority key identifier extension provides a means of identifying the particular public key used to sign a -+ * certificate. This extension would be used where an issuer has multiple signing keys (either due to multiple -+ * concurrent key pairs or due to changeover). -+ *

-+ * The ASN.1 syntax for this is: -+ * -+ *

-+ * AuthorityKeyIdentifier ::= SEQUENCE {
-+ *    keyIdentifier             [0] KeyIdentifier           OPTIONAL,
-+ *    authorityCertIssuer       [1] GeneralNames            OPTIONAL,
-+ *    authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL
-+ * }
-+ * KeyIdentifier ::= OCTET STRING
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.9 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class AuthorityKeyIdentifierExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -157913621972354170L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = -+ "x509.info.extensions.AuthorityKeyIdentifier"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "AuthorityKeyIdentifier"; -+ public static final String KEY_ID = "key_id"; -+ public static final String AUTH_NAME = "auth_name"; -+ public static final String SERIAL_NUMBER = "serial_number"; -+ -+ // Private data members -+ private static final byte TAG_ID = 0; -+ private static final byte TAG_NAMES = 1; -+ private static final byte TAG_SERIAL_NUM = 2; -+ -+ private KeyIdentifier id = null; -+ private GeneralNames names = null; -+ private SerialNumber serialNum = null; -+ -+ // Encode only the extension value -+ private void encodeThis() throws IOException { -+ try (DerOutputStream tmp = new DerOutputStream(); -+ DerOutputStream seq = new DerOutputStream()) { -+ -+ if (id != null) { -+ DerOutputStream tmp1 = new DerOutputStream(); -+ id.encode(tmp1); -+ tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_ID), tmp1); -+ } -+ try { -+ if (names != null) { -+ DerOutputStream tmp1 = new DerOutputStream(); -+ names.encode(tmp1); -+ tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, TAG_NAMES), tmp1); -+ } -+ } catch (Exception e) { -+ throw new IOException(e); -+ } -+ if (serialNum != null) { -+ DerOutputStream tmp1 = new DerOutputStream(); -+ serialNum.encode(tmp1); -+ tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_SERIAL_NUM), tmp1); -+ } -+ seq.write(DerValue.tag_Sequence, tmp); -+ this.extensionValue = seq.toByteArray(); -+ } -+ } -+ -+ /** -+ * Exposed critical parameter. 99/11/03 -+ */ -+ public AuthorityKeyIdentifierExtension(boolean critical, -+ KeyIdentifier kid, GeneralNames name, -+ SerialNumber sn) -+ throws IOException { -+ this.id = kid; -+ this.names = name; -+ this.serialNum = sn; -+ -+ this.extensionId = PKIXExtensions.AuthorityKey_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ /** -+ * The default constructor for this extension. Null parameters make -+ * the element optional (not present). -+ * -+ * @param id the KeyIdentifier associated with this extension. -+ * @param names the GeneralNames associated with this extension -+ * @param serialNum the CertificateSerialNumber associated with -+ * this extension. -+ * @exception IOException on error. -+ */ -+ public AuthorityKeyIdentifierExtension(KeyIdentifier kid, GeneralNames name, -+ SerialNumber sn) -+ throws IOException { -+ this.id = kid; -+ this.names = name; -+ this.serialNum = sn; -+ -+ this.extensionId = PKIXExtensions.AuthorityKey_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public AuthorityKeyIdentifierExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.AuthorityKey_Id; -+ this.critical = critical.booleanValue(); -+ -+ if (!(value instanceof byte[])) -+ throw new IOException("Illegal argument type"); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ System.arraycopy(value, 0, extValue, 0, len); -+ -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for " + -+ "AuthorityKeyIdentifierExtension."); -+ } -+ -+ // NB. this is always encoded with the IMPLICIT tag -+ // The checks only make sense if we assume implicit tagging, -+ // with explicit tagging the form is always constructed. -+ while (val.data.available() != 0) { -+ DerValue opt = val.data.getDerValue(); -+ -+ if (opt.isContextSpecific(TAG_ID) && !opt.isConstructed()) { -+ if (id != null) -+ throw new IOException("Duplicate KeyIdentifier in " + -+ "AuthorityKeyIdentifier."); -+ opt.resetTag(DerValue.tag_OctetString); -+ id = new KeyIdentifier(opt); -+ -+ } else if (opt.isContextSpecific(TAG_NAMES) && -+ opt.isConstructed()) { -+ if (names != null) -+ throw new IOException("Duplicate GeneralNames in " + -+ "AuthorityKeyIdentifier."); -+ try { -+ opt.resetTag(DerValue.tag_Sequence); -+ names = new GeneralNames(opt); -+ } catch (GeneralNamesException e) { -+ throw new IOException(e); -+ } -+ -+ } else if (opt.isContextSpecific(TAG_SERIAL_NUM) && -+ !opt.isConstructed()) { -+ if (serialNum != null) -+ throw new IOException("Duplicate SerialNumber in " + -+ "AuthorityKeyIdentifier."); -+ opt.resetTag(DerValue.tag_Integer); -+ serialNum = new SerialNumber(opt); -+ } else -+ throw new IOException("Invalid encoding of " + -+ "AuthorityKeyIdentifierExtension."); -+ } -+ } -+ -+ /** -+ * Return the object as a string. -+ */ -+ public String toString() { -+ String s = super.toString() + "AuthorityKeyIdentifier [\n"; -+ if (id != null) { -+ s += id.toString(); -+ } -+ if (names != null) { -+ s += names.toString() + "\n"; -+ } -+ if (serialNum != null) { -+ s += serialNum.toString() + "\n"; -+ } -+ return (s + "]\n"); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on error. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (this.extensionValue == null) { -+ extensionId = PKIXExtensions.AuthorityKey_Id; -+ critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (name.equalsIgnoreCase(KEY_ID)) { -+ if (!(obj instanceof KeyIdentifier)) { -+ throw new IOException("Attribute value should be of " + -+ "type KeyIdentifier."); -+ } -+ id = (KeyIdentifier) obj; -+ } else if (name.equalsIgnoreCase(AUTH_NAME)) { -+ if (!(obj instanceof GeneralNames)) { -+ throw new IOException("Attribute value should be of " + -+ "type GeneralNames."); -+ } -+ names = (GeneralNames) obj; -+ } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) { -+ if (!(obj instanceof SerialNumber)) { -+ throw new IOException("Attribute value should be of " + -+ "type SerialNumber."); -+ } -+ serialNum = (SerialNumber) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:AuthorityKeyIdentifier."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(KEY_ID)) { -+ return (id); -+ } else if (name.equalsIgnoreCase(AUTH_NAME)) { -+ return (names); -+ } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) { -+ return (serialNum); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:AuthorityKeyIdentifier."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(KEY_ID)) { -+ id = null; -+ } else if (name.equalsIgnoreCase(AUTH_NAME)) { -+ names = null; -+ } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) { -+ serialNum = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:AuthorityKeyIdentifier."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(KEY_ID); -+ elements.addElement(AUTH_NAME); -+ elements.addElement(SERIAL_NUMBER); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/BasicConstraintsExtension.java b/org/mozilla/jss/netscape/security/x509/BasicConstraintsExtension.java -new file mode 100644 -index 00000000..fc03a526 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/BasicConstraintsExtension.java -@@ -0,0 +1,296 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class represents the Basic Constraints Extension. -+ * -+ *

-+ * The basic constraints extension identifies whether the subject of the certificate is a CA and how deep a -+ * certification path may exist through that CA. -+ * -+ *

-+ * The ASN.1 syntax for this extension is:
-+ * BasicConstraints ::= SEQUENCE {
-+ *     cA                BOOLEAN DEFAULT FALSE,
-+ *     pathLenConstraint INTEGER (0..MAX) OPTIONAL
-+ * }
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.7 -+ * @see CertAttrSet -+ * @see Extension -+ */ -+public class BasicConstraintsExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 6213957094939885889L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions.BasicConstraints"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "BasicConstraints"; -+ public static final String IS_CA = "is_ca"; -+ public static final String PATH_LEN = "path_len"; -+ -+ // Private data members -+ private boolean ca = false; -+ private int pathLen = -1; -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ try (DerOutputStream out = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (ca) { -+ tmp.putBoolean(ca); -+ } -+ if (pathLen >= 0) { -+ tmp.putInteger(new BigInt(pathLen)); -+ } -+ out.write(DerValue.tag_Sequence, tmp); -+ this.extensionValue = out.toByteArray(); -+ } -+ } -+ -+ /** -+ * Default constructor for this object. -+ * -+ * @param ca true, if the subject of the Certificate is a CA. -+ * @param len specifies the depth of the certification path. -+ */ -+ public BasicConstraintsExtension(boolean ca, int len) throws IOException { -+ this.ca = ca; -+ this.pathLen = len; -+ this.extensionId = PKIXExtensions.BasicConstraints_Id; -+ if (ca) { -+ critical = true; -+ } else { -+ critical = false; -+ } -+ encodeThis(); -+ } -+ -+ /** -+ * Default constructor for this object. -+ * -+ * @param ca true, if the subject of the Certificate is a CA. -+ * @param len specifies the depth of the certification path. -+ */ -+ public BasicConstraintsExtension(boolean ca, boolean critical, int len) throws IOException { -+ this.ca = ca; -+ this.pathLen = len; -+ this.extensionId = PKIXExtensions.BasicConstraints_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param extension the DER encoded value of the extension. -+ * @exception IOException on error. -+ */ -+ public BasicConstraintsExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.BasicConstraints_Id; -+ this.critical = critical.booleanValue(); -+ -+ if (value instanceof byte[]) { -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ System.arraycopy(value, 0, extValue, 0, len); -+ -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding of BasicConstraints"); -+ } -+ -+ // non-CA cert with no limit to certification path length -+ if (val.data == null || val.data.available() < 1) { -+ this.ca = false; -+ this.pathLen = -1; -+ return; -+ } -+ DerValue opt = val.data.getDerValue(); -+ if (opt.tag != DerValue.tag_Boolean) { -+ this.ca = false; -+ } else { -+ this.ca = true; -+ if (val.data.available() != 0) { -+ opt = val.data.getDerValue(); -+ } else { -+ this.pathLen = -1; -+ return; -+ } -+ } -+ if (opt.tag != DerValue.tag_Integer) { -+ throw new IOException("Invalid encoding of BasicConstraints"); -+ } -+ this.pathLen = (opt.getInteger()).toInt(); -+ /* -+ * Activate this check once again after PKIX profiling -+ * is a standard and this check no longer imposes an -+ * interoperability barrier. -+ * if (ca) { -+ * if (!this.critical) { -+ * throw new IOException("Criticality cannot be false for CA."); -+ * } -+ * } -+ */ -+ } else -+ throw new IOException("Invalid argument type"); -+ } -+ -+ /** -+ * Return user readable form of extension. -+ */ -+ public String toString() { -+ String s = super.toString() + "BasicConstraints:[\n"; -+ -+ s += ((ca) ? ("CA:true") : ("CA:false")) + "\n"; -+ if (pathLen >= 0) { -+ s += "PathLen:" + pathLen + "\n"; -+ } else { -+ s += "PathLen: undefined\n"; -+ } -+ return (s + "]\n"); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Encode this extension value to the output stream. -+ * -+ * @param out the DerOutputStream to encode the extension to. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ this.extensionId = PKIXExtensions.BasicConstraints_Id; -+ /* #57286 - so that profile can set critiality */ -+ /* -+ if (ca) { -+ critical = true; -+ } else { -+ critical = false; -+ } -+ */ -+ encodeThis(); -+ } -+ super.encode(tmp); -+ -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (name.equalsIgnoreCase(IS_CA)) { -+ if (!(obj instanceof Boolean)) { -+ throw new IOException("Attribute value should be of type Boolean."); -+ } -+ ca = ((Boolean) obj).booleanValue(); -+ } else if (name.equalsIgnoreCase(PATH_LEN)) { -+ if (!(obj instanceof Integer)) { -+ throw new IOException("Attribute value should be of type Integer."); -+ } -+ pathLen = ((Integer) obj).intValue(); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:BasicConstraints."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(IS_CA)) { -+ return (Boolean.valueOf(ca)); -+ } else if (name.equalsIgnoreCase(PATH_LEN)) { -+ return (Integer.valueOf(pathLen)); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:BasicConstraints."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(IS_CA)) { -+ ca = false; -+ } else if (name.equalsIgnoreCase(PATH_LEN)) { -+ pathLen = -1; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:BasicConstraints."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(IS_CA); -+ elements.addElement(PATH_LEN); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CPSuri.java b/org/mozilla/jss/netscape/security/x509/CPSuri.java -new file mode 100644 -index 00000000..681095ae ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CPSuri.java -@@ -0,0 +1,66 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the CPSuri Qualifier. -+ * -+ * CPSuri ::= IA5String; -+ * -+ * @author Thomas Kwan -+ */ -+public class CPSuri extends Qualifier { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -2814961293159006960L; -+ private String mURI = null; -+ -+ /** -+ * Create a PolicyQualifierInfo -+ * -+ * @param id the ObjectIdentifier for the policy id. -+ */ -+ public CPSuri(String uri) { -+ mURI = uri; -+ } -+ -+ public CPSuri(DerValue val) throws IOException { -+ mURI = val.getIA5String(); -+ } -+ -+ /** -+ * Write the PolicyQualifier to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putIA5String(mURI); -+ } -+ -+ public String getURI() { -+ return mURI; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CRLDistributionPoint.java b/org/mozilla/jss/netscape/security/x509/CRLDistributionPoint.java -new file mode 100644 -index 00000000..abec5bc7 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CRLDistributionPoint.java -@@ -0,0 +1,478 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.ByteArrayOutputStream; -+import java.io.FileOutputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+ -+import org.mozilla.jss.netscape.security.util.BitArray; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+import org.mozilla.jss.asn1.ANY; -+import org.mozilla.jss.asn1.ASN1Template; -+import org.mozilla.jss.asn1.ASN1Util; -+import org.mozilla.jss.asn1.ASN1Value; -+import org.mozilla.jss.asn1.BIT_STRING; -+import org.mozilla.jss.asn1.EXPLICIT; -+import org.mozilla.jss.asn1.InvalidBERException; -+import org.mozilla.jss.asn1.SEQUENCE; -+import org.mozilla.jss.asn1.Tag; -+ -+/** -+ *
-+ * DistributionPoint ::= SEQUENCE {
-+ *      distributionPoint       [0]     DistributionPointName OPTIONAL,
-+ *      reasons                 [1]     ReasonFlags OPTIONAL,
-+ *      cRLIssuer               [2]     GeneralNames OPTIONAL }
-+ *
-+ * DistributionPointName ::= CHOICE {
-+ *      fullName                [0]     GeneralNames,
-+ *      nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
-+ *
-+ * ReasonFlags ::= BIT STRING {
-+ *      unused                  (0),
-+ *      keyCompromise           (1),
-+ *      cACompromise            (2),
-+ *      affiliationChanged      (3),
-+ *      superseded              (4),
-+ *      cessationOfOperation    (5),
-+ *      certificateHold         (6) }
-+ * 
-+ */ -+public class CRLDistributionPoint implements ASN1Value { -+ -+ // at most one of the two following may be specified: -+ private GeneralNames fullName; -+ private RDN relativeName; -+ -+ // cache encoding of fullName -+ private ANY fullNameEncoding; -+ -+ private BitArray reasons; // optional, may be null -+ private GeneralNames CRLIssuer; // optional, may be null -+ private ANY CRLIssuerEncoding; -+ -+ // default constructor does nothing. -+ -+ /** -+ * Returns the fullName of the DistributionPointName, which may be null. -+ */ -+ public GeneralNames getFullName() { -+ return fullName; -+ } -+ -+ /** -+ * Returns the relativeName of the DistributionPointName, which may be null. -+ */ -+ public RDN getRelativeName() { -+ return relativeName; -+ } -+ -+ /** -+ * Sets the fullName of the DistributionPointName. It may be set to null. -+ * If it is set to a non-null value, relativeName will be -+ * set to null, because at most one of these two attributes -+ * can be specified at a time. -+ * -+ * @exception GeneralNamesException If an error occurs encoding the -+ * name. -+ */ -+ public void setFullName(GeneralNames fullName) -+ throws GeneralNamesException, IOException { -+ this.fullName = fullName; -+ if (fullName != null) { -+ // encode the name to catch any problems with it -+ DerOutputStream derOut = new DerOutputStream(); -+ fullName.encode(derOut); -+ try { -+ ANY raw = new ANY(derOut.toByteArray()); -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ raw.encodeWithAlternateTag(Tag.get(0), bos); -+ fullNameEncoding = new ANY(bos.toByteArray()); -+ } catch (InvalidBERException e) { -+ // assume this won't happen, since it would imply a bug -+ // in DerOutputStream -+ throw new GeneralNamesException(e.toString()); -+ } -+ -+ this.relativeName = null; -+ } -+ } -+ -+ /** -+ * Sets the relativeName of the DistributionPointName. It may be set to null. -+ * If it is set to a non-null value, fullName will be -+ * set to null, because at most one of these two attributes -+ * can be specified at a time. -+ */ -+ public void setRelativeName(RDN relativeName) { -+ this.relativeName = relativeName; -+ if (relativeName != null) { -+ this.fullName = null; -+ } -+ } -+ -+ /** -+ * Returns the reason flags for this distribution point. May be null. -+ */ -+ public BitArray getReasons() { -+ return reasons; -+ } -+ -+ /** -+ * Sets the reason flags for this distribution point. May be set to null. -+ */ -+ public void setReasons(BitArray reasons) { -+ this.reasons = reasons; -+ } -+ -+ /** -+ * Returns the CRLIssuer for the CRL at this distribution point. -+ * May be null. -+ */ -+ public GeneralNames getCRLIssuer() { -+ return CRLIssuer; -+ } -+ -+ /** -+ * Sets the CRLIssuer for the CRL at this distribution point. -+ * May be set to null. -+ * -+ * @exception GeneralNamesException If an error occurs encoding the name. -+ */ -+ public void setCRLIssuer(GeneralNames CRLIssuer) -+ throws GeneralNamesException, IOException { -+ this.CRLIssuer = CRLIssuer; -+ -+ if (CRLIssuer != null) { -+ // encode the name to catch any problems with it -+ DerOutputStream derOut = new DerOutputStream(); -+ CRLIssuer.encode(derOut); -+ try { -+ ANY raw = new ANY(derOut.toByteArray()); -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ raw.encodeWithAlternateTag(Tag.get(2), bos); -+ CRLIssuerEncoding = new ANY(bos.toByteArray()); -+ } catch (InvalidBERException e) { -+ throw new GeneralNamesException(e.toString()); -+ } -+ } -+ } -+ -+ ///////////////////////////////////////////////////////////// -+ // DER encoding -+ ///////////////////////////////////////////////////////////// -+ -+ private static final Tag TAG = SEQUENCE.TAG; -+ -+ public Tag getTag() { -+ return TAG; -+ } -+ -+ public void encode(OutputStream ostream) throws IOException { -+ encode(TAG, ostream); -+ } -+ -+ public void encode(Tag implicitTag, OutputStream ostream) -+ throws IOException { -+ SEQUENCE seq = new SEQUENCE(); -+ DerOutputStream derOut; -+ -+ try { -+ -+ // Encodes the DistributionPointName. Because DistributionPointName -+ // is a CHOICE, the [0] tag is forced to be EXPLICIT. -+ if (fullName != null) { -+ EXPLICIT distPoint = new EXPLICIT(Tag.get(0), fullNameEncoding); -+ seq.addElement(distPoint); -+ } else if (relativeName != null) { -+ derOut = new DerOutputStream(); -+ relativeName.encode(derOut); -+ ANY rn = new ANY(derOut.toByteArray()); -+ EXPLICIT raw = new EXPLICIT(Tag.get(1), rn); -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ raw.encode(bos); -+ ANY distPointName = new ANY(bos.toByteArray()); -+ EXPLICIT distPoint = new EXPLICIT(Tag.get(0), distPointName); -+ seq.addElement(distPoint); -+ } -+ -+ // Encodes the ReasonFlags. -+ if (reasons != null) { -+ derOut = new DerOutputStream(); -+ derOut.putUnalignedBitString(reasons); -+ ANY raw = new ANY(derOut.toByteArray()); -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ raw.encodeWithAlternateTag(Tag.get(1), bos); -+ ANY reasonEncoding = new ANY(bos.toByteArray()); -+ seq.addElement(Tag.get(1), reasonEncoding); -+ } -+ -+ // Encodes the CRLIssuer -+ if (CRLIssuer != null) { -+ seq.addElement(Tag.get(2), CRLIssuerEncoding); -+ } -+ -+ seq.encode(implicitTag, ostream); -+ -+ } catch (InvalidBERException e) { -+ // this shouldn't happen unless there is a bug in one of -+ // the Sun encoding classes -+ throw new IOException(e.toString()); -+ } -+ } -+ -+ // Template singleton -+ private static Template templateInstance = new Template(); -+ -+ /** -+ * Returns an instance of a template for decoding a CRLDistributionPoint. -+ */ -+ public static Template getTemplate() { -+ return templateInstance; -+ } -+ -+ public static void main(String args[]) throws GeneralNamesException, IOException, InvalidBERException { -+ ByteArrayOutputStream bos = null; -+ FileOutputStream fos = null; -+ try { -+ if (args.length != 1) { -+ System.out.println("Usage: CRLDistributionPoint "); -+ System.exit(-1); -+ } -+ -+ bos = new ByteArrayOutputStream(); -+ -+ SEQUENCE cdps = new SEQUENCE(); -+ -+ // URI only -+ CRLDistributionPoint cdp = new CRLDistributionPoint(); -+ URIName uri = new URIName("http://www.mycrl.com/go/here"); -+ GeneralNames generalNames = new GeneralNames(); -+ generalNames.addElement(uri); -+ cdp.setFullName(generalNames); -+ cdps.addElement(cdp); -+ -+ // DN only -+ cdp = new CRLDistributionPoint(); -+ X500Name dn = new X500Name("CN=Otis Smith,E=otis@fedoraproject.org" + -+ ",OU=Certificate Server,O=Fedora,C=US"); -+ generalNames = new GeneralNames(); -+ generalNames.addElement(dn); -+ cdp.setFullName(generalNames); -+ cdps.addElement(cdp); -+ -+ // DN + reason -+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 }); -+ cdp = new CRLDistributionPoint(); -+ cdp.setFullName(generalNames); -+ cdp.setReasons(ba); -+ cdps.addElement(cdp); -+ -+ // relative DN + reason + crlIssuer -+ cdp = new CRLDistributionPoint(); -+ RDN rdn = new RDN("OU=foobar dept"); -+ cdp.setRelativeName(rdn); -+ cdp.setReasons(ba); -+ cdp.setCRLIssuer(generalNames); -+ cdps.addElement(cdp); -+ -+ cdps.encode(bos); -+ -+ byte[] encoded = bos.toByteArray(); -+ fos = new FileOutputStream(args[0]); -+ fos.write(encoded); -+ -+ SEQUENCE.OF_Template seqt = new SEQUENCE.OF_Template(getTemplate()); -+ -+ cdps = (SEQUENCE) ASN1Util.decode(seqt, encoded); -+ -+ int size = cdps.size(); -+ System.out.println("Total number of CDPs: " + size); -+ for (int i = 0; i < size; i++) { -+ System.out.println("\nCDP " + i); -+ cdp = (CRLDistributionPoint) cdps.elementAt(i); -+ GeneralNames gn = cdp.getFullName(); -+ if (gn == null) { -+ System.out.println("No full name"); -+ } else { -+ System.out.println(gn); -+ } -+ rdn = cdp.getRelativeName(); -+ if (rdn == null) { -+ System.out.println("No relative name"); -+ } else { -+ System.out.println(rdn); -+ } -+ if (cdp.getReasons() == null) { -+ System.out.println("No reasons"); -+ } else { -+ System.out.println(cdp.getReasons()); -+ } -+ gn = cdp.getCRLIssuer(); -+ if (gn == null) { -+ System.out.println("No cRLIssuer"); -+ } else { -+ System.out.println(gn); -+ } -+ } -+ System.out.println("Done"); -+ -+ } finally { -+ if (bos != null) { -+ bos.close(); -+ } -+ if (fos != null) { -+ fos.close(); -+ } -+ if (fos != null) { -+ fos.close(); -+ } -+ } -+ } -+ -+ /** -+ * Template for decoding CRLDistributionPoint. -+ */ -+ public static class Template implements ASN1Template { -+ -+ public boolean tagMatch(Tag tag) { -+ return TAG.equals(tag); -+ } -+ -+ public ASN1Value decode(InputStream istream) -+ throws IOException, InvalidBERException { -+ return decode(TAG, istream); -+ } -+ -+ public ASN1Value decode(Tag implicitTag, InputStream istream) -+ throws IOException, InvalidBERException { -+ CRLDistributionPoint cdp = new CRLDistributionPoint(); -+ -+ // -+ // construct the top-level sequence -+ // -+ -+ SEQUENCE.Template seqt = SEQUENCE.getTemplate(); -+ -+ // distributionPoint -+ seqt.addOptionalElement( -+ new EXPLICIT.Template(Tag.get(0), ANY.getTemplate())); -+ -+ // reasons -+ seqt.addOptionalElement(Tag.get(1), BIT_STRING.getTemplate()); -+ -+ // cRLIssuer -+ // This will have a tag of 2, but we can't say that here -+ // because ANYs can't have implicit tags. We don't need to say -+ // it, because we do check the tags on the other two elements -+ // in the sequence, so we'll know if we get this one. -+ seqt.addOptionalElement(ANY.getTemplate()); -+ -+ // -+ // decode the top-level sequence -+ // -+ SEQUENCE top = (SEQUENCE) seqt.decode(implicitTag, istream); -+ -+ // decode the distribution point name -+ if (top.elementAt(0) != null) { -+ EXPLICIT exp = (EXPLICIT) top.elementAt(0); -+ ANY distPoint = (ANY) exp.getContent(); -+ if (distPoint.getTag().equals(Tag.get(0))) { -+ // fullName -+ try { -+ DerValue dv = new DerValue(distPoint.getEncoded()); -+ //toFile("encodedFullName", distPoint.getEncoded()); -+ dv.resetTag(DerValue.tag_Sequence); -+ cdp.setFullName(new GeneralNames(dv)); -+ } catch (GeneralNamesException e) { -+ throw new InvalidBERException("fullName: " + e.toString()); -+ } catch (IOException e) { -+ throw new InvalidBERException("fullName: " + e.toString()); -+ } -+ } else if (distPoint.getTag().equals(Tag.get(1))) { -+ // relative name -+ try { -+ DerValue dv = new DerValue(distPoint.getEncoded()); -+ /* dv is as follows: -+ 0 12: [1] { -+ 2 10: SET { -+ 4 8: SEQUENCE { -+ 6 3: OBJECT IDENTIFIER commonName (2 5 4 3) -+ 11 1: PrintableString 'x' -+ : } -+ : } -+ : } -+ */ -+ dv = dv.data.getDerValue(); // skipping the tag -+ /* after the skipping, we have: -+ 0 10: SET { -+ 2 8: SEQUENCE { -+ 4 3: OBJECT IDENTIFIER commonName (2 5 4 3) -+ 9 1: PrintableString 'x' -+ : } -+ : } -+ */ -+ dv.resetTag(DerValue.tag_Set); -+ cdp.setRelativeName(new RDN(dv)); -+ } catch (IOException e) { -+ throw new InvalidBERException("relativeName " + -+ e.toString()); -+ } -+ } else { -+ throw new InvalidBERException( -+ "Unknown tag " + distPoint.getTag() + -+ " in distributionPoint"); -+ } -+ } -+ -+ // decode the reasons -+ if (top.elementAt(1) != null) { -+ BIT_STRING bs = (BIT_STRING) top.elementAt(1); -+ byte[] bits = bs.getBits(); -+ cdp.setReasons( -+ new BitArray((bits.length * 8) - bs.getPadCount(), bits)); -+ } -+ -+ // decode the cRLIssuer -+ if (top.elementAt(2) != null) { -+ ANY issuer = (ANY) top.elementAt(2); -+ if (!issuer.getTag().equals(Tag.get(2))) { -+ throw new InvalidBERException("Invalid tag " + issuer.getTag()); -+ } -+ try { -+ DerValue dv = new DerValue(issuer.getEncoded()); -+ dv.resetTag(DerValue.tag_Sequence); -+ cdp.setCRLIssuer(new GeneralNames(dv)); -+ } catch (GeneralNamesException e) { -+ throw new InvalidBERException("cRLIssuer " + e.toString()); -+ } catch (IOException e) { -+ throw new InvalidBERException("cRLIssuer " + e.toString()); -+ } -+ } -+ -+ return cdp; -+ -+ } -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CRLDistributionPointsExtension.java b/org/mozilla/jss/netscape/security/x509/CRLDistributionPointsExtension.java -new file mode 100644 -index 00000000..96fb06f8 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CRLDistributionPointsExtension.java -@@ -0,0 +1,390 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.BufferedOutputStream; -+import java.io.FileOutputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.Vector; -+ -+import org.mozilla.jss.asn1.ASN1Util; -+import org.mozilla.jss.asn1.InvalidBERException; -+import org.mozilla.jss.asn1.SEQUENCE; -+ -+import org.mozilla.jss.netscape.security.util.BitArray; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+ -+/** -+ * An extension that tells applications where to find the CRL for -+ * this certificate. -+ * -+ *
-+ * cRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
-+ *
-+ * DistributionPoint ::= SEQUENCE {
-+ *      distributionPoint       [0]     DistributionPointName OPTIONAL,
-+ *      reasons                 [1]     ReasonFlags OPTIONAL,
-+ *      cRLIssuer               [2]     GeneralNames OPTIONAL }
-+ *
-+ * DistributionPointName ::= CHOICE {
-+ *      fullName                [0]     GeneralNames,
-+ *      nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
-+ *
-+ * ReasonFlags ::= BIT STRING {
-+ *      unused                  (0),
-+ *      keyCompromise           (1),
-+ *      cACompromise            (2),
-+ *      affiliationChanged      (3),
-+ *      superseded              (4),
-+ *      cessationOfOperation    (5),
-+ *      certificateHold         (6) }
-+ * 
-+ */ -+public class CRLDistributionPointsExtension extends Extension -+ implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 8551761833349709229L; -+ // vector of CRLDistributionPoint -+ private SEQUENCE distributionPoints = new SEQUENCE(); -+ -+ // Cached DER-encoding to improve performance. -+ private byte[] cachedEncoding = null; -+ -+ /** -+ * This constructor is called by the CertificateExtensions class to decode -+ * an extension whose OID indicates it is a CRLDistributionsPoints -+ * extension. -+ */ -+ public CRLDistributionPointsExtension(Boolean critical, Object value) -+ //throws IOException -+ { -+ try { -+ -+ this.extensionId = PKIXExtensions.CRLDistributionPoints_Id; -+ this.critical = critical.booleanValue(); -+ this.extensionValue = ((byte[]) value).clone(); -+ -+ // decode the value -+ try { -+ SEQUENCE.OF_Template seqOfCRLDP = -+ new SEQUENCE.OF_Template(CRLDistributionPoint.getTemplate()); -+ -+ distributionPoints = -+ (SEQUENCE) ASN1Util.decode(seqOfCRLDP, extensionValue); -+ } catch (InvalidBERException e) { -+ throw new IOException("Invalid BER-encoding: " + e, e); -+ } -+ } catch (IOException e) { -+ System.out.println("Big error"); -+ System.out.println(e); -+ e.printStackTrace(); -+ //throw e; -+ } -+ } -+ -+ /** -+ * The Object Identifier for this extension. -+ */ -+ public static final String OID = "2.5.29.31"; -+ -+ /** -+ * Creates a new CRLDistributionPoints extension, with the given -+ * distribution point as the first element. -+ */ -+ public CRLDistributionPointsExtension(CRLDistributionPoint dp) { -+ this.extensionId = PKIXExtensions.CRLDistributionPoints_Id; -+ this.critical = false; -+ distributionPoints.addElement(dp); -+ } -+ -+ /** -+ * Adds an additional distribution point to the end of the sequence. -+ */ -+ public void addPoint(CRLDistributionPoint dp) { -+ distributionPoints.addElement(dp); -+ cachedEncoding = null; -+ } -+ -+ /** -+ * Returns the number of distribution points in the sequence. -+ */ -+ public int getNumPoints() { -+ return distributionPoints.size(); -+ } -+ -+ /** -+ * Returns the DistributionPoint at the given index in the sequence. -+ */ -+ public CRLDistributionPoint getPointAt(int index) { -+ return (CRLDistributionPoint) distributionPoints.elementAt(index); -+ } -+ -+ /** -+ * Sets the criticality of this extension. PKIX dictates that this -+ * extension SHOULD NOT be critical, so applications can make it critical -+ * if they have a very good reason. By default, the extension is not -+ * critical. -+ */ -+ public void setCritical(boolean critical) { -+ this.critical = critical; -+ } -+ -+ /** -+ * Encodes this extension to the given DerOutputStream. -+ * This method re-encodes each time it is called, so it is not very -+ * efficient. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ extensionValue = ASN1Util.encode(distributionPoints); -+ super.encode(out); -+ } -+ -+ /** -+ * Should be called if any change is made to this data structure -+ * so that the cached DER encoding can be discarded. -+ */ -+ public void flushCachedEncoding() { -+ cachedEncoding = null; -+ } -+ -+ ///////////////////////////////////////////////////////////// -+ // CertAttrSet interface -+ // This interface is not really appropriate for this extension -+ // because it is so complicated. Therefore, we only provide a -+ // minimal implementation. -+ ///////////////////////////////////////////////////////////// -+ public static final String NAME = "CRLDistributionPoints"; -+ -+ @Override -+ public String toString() { -+ return NAME; -+ } -+ -+ /** -+ * DER-encodes this extension to the given OutputStream. -+ */ -+ public void encode(OutputStream ostream) -+ throws CertificateException, IOException { -+ if (cachedEncoding == null) { -+ // only re-encode if necessary -+ DerOutputStream tmp = new DerOutputStream(); -+ encode(tmp); -+ cachedEncoding = tmp.toByteArray(); -+ } -+ ostream.write(cachedEncoding); -+ } -+ -+ public void decode(InputStream in) -+ throws CertificateException, IOException { -+ throw new IOException("Not supported"); -+ } -+ -+ public void set(String name, Object obj) -+ throws CertificateException, IOException { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CRLDistributionPointsExtension"); -+ } -+ -+ public Object get(String name) -+ throws CertificateException, IOException { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CRLDistributionPointsExtension"); -+ } -+ -+ public void delete(String name) -+ throws CertificateException, IOException { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CRLDistributionPointsExtension"); -+ } -+ -+ /* -+ * TODO use an empty collection to generate these -+ */ -+ public Enumeration getAttributeNames() { -+ return (new Vector()).elements(); -+ } -+ -+ public String getName() { -+ return NAME; -+ } -+ -+ /** -+ * Test driver. -+ */ -+ public static void main(String args[]) { -+ BufferedOutputStream bos = null; -+ try { -+ -+ if (args.length != 1) { -+ System.out.println("Usage: CRLDistributionPointsExtentions " + -+ ""); -+ System.exit(-1); -+ } -+ -+ bos = new BufferedOutputStream( -+ new FileOutputStream(args[0])); -+ -+ // URI only -+ CRLDistributionPoint cdp = new CRLDistributionPoint(); -+ URIName uri = new URIName("http://www.mycrl.com/go/here"); -+ GeneralNames generalNames = new GeneralNames(); -+ generalNames.addElement(uri); -+ cdp.setFullName(generalNames); -+ CRLDistributionPointsExtension crldpExt = -+ new CRLDistributionPointsExtension(cdp); -+ -+ // DN only -+ cdp = new CRLDistributionPoint(); -+ X500Name dn = new X500Name("CN=Otis Smith,E=otis@fedoraproject.org" + -+ ",OU=Certificate Server,O=Fedora,C=US"); -+ generalNames = new GeneralNames(); -+ generalNames.addElement(dn); -+ cdp.setFullName(generalNames); -+ crldpExt.addPoint(cdp); -+ -+ // DN + reason -+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 }); -+ cdp = new CRLDistributionPoint(); -+ cdp.setFullName(generalNames); -+ cdp.setReasons(ba); -+ crldpExt.addPoint(cdp); -+ -+ // relative DN + reason + crlIssuer -+ cdp = new CRLDistributionPoint(); -+ RDN rdn = new RDN("OU=foobar dept"); -+ cdp.setRelativeName(rdn); -+ cdp.setReasons(ba); -+ cdp.setCRLIssuer(generalNames); -+ crldpExt.addPoint(cdp); -+ -+ crldpExt.setCritical(true); -+ crldpExt.encode(bos); -+ -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } finally { -+ if (bos != null) { -+ try { -+ bos.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ -+ /** -+ * Represents a reason that a cert may be revoked. These reasons are -+ * expressed in a ReasonFlags bit string. -+ */ -+ public static class Reason { -+ -+ private String name; -+ private byte bitMask; -+ -+ private Reason() { -+ } -+ -+ private Reason(String name, byte bitMask) { -+ this.name = name; -+ this.bitMask = bitMask; -+ map.put(name, this); -+ list.addElement(this); -+ } -+ -+ private static Hashtable map = new Hashtable(); -+ private static Vector list = new Vector(); -+ -+ public static Reason fromString(String name) { -+ return map.get(name); -+ } -+ -+ public String getName() { -+ return name; -+ } -+ -+ public byte getBitMask() { -+ return bitMask; -+ } -+ -+ /** -+ * Given a bit array representing reason flags, extracts the reasons -+ * and returns them as an array. -+ * -+ * @param bitFlags A bit vector containing reason flags. -+ * @return An array of reasons contained in the bit vector. -+ * May be zero-length but will not be null. -+ */ -+ public static Reason[] bitArrayToReasonArray(byte bitFlags) { -+ return bitArrayToReasonArray(new byte[] { bitFlags }); -+ } -+ -+ /** -+ * Given a bit array representing reason flags, extracts the reasons -+ * and returns them as an array. Currently, only the first byte -+ * of the bitflags are examined. -+ * -+ * @param bitFlags A bit vector containing reason flags. The format -+ * is big-endian (MSB first). Only the first byte is examined. -+ * @return An array of reasons contained in the bit vector. -+ * May be zero-length but will not be null. -+ */ -+ public static Reason[] bitArrayToReasonArray(byte[] bitFlags) { -+ byte first = bitFlags[0]; -+ int size = list.size(); -+ Vector result = new Vector(); -+ for (int i = 0; i < size; i++) { -+ Reason r = list.elementAt(i); -+ byte b = r.getBitMask(); -+ if ((first & b) != 0) { -+ result.addElement(r); -+ } -+ } -+ size = result.size(); -+ Reason[] retval = new Reason[size]; -+ for (int i = 0; i < size; i++) { -+ retval[i] = result.elementAt(i); -+ } -+ return retval; -+ } -+ -+ public static final Reason UNUSED = -+ new Reason("unused", (byte) 0x80); -+ public static final Reason KEY_COMPROMISE = -+ new Reason("keyCompromise", (byte) 0x40); -+ public static final Reason CA_COMPROMISE = -+ new Reason("cACompromise", (byte) 0x20); -+ public static final Reason AFFILIATION_CHANGED = -+ new Reason("affiliationChanged", (byte) 0x10); -+ public static final Reason SUPERSEDED = -+ new Reason("superseded", (byte) 0x08); -+ public static final Reason CESSATION_OF_OPERATION = -+ new Reason("cessationOfOperation", (byte) 0x04); -+ public static final Reason CERTIFICATE_HOLD = -+ new Reason("certificateHold", (byte) 0x02); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CRLExtensions.java b/org/mozilla/jss/netscape/security/x509/CRLExtensions.java -new file mode 100755 -index 00000000..8537046e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CRLExtensions.java -@@ -0,0 +1,254 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.lang.reflect.Constructor; -+import java.lang.reflect.InvocationTargetException; -+import java.security.cert.CRLException; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the CRL Extensions. -+ * -+ * @author Hemma Prafullchandra -+ * @version 1.4 -+ */ -+public class CRLExtensions extends Vector { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 365767738692986418L; -+ private Hashtable map; -+ -+ // Parse the encoded extension -+ private void parseExtension(Extension ext) throws X509ExtensionException { -+ try { -+ Class extClass = OIDMap.getClass(ext.getExtensionId()); -+ if (extClass == null) { // Unsupported extension -+ if (ext.isCritical()) { -+ throw new IOException("Unsupported CRITICAL extension: " -+ + ext.getExtensionId()); -+ } else { -+ map.put(ext.getExtensionId().toString(), ext); -+ addElement(ext); -+ return; -+ } -+ } -+ Class[] params = { Boolean.class, Object.class }; -+ Constructor cons = extClass.getConstructor(params); -+ byte[] extData = ext.getExtensionValue(); -+ int extLen = extData.length; -+ Object value = Array.newInstance(byte.class, extLen); -+ -+ for (int i = 0; i < extLen; i++) { -+ Array.setByte(value, i, extData[i]); -+ } -+ Object[] passed = new Object[] { Boolean.valueOf(ext.isCritical()), -+ value }; -+ CertAttrSet crlExt = (CertAttrSet) cons.newInstance(passed); -+ map.put(crlExt.getName(), (Extension) crlExt); -+ addElement((Extension) crlExt); -+ -+ } catch (InvocationTargetException invk) { -+ throw new X509ExtensionException( -+ invk.getTargetException().getMessage()); -+ -+ } catch (Exception e) { -+ throw new X509ExtensionException(e.toString()); -+ } -+ } -+ -+ /** -+ * Default constructor. -+ */ -+ public CRLExtensions() { -+ map = new Hashtable(); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the Extension from. -+ * @exception CRLException on decoding errors. -+ * @exception X509ExtensionException on extension handling errors. -+ */ -+ public CRLExtensions(DerInputStream in) -+ throws CRLException, X509ExtensionException { -+ -+ map = new Hashtable(); -+ try { -+ DerValue[] exts = in.getSequence(5); -+ -+ for (int i = 0; i < exts.length; i++) { -+ Extension ext = new Extension(exts[i]); -+ parseExtension(ext); -+ } -+ } catch (IOException e) { -+ throw new CRLException("Parsing error: " + e.toString()); -+ } -+ } -+ -+ /** -+ * Decode the extensions from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception CRLException on decoding or validity errors. -+ * @exception X509ExtensionException on extension handling errors. -+ */ -+ public void decode(InputStream in) -+ throws CRLException, X509ExtensionException { -+ try { -+ DerValue val = new DerValue(in); -+ DerInputStream str = val.toDerInputStream(); -+ -+ map = new Hashtable(); -+ DerValue[] exts = str.getSequence(5); -+ -+ for (int i = 0; i < exts.length; i++) { -+ Extension ext = new Extension(exts[i]); -+ parseExtension(ext); -+ } -+ } catch (IOException e) { -+ throw new CRLException("Parsing error: " + e.toString()); -+ } -+ } -+ -+ /** -+ * Encode the extensions in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @param isExplicit the tag indicating whether this is an entry -+ * extension or a CRL extension. -+ * @exception CRLException on encoding errors. -+ */ -+ public void encode(OutputStream out, boolean isExplicit) -+ throws CRLException { -+ try (DerOutputStream tmp = new DerOutputStream()) { -+ // #381559 -+ if (size() == 0) -+ return; -+ DerOutputStream extOut = new DerOutputStream(); -+ for (int i = 0; i < size(); i++) { -+ Object thisOne = elementAt(i); -+ if (thisOne instanceof CertAttrSet) -+ ((CertAttrSet) thisOne).encode(extOut); -+ else if (thisOne instanceof Extension) -+ ((Extension) thisOne).encode(extOut); -+ else -+ throw new CRLException("Illegal extension object"); -+ } -+ -+ DerOutputStream seq = new DerOutputStream(); -+ seq.write(DerValue.tag_Sequence, extOut); -+ -+ if (isExplicit) { -+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, (byte) 0), seq); -+ out.write(tmp.toByteArray()); -+ } else { -+ out.write(seq.toByteArray()); -+ } -+ } catch (IOException e) { -+ throw new CRLException("Encoding error: " + e.toString()); -+ } catch (CertificateException e) { -+ throw new CRLException("Encoding error: " + e.toString()); -+ } -+ } -+ -+ /** -+ * Get the extension with this alias. -+ * -+ * @param alias the identifier string for the extension to retrieve. -+ * @exception X509ExtensionException on extension handling errors. -+ */ -+ public Extension get(String alias) throws X509ExtensionException { -+ X509AttributeName attr = new X509AttributeName(alias); -+ String name; -+ String id = attr.getPrefix(); -+ if (id.equalsIgnoreCase(X509CertImpl.NAME)) { // fully qualified -+ int index = alias.lastIndexOf("."); -+ name = alias.substring(index + 1); -+ } else -+ name = alias; -+ Extension ext = map.get(name); -+ if (ext == null) -+ throw new X509ExtensionException("No extension found with name: " -+ + alias); -+ return ext; -+ } -+ -+ /** -+ * Set the extension value with this alias. -+ * -+ * @param alias the identifier string for the extension to set. -+ * @param obj the Object to set the extension identified by the -+ * alias. -+ * @exception IOException on errors. -+ */ -+ public void set(String alias, Extension obj) throws IOException { -+ map.put(alias, obj); -+ addElement(obj); -+ } -+ -+ /** -+ * Return an enumeration of names of the extensions. -+ * -+ * @return an enumeration of the names of the extensions in this CRL. -+ */ -+ public Enumeration getElements() { -+ return (map.elements()); -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = super.hashCode(); -+ result = prime * result + ((map == null) ? 0 : map.hashCode()); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (!super.equals(obj)) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ CRLExtensions other = (CRLExtensions) obj; -+ if (map == null) { -+ if (other.map != null) -+ return false; -+ } else if (!map.equals(other.map)) -+ return false; -+ return true; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CRLNumberExtension.java b/org/mozilla/jss/netscape/security/x509/CRLNumberExtension.java -new file mode 100755 -index 00000000..3918158f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CRLNumberExtension.java -@@ -0,0 +1,227 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.math.BigInteger; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the CRL Number Extension. -+ * -+ *

-+ * This extension, if present, conveys a monotonically increasing sequence number for each CRL issued by a given CA -+ * through a specific CA X.500 Directory entry or CRL distribution point. This extension allows users to easily -+ * determine when a particular CRL supersedes another CRL. -+ * -+ * @author Hemma Prafullchandra -+ * @version 1.2 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class CRLNumberExtension extends Extension -+ implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 2992307666566322402L; -+ /** -+ * Attribute name. -+ */ -+ public static final String NAME = "CRLNumber"; -+ public static final String NUMBER = "value"; -+ -+ private BigInt crlNumber = null; -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ if (crlNumber == null) -+ throw new IOException("Unintialized CRL number extension"); -+ try (DerOutputStream os = new DerOutputStream()) { -+ os.putInteger(this.crlNumber); -+ this.extensionValue = os.toByteArray(); -+ } -+ } -+ -+ /** -+ * Create a CRLNumberExtension with the integer value . -+ * The criticality is set to false. -+ * -+ * @param crlNum the value to be set for the extension. -+ */ -+ public CRLNumberExtension(int crlNum) throws IOException { -+ this.crlNumber = new BigInt(crlNum); -+ this.extensionId = PKIXExtensions.CRLNumber_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a CRLNumberExtension with the BigInteger value . -+ * The criticality is set to false. -+ * -+ * @param crlNum the value to be set for the extension. -+ */ -+ public CRLNumberExtension(BigInteger crlNum) throws IOException { -+ this.crlNumber = new BigInt(crlNum); -+ this.extensionId = PKIXExtensions.CRLNumber_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a CRLNumberExtension with the BigInteger value . -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param crlNum the value to be set for the extension. -+ */ -+ public CRLNumberExtension(Boolean critical, BigInteger crlNum) throws IOException { -+ this.crlNumber = new BigInt(crlNum); -+ this.extensionId = PKIXExtensions.CRLNumber_Id; -+ this.critical = critical.booleanValue(); -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public CRLNumberExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.CRLNumber_Id; -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ this.crlNumber = val.getInteger(); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (name.equalsIgnoreCase(NUMBER)) { -+ if (!(obj instanceof BigInteger)) { -+ throw new IOException("Attribute must be of type BigInteger."); -+ } -+ crlNumber = new BigInt((BigInteger) obj); -+ } else { -+ throw new IOException("Attribute name not recognized by" -+ + " CertAttrSet:CRLNumber."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(NUMBER)) { -+ if (crlNumber == null) -+ return null; -+ else -+ return crlNumber.toBigInteger(); -+ } else { -+ throw new IOException("Attribute name not recognized by" -+ + " CertAttrSet:CRLNumber."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(NUMBER)) { -+ crlNumber = null; -+ } else { -+ throw new IOException("Attribute name not recognized by" -+ + " CertAttrSet:CRLNumber."); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the CRLNumberExtension. -+ */ -+ public String toString() { -+ String s = super.toString() + "CRL Number: " + -+ ((crlNumber == null) ? "" : crlNumber.toString()) -+ + "\n"; -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ this.extensionId = PKIXExtensions.CRLNumber_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(NUMBER); -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CRLReasonExtension.java b/org/mozilla/jss/netscape/security/x509/CRLReasonExtension.java -new file mode 100644 -index 00000000..350ea481 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CRLReasonExtension.java -@@ -0,0 +1,243 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the CRLReason Extension of CRL entry. -+ * -+ *

-+ * This extension, if present, defines the identifies the reason for the certificate revocation. -+ * -+ * @author galperin -+ * @version $Revision$, $Date$ -+ * @see Extension -+ * @see CertAttrSet -+ */ -+ -+public final class CRLReasonExtension extends Extension implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 4544973296866779535L; -+ /** -+ * Canned instances for all revocation reasons -+ */ -+ public static final CRLReasonExtension UNSPECIFIED = new CRLReasonExtension(RevocationReason.UNSPECIFIED); -+ public static final CRLReasonExtension KEY_COMPROMISE = new CRLReasonExtension(RevocationReason.KEY_COMPROMISE); -+ public static final CRLReasonExtension CA_COMPROMISE = new CRLReasonExtension(RevocationReason.CA_COMPROMISE); -+ public static final CRLReasonExtension AFFILIATION_CHANGED = new CRLReasonExtension( -+ RevocationReason.AFFILIATION_CHANGED); -+ public static final CRLReasonExtension SUPERSEDED = new CRLReasonExtension(RevocationReason.SUPERSEDED); -+ public static final CRLReasonExtension CESSATION_OF_OPERATION = new CRLReasonExtension( -+ RevocationReason.CESSATION_OF_OPERATION); -+ public static final CRLReasonExtension CERTIFICATE_HOLD = new CRLReasonExtension(RevocationReason.CERTIFICATE_HOLD); -+ public static final CRLReasonExtension REMOVE_FROM_CRL = new CRLReasonExtension(RevocationReason.REMOVE_FROM_CRL); -+ public static final CRLReasonExtension PRIVILEGE_WITHDRAWN = new CRLReasonExtension( -+ RevocationReason.PRIVILEGE_WITHDRAWN); -+ public static final CRLReasonExtension AA_COMPROMISE = new CRLReasonExtension(RevocationReason.AA_COMPROMISE); -+ -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "CRLReason"; -+ public static final String REASON = "value"; -+ -+ private RevocationReason mReason = null; -+ -+ public RevocationReason getReason() { -+ return mReason; -+ } -+ -+ /** -+ * Default constructor -+ * -+ */ -+ -+ public CRLReasonExtension() { -+ this.extensionId = PKIXExtensions.ReasonCode_Id; -+ this.critical = false; -+ mReason = null; -+ } -+ -+ /** -+ * Create extension value for specific revocation reason -+ * -+ */ -+ -+ public CRLReasonExtension(RevocationReason reason) { -+ this.extensionId = PKIXExtensions.ReasonCode_Id; -+ this.critical = false; -+ mReason = reason; -+ } -+ -+ public CRLReasonExtension(Boolean critical, RevocationReason reason) -+ throws IOException { -+ this.extensionId = PKIXExtensions.ReasonCode_Id; -+ this.critical = critical.booleanValue(); -+ mReason = reason; -+ } -+ -+ /** -+ * Create the object from the passed DER encoded value. -+ * -+ * @param derVal the DerValue decoded from the stream. -+ * @exception IOException on decoding errors. -+ */ -+ public CRLReasonExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.ReasonCode_Id; -+ this.critical = critical.booleanValue(); -+ -+ byte[] extValue = ((byte[]) value).clone(); -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ int reasonCode = val.getEnumerated(); -+ mReason = RevocationReason.fromInt(reasonCode); -+ if (mReason == null) -+ throw new IOException("Unknown revocation reason value " + reasonCode); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof RevocationReason)) { -+ throw new IOException("Attribute must be of type RevocationReason."); -+ } -+ -+ if (name.equalsIgnoreCase(REASON)) { -+ mReason = (RevocationReason) obj; -+ } else { -+ throw new IOException("Name not recognized by CRLReason"); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(REASON)) { -+ return mReason; -+ } else { -+ throw new IOException("Name not recognized by CRLReason"); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(REASON)) { -+ mReason = null; -+ } else { -+ throw new IOException("Name not recognized by CRLReason"); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the ReasonFlags. -+ */ -+ public String toString() { -+ String s = super.toString() + "CRL Reason [" + mReason + "]\n"; -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ if (mReason == null) -+ throw new IOException("Unintialized CRLReason extension"); -+ try (DerOutputStream os = new DerOutputStream()) { -+ os.putEnumerated(mReason.toInt()); -+ this.extensionValue = os.toByteArray(); -+ } -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(REASON); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ public boolean equals(Object other) { -+ if (this == other) -+ return true; -+ else if (other instanceof CRLReasonExtension) -+ return ((CRLReasonExtension) other).mReason == mReason && -+ ((CRLReasonExtension) other).critical == critical; -+ else -+ return false; -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + ((mReason == null) ? 0 : mReason.hashCode()); -+ return result; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertAndKeyGen.java b/org/mozilla/jss/netscape/security/x509/CertAndKeyGen.java -new file mode 100644 -index 00000000..626bb796 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertAndKeyGen.java -@@ -0,0 +1,290 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.security.InvalidKeyException; -+import java.security.KeyPair; -+import java.security.KeyPairGenerator; -+import java.security.NoSuchAlgorithmException; -+import java.security.NoSuchProviderException; -+import java.security.PrivateKey; -+import java.security.PublicKey; -+import java.security.SecureRandom; -+import java.security.Signature; -+import java.security.SignatureException; -+import java.security.cert.CertificateEncodingException; -+import java.security.cert.CertificateException; -+import java.security.cert.X509Certificate; -+import java.util.Date; -+ -+import org.mozilla.jss.netscape.security.pkcs.PKCS10; -+ -+/** -+ * Generate a pair of keys, and provide access to them. This class is -+ * provided primarily for ease of use. -+ * -+ *

-+ * This provides some simple certificate management functionality. Specifically, it allows you to create self-signed -+ * X.509 certificates as well as PKCS 10 based certificate signing requests. -+ * -+ *

-+ * Keys for some public key signature algorithms have algorithm parameters, such as DSS/DSA. Some sites' Certificate -+ * Authorities adopt fixed algorithm parameters, which speeds up some operations including key generation and signing. -+ * At this time, this interface -+ * does not provide a way to provide such algorithm parameters, e.g. -+ * by providing the CA certificate which includes those parameters. -+ * -+ *

-+ * Also, note that at this time only signature-capable keys may be acquired through this interface. Diffie-Hellman keys, -+ * used for secure key exchange, may be supported later. -+ * -+ * @author David Brownell -+ * @author Hemma Prafullchandra -+ * @version 1.44 -+ * @see PKCS10 -+ * @see X509CertImpl -+ */ -+public final class CertAndKeyGen { -+ /** -+ * Creates a CertAndKeyGen object for a particular key type -+ * and signature algorithm. -+ * -+ * @param keyType type of key, e.g. "RSA", "DSA" -+ * @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA", -+ * "MD2WithRSA", "SHAwithDSA". -+ * @exception NoSuchAlgorithmException on unrecognized algorithms. -+ */ -+ public CertAndKeyGen(String keyType, String sigAlg) -+ throws NoSuchAlgorithmException { -+ keyGen = KeyPairGenerator.getInstance(keyType); -+ this.sigAlg = sigAlg; -+ } -+ -+ /** -+ * Sets the source of random numbers used when generating keys. -+ * If you do not provide one, a system default facility is used. -+ * You may wish to provide your own source of random numbers -+ * to get a reproducible sequence of keys and signatures, or -+ * because you may be able to take advantage of strong sources -+ * of randomness/entropy in your environment. -+ * -+ * @deprecated All random numbers come from PKCS #11 now. -+ */ -+ public void setRandom(SecureRandom generator) { -+ } -+ -+ // want "public void generate (X509Certificate)" ... inherit DSA/D-H param -+ -+ /** -+ * Generates a random public/private key pair, with a given key -+ * size. Different algorithms provide different degrees of security -+ * for the same key size, because of the "work factor" involved in -+ * brute force attacks. As computers become faster, it becomes -+ * easier to perform such attacks. Small keys are to be avoided. -+ * -+ *

-+ * Note that not all values of "keyBits" are valid for all algorithms, and not all public key algorithms are -+ * currently supported for use in X.509 certificates. If the algorithm you specified does not produce X.509 -+ * compatible keys, an invalid key exception is thrown. -+ * -+ * @param keyBits the number of bits in the keys. -+ * @exception InvalidKeyException if the environment does not -+ * provide X.509 public keys for this signature algorithm. -+ */ -+ public void generate(int keyBits) -+ throws InvalidKeyException { -+ KeyPair pair; -+ -+ try { -+ keyGen.initialize(keyBits); -+ pair = keyGen.generateKeyPair(); -+ -+ } catch (Exception e) { -+ throw new IllegalArgumentException(e.getMessage()); -+ } -+ -+ PublicKey publicKey = pair.getPublic(); -+ -+ if (publicKey instanceof X509Key) { -+ this.publicKey = (X509Key) publicKey; -+ -+ } else { -+ throw new InvalidKeyException("public key " + publicKey + -+ " not an X509Key."); -+ } -+ privateKey = pair.getPrivate(); -+ } -+ -+ /** -+ * Returns the public key of the generated key pair. -+ */ -+ public X509Key getPublicKey() { -+ return publicKey; -+ } -+ -+ /** -+ * Returns the private key of the generated key pair. -+ * -+ *

-+ * Be extremely careful when handling private keys. -+ * When private keys are not kept secret, they lose their ability -+ * to securely authenticate specific entities ... that is a huge -+ * security risk! -+ */ -+ public PrivateKey getPrivateKey() { -+ return privateKey; -+ } -+ -+ /** -+ * Returns a self-signed X.509v1 certificate for the public key. -+ * The certificate is immediately valid. -+ * -+ *

-+ * Such certificates normally are used to identify a "Certificate Authority" (CA). Accordingly, they will not always -+ * be accepted by other parties. However, such certificates are also useful when you are bootstrapping your security -+ * infrastructure, or deploying system prototypes. -+ * -+ * @deprecated Use the new -+ * -+ * @param myname X.500 name of the subject (who is also the issuer) -+ * @param validity how long the certificate should be valid, in seconds -+ */ -+ public X509Cert getSelfCert(X500Name myname, long validity) -+ throws InvalidKeyException, SignatureException, NoSuchAlgorithmException { -+ X509Certificate cert; -+ -+ try { -+ cert = getSelfCertificate(myname, validity); -+ return new X509Cert(cert.getEncoded()); -+ } catch (CertificateException e) { -+ throw new SignatureException(e.getMessage()); -+ } catch (NoSuchProviderException e) { -+ throw new NoSuchAlgorithmException(e.getMessage()); -+ } catch (IOException e) { -+ throw new SignatureException(e.getMessage()); -+ } -+ } -+ -+ /** -+ * Returns a self-signed X.509v3 certificate for the public key. -+ * The certificate is immediately valid. No extensions. -+ * -+ *

-+ * Such certificates normally are used to identify a "Certificate Authority" (CA). Accordingly, they will not always -+ * be accepted by other parties. However, such certificates are also useful when you are bootstrapping your security -+ * infrastructure, or deploying system prototypes. -+ * -+ * @param myname X.500 name of the subject (who is also the issuer) -+ * @param validity how long the certificate should be valid, in seconds -+ * @exception CertificateException on certificate handling errors. -+ * @exception InvalidKeyException on key handling errors. -+ * @exception SignatureException on signature handling errors. -+ * @exception NoSuchAlgorithmException on unrecognized algorithms. -+ * @exception NoSuchProviderException on unrecognized providers. -+ */ -+ public X509Certificate getSelfCertificate(X500Name myname, long validity) -+ throws CertificateException, InvalidKeyException, SignatureException, -+ NoSuchAlgorithmException, NoSuchProviderException { -+ X500Signer issuer; -+ X509CertImpl cert; -+ Date firstDate, lastDate; -+ -+ try { -+ issuer = getSigner(myname); -+ -+ firstDate = new Date(); -+ lastDate = new Date(); -+ lastDate.setTime(lastDate.getTime() + validity * 1000); -+ -+ CertificateValidity interval = -+ new CertificateValidity(firstDate, lastDate); -+ -+ X509CertInfo info = new X509CertInfo(); -+ // Add all mandatory attributes -+ info.set(X509CertInfo.VERSION, -+ new CertificateVersion(CertificateVersion.V1)); -+ info.set(X509CertInfo.SERIAL_NUMBER, -+ new CertificateSerialNumber((int) (firstDate.getTime() / 1000))); -+ AlgorithmId algID = issuer.getAlgorithmId(); -+ info.set(X509CertInfo.ALGORITHM_ID, -+ new CertificateAlgorithmId(algID)); -+ info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(myname)); -+ info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey)); -+ info.set(X509CertInfo.VALIDITY, interval); -+ info.set(X509CertInfo.ISSUER, -+ new CertificateIssuerName(issuer.getSigner())); -+ -+ cert = new X509CertImpl(info); -+ cert.sign(privateKey, algID.getName()); -+ -+ return cert; -+ -+ } catch (IOException e) { -+ throw new CertificateEncodingException("getSelfCert: " + -+ e.getMessage()); -+ } -+ } -+ -+ /** -+ * Returns a PKCS #10 certificate request. The caller uses either PKCS10.print or -+ * PKCS10.toByteArray operations on the result, to get the request in an appropriate -+ * transmission format. -+ * -+ *

-+ * PKCS #10 certificate requests are sent, along with some proof of identity, to Certificate Authorities (CAs) which -+ * then issue X.509 public key certificates. -+ * -+ * @param myname X.500 name of the subject -+ * @exception InvalidKeyException on key handling errors. -+ * @exception SignatureException on signature handling errors. -+ */ -+ public PKCS10 getCertRequest(X500Name myname) -+ throws InvalidKeyException, SignatureException { -+ PKCS10 req = new PKCS10(publicKey); -+ -+ try { -+ req.encodeAndSign(getSigner(myname)); -+ -+ } catch (CertificateException e) { -+ throw new SignatureException(sigAlg + " CertificateException"); -+ -+ } catch (IOException e) { -+ throw new SignatureException(sigAlg + " IOException"); -+ -+ } catch (NoSuchAlgorithmException e) { -+ // "can't happen" -+ throw new SignatureException(sigAlg + " unavailable?"); -+ } -+ return req; -+ } -+ -+ private X500Signer getSigner(X500Name me) -+ throws InvalidKeyException, NoSuchAlgorithmException { -+ Signature signature = Signature.getInstance(sigAlg); -+ -+ signature.initSign(privateKey); -+ return new X500Signer(signature, me); -+ } -+ -+ private String sigAlg; -+ private KeyPairGenerator keyGen; -+ private X509Key publicKey; -+ private PrivateKey privateKey; -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertAttrSet.java b/org/mozilla/jss/netscape/security/x509/CertAttrSet.java -new file mode 100755 -index 00000000..7527e5a4 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertAttrSet.java -@@ -0,0 +1,120 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+ -+/** -+ * This interface defines the methods required of a certificate attribute. -+ * Examples of X.509 certificate attributes are Validity, Issuer_Name, and -+ * Subject Name. A CertAttrSet may compromise one attribute or many -+ * attributes. -+ *

-+ * A CertAttrSet itself can also be comprised of other sub-sets. In the case of X.509 V3 certificates, for example, the -+ * "extensions" attribute has subattributes, such as those for KeyUsage and AuthorityKeyIdentifier. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.9 -+ * @see CertificateException -+ */ -+public interface CertAttrSet { -+ /** -+ * Returns a short string describing this certificate attribute. -+ * -+ * @return value of this certificate attribute in -+ * printable form. -+ */ -+ String toString(); -+ -+ /** -+ * Encodes the attribute to the output stream in a format -+ * that can be parsed by the decode method. -+ * -+ * @param out the OutputStream to encode the attribute to. -+ * -+ * @exception CertificateException on encoding or validity errors. -+ * @exception IOException on other errors. -+ */ -+ void encode(OutputStream out) -+ throws CertificateException, IOException; -+ -+ /** -+ * Decodes the attribute in the input stream. -+ * -+ * @param in the InputStream to read the encoded attribute from. -+ * -+ * @exception CertificateException on decoding or validity errors. -+ * @exception IOException on other errors. -+ */ -+ void decode(InputStream in) -+ throws CertificateException, IOException; -+ -+ /** -+ * Sets an attribute value within this CertAttrSet. -+ * -+ * @param name the name of the attribute (e.g. "x509.info.key") -+ * @param obj the attribute object. -+ * -+ * @exception CertificateException on attribute handling errors. -+ * @exception IOException on other errors. -+ */ -+ void set(String name, Object obj) -+ throws CertificateException, IOException; -+ -+ /** -+ * Gets an attribute value for this CertAttrSet. -+ * -+ * @param name the name of the attribute to return. -+ * -+ * @exception CertificateException on attribute handling errors. -+ * @exception IOException on other errors. -+ */ -+ Object get(String name) -+ throws CertificateException, IOException; -+ -+ /** -+ * Deletes an attribute value from this CertAttrSet. -+ * -+ * @param name the name of the attribute to delete. -+ * -+ * @exception CertificateException on attribute handling errors. -+ * @exception IOException on other errors. -+ */ -+ void delete(String name) -+ throws CertificateException, IOException; -+ -+ /** -+ * Returns an enumeration of the names of the attributes existing within -+ * this attribute. -+ * -+ * @return an enumeration of the attribute names. -+ */ -+ Enumeration getAttributeNames(); -+ -+ /** -+ * Returns the name (identifier) of this CertAttrSet. -+ * -+ * @return the name of this CertAttrSet. -+ */ -+ String getName(); -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertException.java b/org/mozilla/jss/netscape/security/x509/CertException.java -new file mode 100644 -index 00000000..6696fd4a ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertException.java -@@ -0,0 +1,165 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+/** -+ * CertException indicates one of a variety of certificate problems. -+ * -+ * @version 1.18 -+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class CertException extends SecurityException { -+ -+ // Zero is reserved. -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -4046189948107720588L; -+ -+ /** Indicates that the signature in the certificate is not valid. */ -+ public static final int verf_INVALID_SIG = 1; -+ -+ /** Indicates that the certificate was revoked, and so is invalid. */ -+ public static final int verf_INVALID_REVOKED = 2; -+ -+ /** Indicates that the certificate is not yet valid. */ -+ public static final int verf_INVALID_NOTBEFORE = 3; -+ -+ /** Indicates that the certificate has expired and so is not valid. */ -+ public static final int verf_INVALID_EXPIRED = 4; -+ -+ /** -+ * Indicates that a certificate authority in the certification -+ * chain is not trusted. -+ */ -+ public static final int verf_CA_UNTRUSTED = 5; -+ -+ /** Indicates that the certification chain is too long. */ -+ public static final int verf_CHAIN_LENGTH = 6; -+ -+ /** Indicates an error parsing the ASN.1/DER encoding of the certificate. */ -+ public static final int verf_PARSE_ERROR = 7; -+ -+ /** Indicates an error constructing a certificate or certificate chain. */ -+ public static final int err_CONSTRUCTION = 8; -+ -+ /** Indicates a problem with the public key */ -+ public static final int err_INVALID_PUBLIC_KEY = 9; -+ -+ /** Indicates a problem with the certificate version */ -+ public static final int err_INVALID_VERSION = 10; -+ -+ /** Indicates a problem with the certificate format */ -+ public static final int err_INVALID_FORMAT = 11; -+ -+ /** Indicates a problem with the certificate encoding */ -+ public static final int err_ENCODING = 12; -+ -+ // Private data members -+ private int verfCode; -+ private String moreData; -+ -+ /** -+ * Constructs a certificate exception using an error code -+ * (verf_*) and a string describing the context -+ * of the error. -+ */ -+ public CertException(int code, String moredata) { -+ verfCode = code; -+ moreData = moredata; -+ } -+ -+ /** -+ * Constructs a certificate exception using just an error code, -+ * without a string describing the context. -+ */ -+ public CertException(int code) { -+ verfCode = code; -+ } -+ -+ /** -+ * Returns the error code with which the exception was created. -+ */ -+ public int getVerfCode() { -+ return verfCode; -+ } -+ -+ /** -+ * Returns a string describing the context in which the exception -+ * was reported. -+ */ -+ public String getMoreData() { -+ return moreData; -+ } -+ -+ /** -+ * Return a string corresponding to the error code used to create -+ * this exception. -+ */ -+ public String getVerfDescription() { -+ switch (verfCode) { -+ case verf_INVALID_SIG: -+ return "The signature in the certificate is not valid."; -+ case verf_INVALID_REVOKED: -+ return "The certificate has been revoked."; -+ case verf_INVALID_NOTBEFORE: -+ return "The certificate is not yet valid."; -+ case verf_INVALID_EXPIRED: -+ return "The certificate has expired."; -+ case verf_CA_UNTRUSTED: -+ return "The Authority which issued the certificate is not trusted."; -+ case verf_CHAIN_LENGTH: -+ return "The certificate path to a trusted authority is too long."; -+ case verf_PARSE_ERROR: -+ return "The certificate could not be parsed."; -+ case err_CONSTRUCTION: -+ return "There was an error when constructing the certificate."; -+ case err_INVALID_PUBLIC_KEY: -+ return "The public key was not in the correct format."; -+ case err_INVALID_VERSION: -+ return "The certificate has an invalid version number."; -+ case err_INVALID_FORMAT: -+ return "The certificate has an invalid format."; -+ case err_ENCODING: -+ return "Problem encountered while encoding the data."; -+ -+ default: -+ return "Unknown code: " + verfCode; -+ } -+ } -+ -+ /** -+ * Returns a string describing the certificate exception. -+ */ -+ public String toString() { -+ return "[Certificate Exception: " + getMessage() + "]"; -+ } -+ -+ /** -+ * Returns a string describing the certificate exception. -+ */ -+ public String getMessage() { -+ return getVerfDescription() -+ + ((moreData != null) -+ ? ("\n (" + moreData + ")") : ""); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertParseError.java b/org/mozilla/jss/netscape/security/x509/CertParseError.java -new file mode 100644 -index 00000000..c03627a6 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertParseError.java -@@ -0,0 +1,40 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+//back out these changes until backwards compatibility with -+//CertException is not an issue. -+//import java.security.CertificateException; -+ -+/** -+ * CertException indicates one of a variety of certificate problems. -+ * -+ * @version 1.7 -+ * @author David Brownell -+ */ -+ -+class CertParseError extends CertException { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -7623327377774730807L; -+ -+ CertParseError(String where) { -+ super(CertException.verf_PARSE_ERROR, where); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateAlgorithmId.java b/org/mozilla/jss/netscape/security/x509/CertificateAlgorithmId.java -new file mode 100644 -index 00000000..1071a6dd ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateAlgorithmId.java -@@ -0,0 +1,187 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the AlgorithmId for the Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.7 -+ */ -+public class CertificateAlgorithmId implements CertAttrSet, Serializable { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 6084780721443376563L; -+ -+ private AlgorithmId algId; -+ -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.algorithmID"; -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "algorithmID"; -+ public static final String ALGORITHM = "algorithm"; -+ -+ /** -+ * Default constructor for the certificate attribute. -+ * -+ * @param algId the Algorithm identifier -+ */ -+ public CertificateAlgorithmId(AlgorithmId algId) { -+ this.algId = algId; -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the serial number from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateAlgorithmId(DerInputStream in) throws IOException { -+ DerValue val = in.getDerValue(); -+ algId = AlgorithmId.parse(val); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed stream. -+ * -+ * @param in the InputStream to read the serial number from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateAlgorithmId(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ algId = AlgorithmId.parse(val); -+ } -+ -+ /** -+ * Return the algorithm identifier as user readable string. -+ */ -+ public String toString() { -+ if (algId == null) -+ return ""; -+ return (algId.toString() + -+ ", OID = " + (algId.getOID()).toString() + "\n"); -+ } -+ -+ private void writeObject(ObjectOutputStream stream) throws IOException { -+ encode(stream); -+ } -+ -+ private void readObject(ObjectInputStream stream) throws IOException { -+ decode(stream); -+ } -+ -+ /** -+ * Encode the algorithm identifier in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ algId.encode(tmp); -+ -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Decode the algorithm identifier from the passed stream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ algId = AlgorithmId.parse(derVal); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof AlgorithmId)) { -+ throw new IOException("Attribute must be of type AlgorithmId."); -+ } -+ if (name.equalsIgnoreCase(ALGORITHM)) { -+ algId = (AlgorithmId) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateAlgorithmId."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(ALGORITHM)) { -+ return (algId); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateAlgorithmId."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(ALGORITHM)) { -+ algId = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateAlgorithmId."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(ALGORITHM); -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateChain.java b/org/mozilla/jss/netscape/security/x509/CertificateChain.java -new file mode 100644 -index 00000000..5e026772 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateChain.java -@@ -0,0 +1,139 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.security.cert.X509Certificate; -+ -+import org.mozilla.jss.netscape.security.pkcs.ContentInfo; -+import org.mozilla.jss.netscape.security.pkcs.PKCS7; -+import org.mozilla.jss.netscape.security.pkcs.SignerInfo; -+ -+public class CertificateChain implements Serializable { -+ public CertificateChain() { -+ } -+ -+ /** -+ * constructs a certificate chain from a certificate. -+ * -+ * @param cert a certificate -+ */ -+ public CertificateChain(X509Certificate cert) { -+ mChain = new X509Certificate[1]; -+ mChain[0] = cert; -+ } -+ -+ /** -+ * constructs a certificate chain from a X509 certificate array. -+ * -+ * @param chain a certificate array. -+ */ -+ public CertificateChain(X509Certificate[] chain) { -+ mChain = chain.clone(); -+ } -+ -+ /** -+ * returns the certificate at specified index in chain. -+ * -+ * @param index the index. -+ * @return the X509 certificate at the given index. -+ */ -+ public X509Certificate getCertificate(int index) { -+ return mChain[index]; -+ } -+ -+ /** -+ * returns the first certificate in chain. -+ * -+ * @return the X509 certificate at the given index. -+ */ -+ public X509Certificate getFirstCertificate() { -+ return mChain[0]; -+ } -+ -+ /** -+ * returns the certificate chain as an array of X509 certificates. -+ * -+ * @return an array of X509 Certificates. -+ */ -+ public X509Certificate[] getChain() { -+ return mChain.clone(); -+ } -+ -+ public void encode(OutputStream out) -+ throws IOException { -+ encode(out, true); -+ } -+ -+ /** -+ * encode in PKCS7 blob. -+ */ -+ public void encode(OutputStream out, boolean sort) -+ throws IOException { -+ PKCS7 p7 = new PKCS7(new AlgorithmId[0], -+ new ContentInfo(new byte[0]), mChain, -+ new SignerInfo[0]); -+ p7.encodeSignedData(out, sort); -+ } -+ -+ /** -+ * decode from PKCS7 blob. -+ */ -+ public void decode(InputStream in) -+ throws IOException { -+ PKCS7 p7 = new PKCS7(in); -+ mChain = p7.getCertificates(); -+ } -+ -+ /** -+ * for serialization -+ */ -+ private void writeObject(java.io.ObjectOutputStream out) -+ throws IOException { -+ encode(out); -+ } -+ -+ /** -+ * for serialization -+ */ -+ private void readObject(java.io.ObjectInputStream in) -+ throws IOException { -+ decode(in); -+ } -+ -+ /** -+ * Converts the certificate chain to a readable string. -+ */ -+ public String toString() { -+ -+ String s = "[\n"; -+ if (mChain == null) -+ return "[empty]"; -+ StringBuffer tempBuffer = new StringBuffer(); -+ for (int i = 0; i < mChain.length; i++) { -+ tempBuffer.append(mChain[i].toString()); -+ } -+ s += tempBuffer.toString() + "]\n"; -+ return s; -+ } -+ -+ private X509Certificate[] mChain = null; -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateExtensions.java b/org/mozilla/jss/netscape/security/x509/CertificateExtensions.java -new file mode 100644 -index 00000000..c449ad49 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateExtensions.java -@@ -0,0 +1,303 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.lang.reflect.Array; -+import java.lang.reflect.Constructor; -+import java.lang.reflect.InvocationTargetException; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the Extensions attribute for the Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.11 -+ * @see CertAttrSet -+ */ -+public class CertificateExtensions extends Vector -+ implements CertAttrSet, Serializable { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -7172635300185788849L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions"; -+ /** -+ * name -+ */ -+ public static final String NAME = "extensions"; -+ -+ private Hashtable map; -+ -+ // Parse the encoded extension -+ public void parseExtension(Extension ext) throws IOException { -+ try { -+ @SuppressWarnings("unchecked") -+ Class extClass = (Class) OIDMap.getClass(ext.getExtensionId()); -+ if (extClass == null) { // Unsupported extension -+ map.put(ext.getExtensionId().toString(), ext); -+ addElement(ext); -+ return; -+ } -+ Class[] params = { Boolean.class, Object.class }; -+ Constructor cons = extClass.getConstructor(params); -+ -+ byte[] extData = ext.getExtensionValue(); -+ int extLen = extData.length; -+ Object value = Array.newInstance(byte.class, extLen); -+ -+ for (int i = 0; i < extLen; i++) { -+ Array.setByte(value, i, extData[i]); -+ } -+ Object[] passed = new Object[] { Boolean.valueOf(ext.isCritical()), -+ value }; -+ CertAttrSet certExt = cons.newInstance(passed); -+ if (certExt != null && certExt.getName() != null) { -+ map.put(certExt.getName(), (Extension) certExt); -+ addElement((Extension) certExt); -+ } -+ -+ } catch (NoSuchMethodException e) { -+ throw new IOException(e); -+ -+ } catch (InvocationTargetException e) { -+ Throwable t = e.getTargetException(); -+ if (t instanceof IOException) { -+ throw (IOException)t; -+ } -+ throw new IOException(t); -+ -+ } catch (Exception e) { -+ throw new IOException(e); -+ } -+ } -+ -+ /** -+ * Default constructor for the certificate attribute. -+ */ -+ public CertificateExtensions() { -+ map = new Hashtable(); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the Extension from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateExtensions(DerInputStream in) -+ throws IOException { -+ -+ map = new Hashtable(); -+ DerValue[] exts = in.getSequence(5); -+ -+ for (int i = 0; i < exts.length; i++) { -+ Extension ext = new Extension(exts[i]); -+ parseExtension(ext); -+ } -+ } -+ -+ /** -+ * Decode the extensions from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ DerInputStream str = val.toDerInputStream(); -+ -+ map = new Hashtable(); -+ DerValue[] exts = str.getSequence(5); -+ -+ for (int i = 0; i < exts.length; i++) { -+ Extension ext = new Extension(exts[i]); -+ parseExtension(ext); -+ } -+ } -+ -+ /** -+ * Decode the extensions from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decodeEx(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ DerInputStream str = null; -+ if (val.isConstructed() && val.isContextSpecific((byte) 3)) { -+ str = val.data; -+ } else { -+ str = val.toDerInputStream(); -+ } -+ -+ map = new Hashtable(); -+ DerValue[] exts = str.getSequence(5); -+ -+ for (int i = 0; i < exts.length; i++) { -+ Extension ext = new Extension(exts[i]); -+ parseExtension(ext); -+ } -+ } -+ -+ private void writeObject(ObjectOutputStream stream) throws CertificateException, IOException { -+ encode(stream); -+ } -+ -+ private void readObject(ObjectInputStream stream) throws CertificateException, IOException { -+ decodeEx(stream); -+ } -+ -+ /** -+ * Encode the extensions in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @exception CertificateException on encoding errors. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) -+ throws CertificateException, IOException { -+ try (DerOutputStream tmp = new DerOutputStream()) { -+ DerOutputStream extOut = new DerOutputStream(); -+ for (int i = 0; i < size(); i++) { -+ Object thisOne = elementAt(i); -+ if (thisOne instanceof CertAttrSet) -+ ((CertAttrSet) thisOne).encode(extOut); -+ else if (thisOne instanceof Extension) -+ ((Extension) thisOne).encode(extOut); -+ else -+ throw new CertificateException("Invalid extension object"); -+ } -+ -+ DerOutputStream seq = new DerOutputStream(); -+ seq.write(DerValue.tag_Sequence, extOut); -+ -+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 3), -+ seq); -+ -+ out.write(tmp.toByteArray()); -+ } -+ } -+ -+ /** -+ * Set the attribute value. -+ * -+ * @param name the extension name used in the cache. -+ * @param obj the object to set. -+ * @exception IOException if the object could not be cached. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ map.put(name, (Extension) obj); -+ addElement((Extension) obj); -+ } -+ -+ /** -+ * Get the attribute value. -+ * -+ * @param name the extension name used in the lookup. -+ * @exception IOException if named extension is not found. -+ */ -+ public Object get(String name) throws IOException { -+ Object obj = map.get(name); -+ if (obj == null) { -+ throw new IOException("No extension found with name " + name); -+ } -+ return (obj); -+ } -+ -+ /** -+ * Delete the attribute value. -+ * -+ * @param name the extension name used in the lookup. -+ * @exception IOException if named extension is not found. -+ */ -+ public void delete(String name) throws IOException { -+ Object obj = map.get(name); -+ if (obj == null) { -+ throw new IOException("No extension found with name " + name); -+ } -+ map.remove(name); -+ removeElement(obj); -+ } -+ -+ public Enumeration getNames() { -+ return map.keys(); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributes() { -+ return (map.elements()); -+ } -+ -+ public Enumeration getAttributeNames() { -+ return (map.keys()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = super.hashCode(); -+ result = prime * result + ((map == null) ? 0 : map.hashCode()); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (!super.equals(obj)) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ CertificateExtensions other = (CertificateExtensions) obj; -+ if (map == null) { -+ if (other.map != null) -+ return false; -+ } else if (!map.equals(other.map)) -+ return false; -+ return true; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateIssuerExtension.java b/org/mozilla/jss/netscape/security/x509/CertificateIssuerExtension.java -new file mode 100644 -index 00000000..85d94b94 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateIssuerExtension.java -@@ -0,0 +1,241 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the CRL Certificate Issuer Extension. -+ * -+ *

-+ * This CRL entry extension identifies the certificate issuer associated with an entry in an indirect CRL, i.e. a CRL -+ * that has the indirectCRL indicator set in its issuing distribution point extension. -+ * -+ * @see Extension -+ * @see CertAttrSet -+ */ -+ -+public class CertificateIssuerExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 8643788952936025986L; -+ /** -+ * Attribute name. -+ */ -+ public static final String NAME = "CertificateIssuer"; -+ public static final String CERTIFICATE_ISSUER = "value"; -+ -+ /** -+ * The Object Identifier for this extension. -+ */ -+ public static final String OID = "2.5.29.29"; -+ -+ // private data members -+ GeneralNames names = null; -+ -+ static { -+ try { -+ OIDMap.addAttribute(CertificateIssuerExtension.class.getName(), -+ OID, NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ // Encode this extension -+ private void encodeThis() throws IOException { -+ DerOutputStream os = new DerOutputStream(); -+ try { -+ names.encode(os); -+ } catch (GeneralNamesException e) { -+ throw new IOException(e); -+ } -+ this.extensionValue = os.toByteArray(); -+ } -+ -+ /** -+ * Create a CertificateIssuerExtension with the passed GeneralNames -+ * and criticality. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param names the GeneralNames for the issuer. -+ * @exception IOException on error. -+ */ -+ public CertificateIssuerExtension(Boolean critical, GeneralNames names) -+ throws IOException { -+ this.names = names; -+ this.extensionId = PKIXExtensions.CertificateIssuer_Id; -+ this.critical = critical.booleanValue(); -+ encodeThis(); -+ } -+ -+ /** -+ * Create a CertificateIssuerExtension with the passed GeneralNames. -+ * -+ * @param names the GeneralNames for the issuer. -+ * @exception IOException on error. -+ */ -+ public CertificateIssuerExtension(GeneralNames names) -+ throws IOException { -+ this.names = names; -+ this.extensionId = PKIXExtensions.CertificateIssuer_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a default CertificateIssuerExtension. -+ */ -+ public CertificateIssuerExtension() { -+ extensionId = PKIXExtensions.CertificateIssuer_Id; -+ critical = false; -+ names = new GeneralNames(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public CertificateIssuerExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.CertificateIssuer_Id; -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ try { -+ names = new GeneralNames(val); -+ } catch (GeneralNamesException e) { -+ throw new IOException("CertificateIssuerExtension: " + e, e); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the CertificateIssuerName. -+ */ -+ public String toString() { -+ if (names == null) -+ return ""; -+ String s = super.toString() + "CertificateIssuerName [\n" -+ + names.toString() + "]\n"; -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding error. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ extensionId = PKIXExtensions.CertificateIssuer_Id; -+ critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (name.equalsIgnoreCase(CERTIFICATE_ISSUER)) { -+ if (!(obj instanceof GeneralNames)) { -+ throw new IOException("Attribute value should be of" + -+ " type GeneralNames."); -+ } -+ names = (GeneralNames) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateIssuerName."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(CERTIFICATE_ISSUER)) { -+ return (names); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateIssuerName."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(CERTIFICATE_ISSUER)) { -+ names = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateIssuerName."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(CERTIFICATE_ISSUER); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateIssuerName.java b/org/mozilla/jss/netscape/security/x509/CertificateIssuerName.java -new file mode 100644 -index 00000000..ee075ebd ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateIssuerName.java -@@ -0,0 +1,172 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the X500Name attribute for the Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.6 -+ * @see CertAttrSet -+ */ -+public class CertificateIssuerName implements CertAttrSet { -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.issuer"; -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "issuer"; -+ public static final String DN_NAME = "dname"; -+ -+ // Private data member -+ private X500Name dnName; -+ -+ /** -+ * Default constructor for the certificate attribute. -+ * -+ * @param name the X500Name -+ */ -+ public CertificateIssuerName(X500Name name) { -+ this.dnName = name; -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the X500Name from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateIssuerName(DerInputStream in) throws IOException { -+ dnName = new X500Name(in); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed stream. -+ * -+ * @param in the InputStream to read the X500Name from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateIssuerName(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ dnName = new X500Name(derVal); -+ } -+ -+ /** -+ * Return the name as user readable string. -+ */ -+ public String toString() { -+ if (dnName == null) -+ return ""; -+ return (dnName.toString()); -+ } -+ -+ /** -+ * Encode the name in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ dnName.encode(tmp); -+ -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Decode the name in DER form from the stream. -+ * -+ * @param in the InputStream to marshal the contents from. -+ * @exception IOException on errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ dnName = new X500Name(derVal); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof X500Name)) { -+ throw new IOException("Attribute must be of type X500Name."); -+ } -+ if (name.equalsIgnoreCase(DN_NAME)) { -+ this.dnName = (X500Name) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateIssuerName."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(DN_NAME)) { -+ return (dnName); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateIssuerName."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(DN_NAME)) { -+ dnName = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateIssuerName."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(DN_NAME); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateIssuerUniqueIdentity.java b/org/mozilla/jss/netscape/security/x509/CertificateIssuerUniqueIdentity.java -new file mode 100644 -index 00000000..a0ea4ec0 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateIssuerUniqueIdentity.java -@@ -0,0 +1,185 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the subject/issuer unique identity attribute -+ * for the Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.6 -+ * @see CertAttrSet -+ */ -+public class CertificateIssuerUniqueIdentity implements CertAttrSet { -+ private UniqueIdentity id; -+ -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.issuerID"; -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "issuerID"; -+ public static final String ID = "id"; -+ -+ /** -+ * Default constructor for the certificate attribute. -+ * -+ * @param key the UniqueIdentity -+ */ -+ public CertificateIssuerUniqueIdentity(UniqueIdentity id) { -+ this.id = id; -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the UniqueIdentity from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateIssuerUniqueIdentity(DerInputStream in) -+ throws IOException { -+ id = new UniqueIdentity(in); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed stream. -+ * -+ * @param in the InputStream to read the UniqueIdentity from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateIssuerUniqueIdentity(InputStream in) -+ throws IOException { -+ DerValue val = new DerValue(in); -+ id = new UniqueIdentity(val); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER value. -+ * -+ * @param in the DerValue to read the UniqueIdentity from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateIssuerUniqueIdentity(DerValue val) -+ throws IOException { -+ id = new UniqueIdentity(val); -+ } -+ -+ /** -+ * Return the identity as user readable string. -+ */ -+ public String toString() { -+ if (id == null) -+ return ""; -+ return (id.toString()); -+ } -+ -+ /** -+ * Decode the identity in DER form from the stream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ id = new UniqueIdentity(val); -+ } -+ -+ /** -+ * Encode the identity in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ id.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT, false, (byte) 1)); -+ -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof UniqueIdentity)) { -+ throw new IOException("Attribute must be of type UniqueIdentity."); -+ } -+ if (name.equalsIgnoreCase(ID)) { -+ id = (UniqueIdentity) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateIssuerUniqueIdentity."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(ID)) { -+ return (id); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateIssuerUniqueIdentity."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(ID)) { -+ id = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateIssuerUniqueIdentity."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(ID); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificatePoliciesExtension.java b/org/mozilla/jss/netscape/security/x509/CertificatePoliciesExtension.java -new file mode 100644 -index 00000000..b3427c22 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificatePoliciesExtension.java -@@ -0,0 +1,339 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Arrays; -+import java.util.Collections; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+import org.mozilla.jss.netscape.security.util.Utils; -+ -+/** -+ * This class defines the Certificate Policies Extension. -+ * -+ *

-+ * The certificate policies extension conatins a sequence of policy information terms, each of which consists of an -+ * object identifier (OID) and optional qualifiers. These policy information terms indicate the policy under which the -+ * certificate has been issued and the purposes for which the certificate may be used. Aplications with specific policy -+ * requirements are expected to have a list of those policies which they will accept and to compare the policy OIDs in -+ * the certificate to that list. If this extension is critical, the path validation software must be able to interpret -+ * this extension, or must reject the certificate. -+ * -+ *

-+ * CertificatePolicies ::= SEQUENECE OF PolicyInformation
-+ * 
-+ * -+ * @author Christine Ho -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class CertificatePoliciesExtension extends Extension -+ implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -3729294064061837367L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions.CertificatePolicies"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "CertificatePolicies"; -+ public static final String INFOS = "infos"; -+ -+ // Private data members -+ private Vector mInfos; -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ try (DerOutputStream os = new DerOutputStream();) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ for (int i = 0; i < mInfos.size(); i++) { -+ mInfos.elementAt(i).encode(tmp); -+ } -+ os.write(DerValue.tag_Sequence, tmp); -+ extensionValue = os.toByteArray(); -+ } -+ } -+ -+ public CertificatePoliciesExtension(boolean critical, Vector infos) throws IOException { -+ this.mInfos = infos; -+ this.extensionId = PKIXExtensions.CertificatePolicies_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a CertificatePolicies with the Vector of CertificatePolicyInfo. -+ * -+ * @param infos the Vector of CertificatePolicyInfo. -+ */ -+ public CertificatePoliciesExtension(Vector infos) throws IOException { -+ this.mInfos = infos; -+ this.extensionId = PKIXExtensions.CertificatePolicies_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a default CertificatePoliciesExtension. -+ */ -+ public CertificatePoliciesExtension() { -+ this.extensionId = PKIXExtensions.CertificatePolicies_Id; -+ critical = false; -+ mInfos = new Vector(1, 1); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public CertificatePoliciesExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.CertificatePolicies_Id; -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for " + -+ "CertificatePoliciesExtension."); -+ } -+ mInfos = new Vector(1, 1); -+ while (val.data.available() != 0) { -+ DerValue seq = val.data.getDerValue(); -+ CertificatePolicyInfo info = new CertificatePolicyInfo(seq); -+ mInfos.addElement(info); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the policy extension. -+ */ -+ public String toString() { -+ if (mInfos == null) -+ return ""; -+ String s = super.toString() + "Certificate Policies [\n" -+ + mInfos.toString() + "]\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ extensionId = PKIXExtensions.CertificatePolicies_Id; -+ critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ @SuppressWarnings("unchecked") -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (name.equalsIgnoreCase(INFOS)) { -+ if (!(obj instanceof Vector)) { -+ throw new IOException("Attribute value should be of" + -+ " type Vector."); -+ } -+ mInfos = (Vector) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificatePoliciesExtension."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(INFOS)) { -+ return (mInfos); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificatePoliciesExtension."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(INFOS)) { -+ mInfos = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificatePoliciesExtension."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration> getAttributes() { -+ Vector> elements = new Vector>(); -+ elements.addElement(mInfos); -+ return (elements.elements()); -+ } -+ -+ private static final String[] NAMES = { INFOS }; -+ -+ @Override -+ public Enumeration getAttributeNames() { -+ // TODO Auto-generated method stub -+ return Collections.enumeration(Arrays.asList(NAMES)); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ public static void main(String args[]) { -+ -+ /** -+ * From ASN.1 dump -+ * -+ * 0 30 133: SEQUENCE { -+ * 3 30 45: . SEQUENCE { -+ * 5 06 3: . . OBJECT IDENTIFIER '1 2 3 5' -+ * 10 30 38: . . SEQUENCE { -+ * 12 30 36: . . . SEQUENCE { -+ * 14 06 8: . . . . OBJECT IDENTIFIER cps (1 3 6 1 5 5 7 2 1) -+ * : . . . . . (PKIX policy qualifier) -+ * 24 16 24: . . . . IA5String 'http://home.netscape.com' -+ * : . . . . } -+ * : . . . } -+ * : . . } -+ * 50 30 84: . SEQUENCE { -+ * 52 06 2: . . OBJECT IDENTIFIER '2 3 5' -+ * 56 30 78: . . SEQUENCE { -+ * 58 30 36: . . . SEQUENCE { -+ * 60 06 8: . . . . OBJECT IDENTIFIER cps (1 3 6 1 5 5 7 2 1) -+ * : . . . . . (PKIX policy qualifier) -+ * 70 16 24: . . . . IA5String 'http://home.netscape.com' -+ * : . . . . } -+ * 96 30 38: . . . SEQUENCE { -+ * 98 06 8: . . . . OBJECT IDENTIFIER unotice (1 3 6 1 5 5 7 2 2) -+ * : . . . . . (PKIX policy qualifier) -+ * 108 30 26: . . . . SEQUENCE { -+ * 110 30 16: . . . . . SEQUENCE { -+ * 112 1E 8: . . . . . . BMPString (1993) '_..o.r.g' -+ * 122 02 1: . . . . . . INTEGER 1 -+ * 125 02 1: . . . . . . INTEGER 2 -+ * : . . . . . . } -+ * 128 1E 6: . . . . . BMPString (1993) '_..d.t' -+ * : . . . . . } -+ * : . . . . } -+ * : . . . } -+ * : . . } -+ * : . } -+ **/ -+ -+ CertificatePolicyId plcyId0 = new CertificatePolicyId( -+ new ObjectIdentifier("1.2.3.5") -+ ); -+ PolicyQualifiers qualifiers0 = new PolicyQualifiers(); -+ CPSuri cpsQualifier0 = new CPSuri("http://home.netscape.com"); -+ PolicyQualifierInfo qualifierInfo0 = new PolicyQualifierInfo( -+ PolicyQualifierInfo.QT_CPS, -+ cpsQualifier0 -+ ); -+ qualifiers0.add(qualifierInfo0); -+ CertificatePolicyInfo info0 = new CertificatePolicyInfo( -+ plcyId0, qualifiers0); -+ CertificatePolicyId plcyId1 = new CertificatePolicyId( -+ new ObjectIdentifier("2.3.5") -+ ); -+ PolicyQualifiers qualifiers1 = new PolicyQualifiers(); -+ DisplayText org1 = new DisplayText(DisplayText.tag_BMPString, -+ "org"); -+ int nums[] = { 1, 2 }; -+ NoticeReference nr1 = new NoticeReference(org1, nums); -+ DisplayText dt1 = new DisplayText(DisplayText.tag_BMPString, -+ "dt"); -+ UserNotice userNotice1 = new UserNotice(nr1, dt1); -+ PolicyQualifierInfo qualifierInfo1 = new PolicyQualifierInfo( -+ PolicyQualifierInfo.QT_UNOTICE, -+ userNotice1 -+ ); -+ qualifiers1.add(qualifierInfo0); -+ qualifiers1.add(qualifierInfo1); -+ CertificatePolicyInfo info1 = new CertificatePolicyInfo( -+ plcyId1, qualifiers1); -+ Vector infos = new Vector(); -+ infos.addElement(info0); -+ infos.addElement(info1); -+ try { -+ CertificatePoliciesExtension ext = -+ new CertificatePoliciesExtension(infos); -+ -+ // BASE64 encode the whole thing and write it to stdout -+ System.out.println(Utils.base64encode(ext.getExtensionValue(), true)); -+ } catch (IOException e) { -+ System.out.println(e.toString()); -+ } -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificatePolicyId.java b/org/mozilla/jss/netscape/security/x509/CertificatePolicyId.java -new file mode 100644 -index 00000000..6b86910f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificatePolicyId.java -@@ -0,0 +1,85 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * Represent the CertificatePolicyId ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.5 -+ */ -+public class CertificatePolicyId implements java.io.Serializable { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -2376810529862707757L; -+ private ObjectIdentifier id; -+ -+ /** -+ * Create a CertificatePolicyId with the ObjectIdentifier. -+ * -+ * @param id the ObjectIdentifier for the policy id. -+ */ -+ public CertificatePolicyId(ObjectIdentifier id) { -+ this.id = id; -+ } -+ -+ /** -+ * Create the object from its Der encoded value. -+ * -+ * @param val the DER encoded value for the same. -+ */ -+ public CertificatePolicyId(DerValue val) throws IOException { -+ this.id = val.getOID(); -+ } -+ -+ /** -+ * Return the value of the CertificatePolicyId as an ObjectIdentifier. -+ */ -+ public ObjectIdentifier getIdentifier() { -+ return (id); -+ } -+ -+ /** -+ * Returns a printable representation of the CertificatePolicyId. -+ */ -+ public String toString() { -+ String s = "CertificatePolicyId: [" -+ + id.toString() -+ + "]\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Write the CertificatePolicyId to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putOID(id); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificatePolicyInfo.java b/org/mozilla/jss/netscape/security/x509/CertificatePolicyInfo.java -new file mode 100644 -index 00000000..558a7fd1 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificatePolicyInfo.java -@@ -0,0 +1,110 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the CertificatePolicyInformation ASN.1 object. -+ * -+ * @author Christine Ho -+ */ -+public class CertificatePolicyInfo implements java.io.Serializable { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -8516006396099280477L; -+ private CertificatePolicyId mPolicyIdentifier; -+ private PolicyQualifiers mPolicyQualifiers; -+ -+ /** -+ * Create a CertificatePolicyInfo with the passed CertificatePolicyId's. -+ * -+ * @param id the CertificatePolicyId. -+ */ -+ public CertificatePolicyInfo(CertificatePolicyId id) { -+ this.mPolicyIdentifier = id; -+ this.mPolicyQualifiers = null; -+ } -+ -+ public CertificatePolicyInfo(CertificatePolicyId id, PolicyQualifiers qualifiers) { -+ this.mPolicyIdentifier = id; -+ this.mPolicyQualifiers = qualifiers; -+ } -+ -+ /** -+ * Create the CertificatePolicyInfo from the DER encoded value. -+ * -+ * @param val the DER encoded value of the same. -+ */ -+ public CertificatePolicyInfo(DerValue val) throws IOException { -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for CertificatePolicyInfo"); -+ } -+ mPolicyIdentifier = new CertificatePolicyId(val.data.getDerValue()); -+ // The specification is not clear on whether qualifier is -+ // optional or not. GTE CyberTrust Root certificate has -+ // no qualifier. -+ if (val.data.available() == 0) { -+ mPolicyQualifiers = null; -+ } else { -+ mPolicyQualifiers = new PolicyQualifiers(val.data.getDerValue()); -+ } -+ } -+ -+ /** -+ * return the policy identifier of the policy info -+ */ -+ public CertificatePolicyId getPolicyIdentifier() { -+ return (mPolicyIdentifier); -+ } -+ -+ public PolicyQualifiers getPolicyQualifiers() { -+ return mPolicyQualifiers; -+ } -+ -+ /** -+ * Returns a printable representation of the CertificatePolicyId. -+ */ -+ public String toString() { -+ String s = "CertificatePolicyInfo: [\n" -+ + "PolicyIdentifier:" + mPolicyIdentifier.toString() -+ -+ + "]\n"; -+ return (s); -+ } -+ -+ /** -+ * Write the CertificatePolicyInfo to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ mPolicyIdentifier.encode(tmp); -+ if (mPolicyQualifiers != null) { -+ mPolicyQualifiers.encode(tmp); -+ } -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificatePolicyMap.java b/org/mozilla/jss/netscape/security/x509/CertificatePolicyMap.java -new file mode 100644 -index 00000000..9dc8d909 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificatePolicyMap.java -@@ -0,0 +1,100 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the CertificatePolicyMap ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.5 -+ */ -+public class CertificatePolicyMap { -+ private CertificatePolicyId issuerDomain; -+ private CertificatePolicyId subjectDomain; -+ -+ /** -+ * Create a CertificatePolicyMap with the passed CertificatePolicyId's. -+ * -+ * @param issuer the CertificatePolicyId for the issuer CA. -+ * @param subject the CertificatePolicyId for the subject CA. -+ */ -+ public CertificatePolicyMap(CertificatePolicyId issuer, -+ CertificatePolicyId subject) { -+ this.issuerDomain = issuer; -+ this.subjectDomain = subject; -+ } -+ -+ /** -+ * Create the CertificatePolicyMap from the DER encoded value. -+ * -+ * @param val the DER encoded value of the same. -+ */ -+ public CertificatePolicyMap(DerValue val) throws IOException { -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for CertificatePolicyMap"); -+ } -+ issuerDomain = new CertificatePolicyId(val.data.getDerValue()); -+ subjectDomain = new CertificatePolicyId(val.data.getDerValue()); -+ } -+ -+ /** -+ * Return the issuer CA part of the policy map. -+ */ -+ public CertificatePolicyId getIssuerIdentifier() { -+ return (issuerDomain); -+ } -+ -+ /** -+ * Return the subject CA part of the policy map. -+ */ -+ public CertificatePolicyId getSubjectIdentifier() { -+ return (subjectDomain); -+ } -+ -+ /** -+ * Returns a printable representation of the CertificatePolicyId. -+ */ -+ public String toString() { -+ String s = "CertificatePolicyMap: [\n" -+ + "IssuerDomain:" + issuerDomain.toString() -+ + "SubjectDomain:" + subjectDomain.toString() -+ + "]\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Write the CertificatePolicyMap to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ issuerDomain.encode(tmp); -+ subjectDomain.encode(tmp); -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificatePolicySet.java b/org/mozilla/jss/netscape/security/x509/CertificatePolicySet.java -new file mode 100644 -index 00000000..4e2ab295 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificatePolicySet.java -@@ -0,0 +1,86 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the certificate policy set ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.4 -+ */ -+public class CertificatePolicySet { -+ private Vector ids; -+ -+ /** -+ * The default constructor for this class. -+ * -+ * @param ids the sequence of CertificatePolicyId's. -+ */ -+ public CertificatePolicySet(Vector ids) { -+ this.ids = ids; -+ } -+ -+ /** -+ * Create the object from the DerValue. -+ * -+ * @param in the passed DerInputStream. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificatePolicySet(DerInputStream in) throws IOException { -+ ids = new Vector(1, 1); -+ DerValue[] seq = in.getSequence(5); -+ -+ for (int i = 0; i < seq.length; i++) { -+ CertificatePolicyId id = new CertificatePolicyId(seq[i]); -+ ids.addElement(id); -+ } -+ } -+ -+ /** -+ * Return printable form of the object. -+ */ -+ public String toString() { -+ String s = "CertificatePolicySet:[\n" -+ + ids.toString() -+ + "]\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Encode the policy set to the output stream. -+ * -+ * @param out the DerOutputStream to encode the data to. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ for (int i = 0; i < ids.size(); i++) { -+ ids.elementAt(i).encode(tmp); -+ } -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateSerialNumber.java b/org/mozilla/jss/netscape/security/x509/CertificateSerialNumber.java -new file mode 100644 -index 00000000..ee21610b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateSerialNumber.java -@@ -0,0 +1,191 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.math.BigInteger; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the SerialNumber attribute for the Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.6 -+ * @see CertAttrSet -+ */ -+public class CertificateSerialNumber implements CertAttrSet { -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.serialNumber"; -+ -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "serialNumber"; -+ public static final String NUMBER = "number"; -+ -+ private SerialNumber serial; -+ -+ /** -+ * Default constructor for the certificate attribute. -+ * -+ * @param serial the serial number for the certificate. -+ */ -+ public CertificateSerialNumber(BigInteger num) { -+ this.serial = new SerialNumber(num); -+ } -+ -+ /** -+ * Default constructor for the certificate attribute. -+ * -+ * @param serial the serial number for the certificate. -+ */ -+ public CertificateSerialNumber(int num) { -+ this.serial = new SerialNumber(num); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the serial number from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateSerialNumber(DerInputStream in) throws IOException { -+ serial = new SerialNumber(in); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed stream. -+ * -+ * @param in the InputStream to read the serial number from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateSerialNumber(InputStream in) throws IOException { -+ serial = new SerialNumber(in); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DerValue. -+ * -+ * @param val the DER encoded value. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateSerialNumber(DerValue val) throws IOException { -+ serial = new SerialNumber(val); -+ } -+ -+ /** -+ * Return the serial number as user readable string. -+ */ -+ public String toString() { -+ if (serial == null) -+ return ""; -+ return (serial.toString()); -+ } -+ -+ /** -+ * Encode the serial number in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ serial.encode(tmp); -+ -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Decode the serial number in DER form from the stream. -+ * -+ * @param in the InputStream to marshal the contents from. -+ * @exception IOException on errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ serial = new SerialNumber(derVal); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof SerialNumber)) { -+ throw new IOException("Attribute must be of type SerialNumber."); -+ } -+ if (name.equalsIgnoreCase(NUMBER)) { -+ serial = (SerialNumber) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateSerialNumber."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(NUMBER)) { -+ return (serial); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateSerialNumber."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(NUMBER)) { -+ serial = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateSerialNumber."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(NUMBER); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateSubjectName.java b/org/mozilla/jss/netscape/security/x509/CertificateSubjectName.java -new file mode 100644 -index 00000000..63150779 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateSubjectName.java -@@ -0,0 +1,211 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the X500Name attribute for the Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.6 -+ * @see CertAttrSet -+ */ -+public class CertificateSubjectName implements CertAttrSet, Serializable { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 503643453152834350L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.subject"; -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "subject"; -+ public static final String DN_NAME = "dname"; -+ -+ // Private data member -+ private X500Name dnName; -+ -+ /** -+ * Default constructor for the certificate attribute. -+ * -+ * @param name the X500Name -+ */ -+ public CertificateSubjectName(X500Name name) { -+ this.dnName = name; -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the X500Name from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateSubjectName(DerInputStream in) throws IOException { -+ dnName = new X500Name(in); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed stream. -+ * -+ * @param in the InputStream to read the X500Name from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateSubjectName(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ dnName = new X500Name(derVal); -+ } -+ -+ /** -+ * Return the name as user readable string. -+ */ -+ public String toString() { -+ if (dnName == null) -+ return ""; -+ return (dnName.toString()); -+ } -+ -+ private void writeObject(ObjectOutputStream stream) throws IOException { -+ encode(stream); -+ } -+ -+ private void readObject(ObjectInputStream stream) throws IOException { -+ decodeEx(stream); -+ } -+ -+ /** -+ * Encode the name in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ dnName.encode(tmp); -+ -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Decode the name in DER form from the stream. -+ * -+ * @param in the InputStream to marshal the contents from. -+ * @exception IOException on errors. -+ */ -+ public void decodeEx(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ -+ // dnName = new X500Name(derVal); -+ dnName = new X500Name(derVal.toByteArray()); -+ } -+ -+ /** -+ * Decode the name in DER form from the stream. -+ * -+ * @param in the InputStream to marshal the contents from. -+ * @exception IOException on errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ -+ dnName = new X500Name(derVal); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof X500Name)) { -+ throw new IOException("Attribute must be of type X500Name."); -+ } -+ if (name.equalsIgnoreCase(DN_NAME)) { -+ this.dnName = (X500Name) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateSubjectName."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(DN_NAME)) { -+ return (dnName); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateSubjectName."); -+ } -+ } -+ -+ /** -+ * Get underlying X500Name value. -+ * -+ * Where the type is known to be CertificateSubjectName, use -+ * this method instead of 'get' to avoid casts and exceptions. -+ */ -+ public X500Name getX500Name() { -+ return dnName; -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(DN_NAME)) { -+ dnName = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:CertificateSubjectName."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(DN_NAME); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateSubjectUniqueIdentity.java b/org/mozilla/jss/netscape/security/x509/CertificateSubjectUniqueIdentity.java -new file mode 100644 -index 00000000..1033621f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateSubjectUniqueIdentity.java -@@ -0,0 +1,185 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the subject/issuer unique identity attribute -+ * for the Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.6 -+ * @see CertAttrSet -+ */ -+public class CertificateSubjectUniqueIdentity implements CertAttrSet { -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.subjectID"; -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "subjectID"; -+ public static final String ID = "id"; -+ -+ private UniqueIdentity id; -+ -+ /** -+ * Default constructor for the certificate attribute. -+ * -+ * @param key the UniqueIdentity -+ */ -+ public CertificateSubjectUniqueIdentity(UniqueIdentity id) { -+ this.id = id; -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the UniqueIdentity from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateSubjectUniqueIdentity(DerInputStream in) -+ throws IOException { -+ id = new UniqueIdentity(in); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed stream. -+ * -+ * @param in the InputStream to read the UniqueIdentity from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateSubjectUniqueIdentity(InputStream in) -+ throws IOException { -+ DerValue val = new DerValue(in); -+ id = new UniqueIdentity(val); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER value. -+ * -+ * @param in the DerValue to read the UniqueIdentity from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateSubjectUniqueIdentity(DerValue val) -+ throws IOException { -+ id = new UniqueIdentity(val); -+ } -+ -+ /** -+ * Return the identity as user readable string. -+ */ -+ public String toString() { -+ if (id == null) -+ return ""; -+ return (id.toString()); -+ } -+ -+ /** -+ * Decode the identity in DER form from the stream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ id = new UniqueIdentity(val); -+ } -+ -+ /** -+ * Encode the identity in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ id.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT, false, (byte) 2)); -+ -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof UniqueIdentity)) { -+ throw new IOException("Attribute must be of type UniqueIdentity."); -+ } -+ if (name.equalsIgnoreCase(ID)) { -+ id = (UniqueIdentity) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateSubjectUniqueIdentity."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(ID)) { -+ return (id); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateSubjectUniqueIdentity."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(ID)) { -+ id = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateSubjectUniqueIdentity."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(ID); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateValidity.java b/org/mozilla/jss/netscape/security/x509/CertificateValidity.java -new file mode 100644 -index 00000000..b8171c89 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateValidity.java -@@ -0,0 +1,301 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.security.cert.CertificateExpiredException; -+import java.security.cert.CertificateNotYetValidException; -+import java.util.Date; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the interval for which the certificate is valid. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.12 -+ * @see CertAttrSet -+ */ -+public class CertificateValidity implements CertAttrSet, Serializable { -+ -+ private static final long serialVersionUID = 8277703278213804194L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.validity"; -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "validity"; -+ public static final String NOT_BEFORE = "notBefore"; -+ public static final String NOT_AFTER = "notAfter"; -+ private static final long YR_2050 = 2524636800000L; -+ -+ // Private data members -+ private Date notBefore; -+ private Date notAfter; -+ -+ // Returns the first time the certificate is valid. -+ private Date getNotBefore() { -+ return (new Date(notBefore.getTime())); -+ } -+ -+ // Returns the last time the certificate is valid. -+ private Date getNotAfter() { -+ return (new Date(notAfter.getTime())); -+ } -+ -+ // Construct the class from the DerValue -+ private void construct(DerValue derVal) throws IOException { -+ if (derVal.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoded CertificateValidity, " + -+ "starting sequence tag missing."); -+ } -+ // check if UTCTime encoded or GeneralizedTime -+ if (derVal.data.available() == 0) -+ throw new IOException("No data encoded for CertificateValidity"); -+ -+ DerInputStream derIn = new DerInputStream(derVal.toByteArray()); -+ DerValue[] seq = derIn.getSequence(2); -+ if (seq.length != 2) -+ throw new IOException("Invalid encoding for CertificateValidity"); -+ -+ if (seq[0].tag == DerValue.tag_UtcTime) { -+ notBefore = derVal.data.getUTCTime(); -+ } else if (seq[0].tag == DerValue.tag_GeneralizedTime) { -+ notBefore = derVal.data.getGeneralizedTime(); -+ } else { -+ throw new IOException("Invalid encoding for CertificateValidity"); -+ } -+ -+ if (seq[1].tag == DerValue.tag_UtcTime) { -+ notAfter = derVal.data.getUTCTime(); -+ } else if (seq[1].tag == DerValue.tag_GeneralizedTime) { -+ notAfter = derVal.data.getGeneralizedTime(); -+ } else { -+ throw new IOException("Invalid encoding for CertificateValidity"); -+ } -+ } -+ -+ /** -+ * Default constructor for the class. -+ */ -+ public CertificateValidity() { -+ } -+ -+ /** -+ * The default constructor for this class for the specified interval. -+ * -+ * @param notBefore the date and time before which the certificate -+ * is not valid. -+ * @param notAfter the date and time after which the certificate is -+ * not valid. -+ */ -+ public CertificateValidity(Date notBefore, Date notAfter) { -+ this.notBefore = notBefore; -+ this.notAfter = notAfter; -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the CertificateValidity from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateValidity(DerInputStream in) throws IOException { -+ DerValue derVal = in.getDerValue(); -+ construct(derVal); -+ } -+ -+ /** -+ * Return the validity period as user readable string. -+ */ -+ public String toString() { -+ if (notBefore == null || notAfter == null) -+ return ""; -+ return ("Validity: [From: " + notBefore.toString() + -+ ",\n To: " + notAfter.toString() + "]"); -+ } -+ -+ /** -+ * Decode the CertificateValidity period from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ construct(derVal); -+ } -+ -+ private void writeObject(ObjectOutputStream stream) throws IOException { -+ encode(stream); -+ } -+ -+ private void readObject(ObjectInputStream stream) throws IOException { -+ decode(stream); -+ } -+ -+ /** -+ * Encode the CertificateValidity period in DER form to the stream. -+ * -+ * @param out the OutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ // in cases where default constructor is used check for -+ // null values -+ if (notBefore == null || notAfter == null) { -+ throw new IOException("CertAttrSet:CertificateValidity:" + -+ " null values to encode.\n"); -+ } -+ try (DerOutputStream pair = new DerOutputStream(); -+ DerOutputStream seq = new DerOutputStream()) { -+ if (notBefore.getTime() < YR_2050) { -+ pair.putUTCTime(notBefore); -+ } else -+ pair.putGeneralizedTime(notBefore); -+ -+ if (notAfter.getTime() < YR_2050) { -+ pair.putUTCTime(notAfter); -+ } else { -+ pair.putGeneralizedTime(notAfter); -+ } -+ seq.write(DerValue.tag_Sequence, pair); -+ -+ out.write(seq.toByteArray()); -+ } -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof Date)) { -+ throw new IOException("Attribute must be of type Date."); -+ } -+ if (name.equalsIgnoreCase(NOT_BEFORE)) { -+ notBefore = (Date) obj; -+ } else if (name.equalsIgnoreCase(NOT_AFTER)) { -+ notAfter = (Date) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateValidity."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(NOT_BEFORE)) { -+ return (getNotBefore()); -+ } else if (name.equalsIgnoreCase(NOT_AFTER)) { -+ return (getNotAfter()); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateValidity."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(NOT_BEFORE)) { -+ notBefore = null; -+ } else if (name.equalsIgnoreCase(NOT_AFTER)) { -+ notAfter = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateValidity."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(NOT_BEFORE); -+ elements.addElement(NOT_AFTER); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ /** -+ * Verify that the current time is within the validity period. -+ * -+ * @exception CertificateExpiredException if the certificate has expired. -+ * @exception CertificateNotYetValidException if the certificate is not -+ * yet valid. -+ */ -+ public void valid() -+ throws CertificateNotYetValidException, CertificateExpiredException { -+ Date now = new Date(); -+ valid(now); -+ } -+ -+ /** -+ * Verify that the passed time is within the validity period. -+ * -+ * @param now the Date against which to compare the validity -+ * period. -+ * -+ * @exception CertificateExpiredException if the certificate has expired -+ * with respect to the Date supplied. -+ * @exception CertificateNotYetValidException if the certificate is not -+ * yet valid with respect to the Date supplied. -+ * -+ */ -+ public void valid(Date now) -+ throws CertificateNotYetValidException, CertificateExpiredException { -+ /* -+ * we use the internal Dates rather than the passed in Date -+ * because someone could override the Date methods after() -+ * and before() to do something entirely different. -+ */ -+ if (notBefore.after(now)) { -+ throw new CertificateNotYetValidException("NotBefore: " + -+ notBefore.toString()); -+ } -+ if (notAfter.before(now)) { -+ throw new CertificateExpiredException("NotAfter: " + -+ notAfter.toString()); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateVersion.java b/org/mozilla/jss/netscape/security/x509/CertificateVersion.java -new file mode 100644 -index 00000000..27b1473b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateVersion.java -@@ -0,0 +1,248 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the version of the X509 Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.8 -+ * @see CertAttrSet -+ */ -+public class CertificateVersion implements CertAttrSet { -+ /** -+ * X509Certificate Version 1 -+ */ -+ public static final int V1 = 0; -+ /** -+ * X509Certificate Version 2 -+ */ -+ public static final int V2 = 1; -+ /** -+ * X509Certificate Version 3 -+ */ -+ public static final int V3 = 2; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.version"; -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "version"; -+ public static final String VERSION = "number"; -+ -+ // Private data members -+ int version = V1; -+ -+ // Returns the version number. -+ private int getVersion() { -+ return (version); -+ } -+ -+ // Construct the class from the passed DerValue -+ private void construct(DerValue derVal) throws IOException { -+ if (derVal.isConstructed() && derVal.isContextSpecific()) { -+ derVal = derVal.data.getDerValue(); -+ version = derVal.getInteger().toInt(); -+ if (derVal.data.available() != 0) { -+ throw new IOException("X.509 version, bad format"); -+ } -+ } -+ } -+ -+ /** -+ * The default constructor for this class, -+ * sets the version to 0 (i.e. X.509 version 1). -+ */ -+ public CertificateVersion() { -+ version = V1; -+ } -+ -+ /** -+ * The constructor for this class for the required version. -+ * -+ * @param version the version for the certificate. -+ * @exception IOException if the version is not valid. -+ */ -+ public CertificateVersion(int version) throws IOException { -+ -+ // check that it is a valid version -+ if (version == V1 || version == V2 || version == V3) -+ this.version = version; -+ else { -+ throw new IOException("X.509 Certificate version " + -+ version + " not supported.\n"); -+ } -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the CertificateVersion from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateVersion(DerInputStream in) throws IOException { -+ version = V1; -+ DerValue derVal = in.getDerValue(); -+ -+ construct(derVal); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed stream. -+ * -+ * @param in the InputStream to read the CertificateVersion from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateVersion(InputStream in) throws IOException { -+ version = V1; -+ DerValue derVal = new DerValue(in); -+ -+ construct(derVal); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DerValue. -+ * -+ * @param val the Der encoded value. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateVersion(DerValue val) throws IOException { -+ version = V1; -+ -+ construct(val); -+ } -+ -+ /** -+ * Return the version number of the certificate. -+ */ -+ public String toString() { -+ return ("Version: V" + (version + 1)); -+ } -+ -+ /** -+ * Encode the CertificateVersion period in DER form to the stream. -+ * -+ * @param out the OutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ // Nothing for default -+ if (version == V1) { -+ return; -+ } -+ try (DerOutputStream tmp = new DerOutputStream(); -+ DerOutputStream seq = new DerOutputStream()) { -+ tmp.putInteger(new BigInt(version)); -+ -+ seq.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0), -+ tmp); -+ -+ out.write(seq.toByteArray()); -+ } -+ } -+ -+ /** -+ * Decode the CertificateVersion period in DER form from the stream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ construct(derVal); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof Integer)) { -+ throw new IOException("Attribute must be of type Integer."); -+ } -+ if (name.equalsIgnoreCase(VERSION)) { -+ version = ((Integer) obj).intValue(); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateVersion."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(VERSION)) { -+ return (Integer.valueOf(getVersion())); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateVersion."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(VERSION)) { -+ version = V1; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateVersion."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(VERSION); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ /** -+ * Compare versions. -+ */ -+ public int compare(int vers) { -+ return (version - vers); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/CertificateX509Key.java b/org/mozilla/jss/netscape/security/x509/CertificateX509Key.java -new file mode 100644 -index 00000000..d47b2b0a ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/CertificateX509Key.java -@@ -0,0 +1,188 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the X509Key attribute for the Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.5 -+ * @see CertAttrSet -+ */ -+public class CertificateX509Key implements CertAttrSet, Serializable { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 6718749024328681131L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.key"; -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "key"; -+ public static final String KEY = "value"; -+ -+ // Private data member -+ private X509Key key; -+ -+ /** -+ * Default constructor for the certificate attribute. -+ * -+ * @param key the X509Key -+ */ -+ public CertificateX509Key(X509Key key) { -+ this.key = key; -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the X509Key from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateX509Key(DerInputStream in) throws IOException { -+ DerValue val = in.getDerValue(); -+ key = X509Key.parse(val); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed stream. -+ * -+ * @param in the InputStream to read the X509Key from. -+ * @exception IOException on decoding errors. -+ */ -+ public CertificateX509Key(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ key = X509Key.parse(val); -+ } -+ -+ /** -+ * Return the key as printable string. -+ */ -+ public String toString() { -+ if (key == null) -+ return ""; -+ return (key.toString()); -+ } -+ -+ /** -+ * Decode the key in DER form from the stream. -+ * -+ * @param in the InputStream to unmarshal the contents from -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ key = X509Key.parse(val); -+ } -+ -+ private void writeObject(ObjectOutputStream stream) throws IOException { -+ encode(stream); -+ } -+ -+ private void readObject(ObjectInputStream stream) throws IOException { -+ decode(stream); -+ } -+ -+ /** -+ * Encode the key in DER form to the stream. -+ * -+ * @param out the OutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ key.encode(tmp); -+ -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof X509Key)) { -+ throw new IOException("Attribute must be of type X509Key."); -+ } -+ if (name.equalsIgnoreCase(KEY)) { -+ this.key = (X509Key) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateX509Key."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(KEY)) { -+ return (key); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateX509Key."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(KEY)) { -+ key = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet: CertificateX509Key."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(KEY); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/DNSName.java b/org/mozilla/jss/netscape/security/x509/DNSName.java -new file mode 100644 -index 00000000..3483cca2 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/DNSName.java -@@ -0,0 +1,90 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class implements the DNSName as required by the GeneralNames -+ * ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.4 -+ */ -+public class DNSName implements GeneralNameInterface { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -2907649488092607056L; -+ private String name; -+ -+ /** -+ * Create the DNSName object from the passed encoded Der value. -+ * -+ * @param derValue the encoded DER DNSName. -+ * @exception IOException on error. -+ */ -+ public DNSName(DerValue derValue) throws IOException { -+ name = derValue.getIA5String(); -+ } -+ -+ /** -+ * Create the DNSName object with the specified name. -+ * -+ * @param name the DNSName. -+ */ -+ public DNSName(String name) { -+ this.name = name; -+ } -+ -+ /** -+ * Return the type of the GeneralName. -+ */ -+ public int getType() { -+ return (GeneralNameInterface.NAME_DNS); -+ } -+ -+ /** -+ * Encode the DNS name into the DerOutputStream. -+ * -+ * @param out the DER stream to encode the DNSName to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putIA5String(name); -+ } -+ -+ /** -+ * Convert the name into user readable string. -+ */ -+ public String toString() { -+ return ("DNSName: " + name); -+ } -+ -+ /** -+ * Get the raw DNSName value. -+ */ -+ public String getValue() { -+ return name; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/DeltaCRLIndicatorExtension.java b/org/mozilla/jss/netscape/security/x509/DeltaCRLIndicatorExtension.java -new file mode 100755 -index 00000000..359ecbd6 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/DeltaCRLIndicatorExtension.java -@@ -0,0 +1,240 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.math.BigInteger; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the Delta CRL Indicator Extension. -+ * -+ *

-+ * The delta CRL indicator is a critical CRL extension that identifies a delta-CRL. The value of BaseCRLNumber -+ * identifies the CRL number of the base CRL that was used as the starting point in the generation of this delta- CRL. -+ * The delta-CRL contains the changes between the base CRL and the current CRL issued along with the delta-CRL. -+ * -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class DeltaCRLIndicatorExtension extends Extension -+ implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 7182919216525364676L; -+ /** -+ * Attribute name. -+ */ -+ public static final String NAME = "DeltaCRLIndicator"; -+ public static final String NUMBER = "value"; -+ -+ /** -+ * The Object Identifier for this extension. -+ */ -+ public static final String OID = "2.5.29.27"; -+ -+ private BigInt baseCRLNumber = null; -+ -+ static { -+ try { -+ OIDMap.addAttribute(DeltaCRLIndicatorExtension.class.getName(), -+ OID, NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ if (baseCRLNumber == null) -+ throw new IOException("Unintialized delta CRL indicator extension"); -+ try (DerOutputStream os = new DerOutputStream()) { -+ os.putInteger(this.baseCRLNumber); -+ this.extensionValue = os.toByteArray(); -+ } -+ } -+ -+ /** -+ * Create a DeltaCRLIndicatorExtension with the integer value. -+ * The criticality is set to true. -+ * -+ * @param baseCRLNum the value to be set for the extension. -+ */ -+ public DeltaCRLIndicatorExtension(int baseCRLNum) throws IOException { -+ this.baseCRLNumber = new BigInt(baseCRLNum); -+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a DeltaCRLIndicatorExtension with the BigInteger value. -+ * The criticality is set to true. -+ * -+ * @param baseCRLNum the value to be set for the extension. -+ */ -+ public DeltaCRLIndicatorExtension(BigInteger baseCRLNum) throws IOException { -+ this.baseCRLNumber = new BigInt(baseCRLNum); -+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a DeltaCRLIndicatorExtension with the BigInteger value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param baseCRLNum the value to be set for the extension. -+ */ -+ public DeltaCRLIndicatorExtension(Boolean critical, BigInteger baseCRLNum) -+ throws IOException { -+ this.baseCRLNumber = new BigInt(baseCRLNum); -+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id; -+ this.critical = critical.booleanValue(); -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public DeltaCRLIndicatorExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id; -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ this.baseCRLNumber = val.getInteger(); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (name.equalsIgnoreCase(NUMBER)) { -+ if (!(obj instanceof BigInteger)) { -+ throw new IOException("Attribute must be of type BigInteger."); -+ } -+ baseCRLNumber = new BigInt((BigInteger) obj); -+ } else { -+ throw new IOException("Attribute name not recognized by" + -+ " CertAttrSet:DeltaCRLIndicator."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(NUMBER)) { -+ if (baseCRLNumber == null) -+ return null; -+ else -+ return baseCRLNumber.toBigInteger(); -+ } else { -+ throw new IOException("Attribute name not recognized by" + -+ " CertAttrSet:DeltaCRLIndicator."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(NUMBER)) { -+ baseCRLNumber = null; -+ } else { -+ throw new IOException("Attribute name not recognized by" + -+ " CertAttrSet:DeltaCRLIndicator."); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the DeltaCRLIndicatorExtension. -+ */ -+ public String toString() { -+ String s = super.toString() + "Delta CRL Indicator: " + -+ ((baseCRLNumber == null) ? "" : baseCRLNumber.toString()) -+ + "\n"; -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ this.extensionId = PKIXExtensions.DeltaCRLIndicator_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(NUMBER); -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/DirStrConverter.java b/org/mozilla/jss/netscape/security/x509/DirStrConverter.java -new file mode 100644 -index 00000000..5bdb30c1 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/DirStrConverter.java -@@ -0,0 +1,172 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.CharacterCodingException; -+import java.nio.charset.CharsetEncoder; -+ -+import org.mozilla.jss.netscape.security.util.ASN1CharStrConvMap; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * A DirStrConverter converts a string to a DerValue of ASN.1 Directory String, -+ * which is a CHOICE of Printable (subset of ASCII), T.61 (Teletex) or -+ * Universal String (UCS-4), and vice versa. -+ * -+ *

-+ * The string to DerValue conversion is done as follows. If the string has only PrintableString characters it is -+ * converted to a ASN.1 Printable String using the PrintableString encoder from the global default ASN1CharStrConvMap. -+ * If it has only characters covered in the PrintableString or T.61 character set it is converted to a ASN.1 T.61 string -+ * using the T.61 encoder from the ASN1CharStrCovnMap. Otherwise it is converted to a ASN.1 UniversalString (UCS-4 -+ * character set) which covers all characters. -+ * -+ * @see AVAValueConverter -+ * @see ASN1CharStrConvMap -+ * -+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc. -+ */ -+ -+public class DirStrConverter implements AVAValueConverter { -+ // public constructors -+ -+ /** -+ * Constructs a DirStrConverter. -+ */ -+ public DirStrConverter() { -+ } -+ -+ // public functions -+ -+ /** -+ * Converts a string to a DER encoded ASN1 Directory String, which is a -+ * CHOICE of PrintableString, T.61String or UniversalString. -+ * The string is taken as is i.e. should not be in Ldap DN string syntax. -+ * -+ * @param ds a string representing a directory string value. -+ * -+ * @return a DerValue -+ * -+ * @exception IOException if the string cannot be converted, such as -+ * when a UniversalString encoder -+ * isn't available and the string contains -+ * characters covered only in the universal -+ * string (or UCS-4) character set. -+ */ -+ private static byte[] DefEncodingOrder = -+ new byte[] { -+ DerValue.tag_UTF8String, -+ DerValue.tag_PrintableString, -+ DerValue.tag_T61String, -+ DerValue.tag_UniversalString -+ }; -+ -+ public static synchronized void -+ setDefEncodingOrder(byte[] defEncodingOrder) { -+ DefEncodingOrder = defEncodingOrder; -+ } -+ -+ public DerValue getValue(String ds) -+ throws IOException { -+ return getValue(ds, DefEncodingOrder); -+ } -+ -+ /** -+ * Like getValue(String) with specified DER tags as encoding order. -+ */ -+ public DerValue getValue(String valueString, byte[] tags) throws IOException { -+ // try to convert to printable, then t61 the universal - -+ // i.e. from minimal to the most liberal. -+ -+ if (tags == null || tags.length == 0) -+ tags = DefEncodingOrder; -+ -+ for (int i = 0; i < tags.length; i++) { -+ try { -+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(tags[i]); -+ if (encoder == null) -+ continue; -+ -+ CharBuffer charBuffer = CharBuffer.wrap(valueString.toCharArray()); -+ ByteBuffer byteBuffer = encoder.encode(charBuffer); -+ -+ return new DerValue(tags[i], byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit()); -+ -+ } catch (CharacterCodingException e) { -+ continue; -+ } -+ } -+ -+ throw new IOException( -+ "Cannot convert the directory string value to a ASN.1 type"); -+ } -+ -+ /** -+ * Creates a DerValue from a BER encoded value, obtained from for example -+ * a attribute value in octothorpe form of a Ldap DN string. -+ * Checks if the BER encoded value is legal for a DirectoryString. -+ * -+ * NOTE: currently only supports DER encoding for the BER encoded value. -+ * -+ * @param berStream Byte array of a BER encoded value. -+ * -+ * @return DerValue object. -+ * -+ * @exception IOException If the BER value cannot be converted to a -+ * valid Directory String DER value. -+ */ -+ public DerValue getValue(byte[] berByteStream) -+ throws IOException { -+ DerValue value = new DerValue(berByteStream); -+ -+ /* -+ if (value.tag != DerValue.tag_PrintableString && -+ value.tag != DerValue.tag_T61String && -+ value.tag != DerValue.tag_UniversalString) -+ throw new IOException("Invalid Directory String AVA Value"); -+ */ -+ -+ return value; -+ } -+ -+ /** -+ * Converts a DerValue to a string. -+ * The string is not in any syntax, such as RFC1779 string syntax. -+ * -+ * @param avaValue a DerValue -+ * @return a string if the value can be converted. -+ * @exception IOException if a decoder needed for the -+ * conversion is not available. -+ */ -+ public String getAsString(DerValue avaValue) -+ throws IOException { -+ /* -+ if (avaValue.tag != DerValue.tag_PrintableString && -+ avaValue.tag != DerValue.tag_BMPString && -+ avaValue.tag != DerValue.tag_UniversalString && -+ avaValue.tag != DerValue.tag_T61String) -+ throw new IllegalArgumentException( -+ "Invalid Directory String value"); -+ // NOTE will return null if a decoder is not available. -+ */ -+ return avaValue.getASN1CharString(); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/DisplayText.java b/org/mozilla/jss/netscape/security/x509/DisplayText.java -new file mode 100644 -index 00000000..76610400 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/DisplayText.java -@@ -0,0 +1,85 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.Serializable; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the DisplayText. -+ * -+ * DisplayText ::= CHOICE { -+ * visibleString VisibleString (SIZE (1..200)), -+ * bmpString BMPString (SIZE (1..200)), -+ * utf8String UTF8String (SIZE (1..200)), -+ * } -+ * -+ * @author Thomas Kwan -+ */ -+public class DisplayText implements Serializable { -+ -+ private static final long serialVersionUID = -6521458152495173328L; -+ -+ /** Tag value indicating an ASN.1 "BMPString" value. */ -+ public final static byte tag_IA5String = 0x16; -+ public final static byte tag_BMPString = 0x1E; -+ public final static byte tag_VisibleString = 0x1A; -+ public final static byte tag_UTF8String = 0x0C; -+ -+ private byte mTag; -+ private String mS = null; -+ -+ public DisplayText(byte tag, String s) { -+ mTag = tag; -+ mS = s; -+ } -+ -+ public DisplayText(DerValue val) throws IOException { -+ mTag = val.tag; -+ mS = val.getAsString(); -+ } -+ -+ /** -+ * Write the DisplayText to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putStringType(mTag, mS); -+ } -+ -+ public String getText() { -+ return mS; -+ } -+ -+ public String toString() { -+ if (mTag == tag_IA5String) { -+ return "IA5String: " + mS; -+ } else if (mTag == tag_BMPString) { -+ return "BMPString: " + mS; -+ } else if (mTag == tag_VisibleString) { -+ return "VisibleString: " + mS; -+ } else { -+ return "UTF8String: " + mS; -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/EDIPartyName.java b/org/mozilla/jss/netscape/security/x509/EDIPartyName.java -new file mode 100644 -index 00000000..dedd3a7f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/EDIPartyName.java -@@ -0,0 +1,157 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the EDIPartyName of the GeneralName choice. -+ * The ASN.1 syntax for this is: -+ * -+ *

-+ * EDIPartyName ::= SEQUENCE {
-+ *     nameAssigner  [0]  DirectoryString OPTIONAL,
-+ *     partyName     [1]  DirectoryString }
-+ * 
-+ * -+ * @author Hemma Prafullchandra -+ * @version 1.2 -+ * @see GeneralName -+ * @see GeneralNames -+ * @see GeneralNameInterface -+ */ -+public class EDIPartyName implements GeneralNameInterface { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -8669257424766789063L; -+ // Private data members -+ private static final byte TAG_ASSIGNER = 0; -+ private static final byte TAG_PARTYNAME = 1; -+ -+ private String assigner = null; -+ private String party = null; -+ -+ /** -+ * Create the EDIPartyName object from the specified names. -+ * -+ * @param assignerName the name of the assigner -+ * @param partyName the name of the EDI party. -+ */ -+ public EDIPartyName(String assignerName, String partyName) { -+ this.assigner = assignerName; -+ this.party = partyName; -+ } -+ -+ /** -+ * Create the EDIPartyName object from the specified name. -+ * -+ * @param partyName the name of the EDI party. -+ */ -+ public EDIPartyName(String partyName) { -+ this.party = partyName; -+ } -+ -+ /** -+ * Create the EDIPartyName object from the passed encoded Der value. -+ * -+ * @param derValue the encoded DER EDIPartyName. -+ * @exception IOException on error. -+ */ -+ public EDIPartyName(DerValue derValue) throws IOException { -+ DerInputStream in = new DerInputStream(derValue.toByteArray()); -+ DerValue[] seq = in.getSequence(2); -+ -+ int len = seq.length; -+ if (len < 1 || len > 2) -+ throw new IOException("Invalid encoding of EDIPartyName"); -+ -+ for (int i = 0; i < len; i++) { -+ DerValue opt = seq[i]; -+ if (opt.isContextSpecific(TAG_ASSIGNER) && -+ !opt.isConstructed()) { -+ if (assigner != null) -+ throw new IOException("Duplicate nameAssigner found in" -+ + " EDIPartyName"); -+ opt = opt.data.getDerValue(); -+ assigner = opt.getAsString(); -+ } -+ if (opt.isContextSpecific(TAG_PARTYNAME) && -+ !opt.isConstructed()) { -+ if (party != null) -+ throw new IOException("Duplicate partyName found in" -+ + " EDIPartyName"); -+ opt = opt.data.getDerValue(); -+ party = opt.getAsString(); -+ } -+ } -+ } -+ -+ /** -+ * Return the type of the GeneralName. -+ */ -+ public int getType() { -+ return (GeneralNameInterface.NAME_EDI); -+ } -+ -+ /** -+ * Encode the EDI party name into the DerOutputStream. -+ * -+ * @param out the DER stream to encode the EDIPartyName to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tagged = new DerOutputStream(); -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (assigner != null) { -+ DerOutputStream tmp2 = new DerOutputStream(); -+ // XXX - shd check is chars fit into PrintableString -+ tmp2.putPrintableString(assigner); -+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_ASSIGNER), tmp2); -+ } -+ if (party == null) { -+ tagged.close(); -+ tmp.close(); -+ throw new IOException("Cannot have null partyName"); -+ } -+ -+ // XXX - shd check is chars fit into PrintableString -+ tmp.putPrintableString(party); -+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_PARTYNAME), tmp); -+ -+ out.write(DerValue.tag_Sequence, tagged); -+ } -+ -+ /** -+ * Return the printable string. -+ */ -+ public String toString() { -+ return ("EDIPartyName: " + -+ ((assigner == null) ? "" : -+ (" nameAssigner = " + assigner + ",")) -+ + " partyName = " + party); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/Extension.java b/org/mozilla/jss/netscape/security/x509/Extension.java -new file mode 100644 -index 00000000..824b0456 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/Extension.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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.Serializable; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * Represent a X509 Extension Attribute. -+ * -+ *

-+ * Extensions are addiitonal attributes which can be inserted in a X509 v3 certificate. For example a -+ * "Driving License Certificate" could have the driving license number as a extension. -+ * -+ *

-+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating -+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding -+ * of the extension value). -+ * -+ *

-+ * ASN.1 definition of Extension:
-+ * Extension ::= SEQUENCE {
-+ * ExtensionId	OBJECT IDENTIFIER,
-+ * critical	BOOLEAN DEFAULT FALSE,
-+ * extensionValue	OCTET STRING
-+ * }
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.9 -+ */ -+public class Extension implements Serializable { -+ private static final long serialVersionUID = -643549610716024753L; -+ protected ObjectIdentifier extensionId = null; -+ protected boolean critical = false; -+ protected byte[] extensionValue = null; -+ -+ /** -+ * Default constructor. Used only by sub-classes. -+ */ -+ public Extension() { -+ } -+ -+ /** -+ * Constructs an extension from a DER encoded array of bytes. -+ */ -+ public Extension(DerValue derVal) throws IOException { -+ -+ DerInputStream in = derVal.toDerInputStream(); -+ -+ // Object identifier -+ extensionId = in.getOID(); -+ -+ // If the criticality flag was false, it will not have been encoded. -+ DerValue val = in.getDerValue(); -+ if (val.tag == DerValue.tag_Boolean) { -+ critical = val.getBoolean(); -+ -+ // Extension value (DER encoded) -+ val = in.getDerValue(); -+ extensionValue = val.getOctetString(); -+ } else { -+ critical = false; -+ extensionValue = val.getOctetString(); -+ } -+ } -+ -+ /** -+ * Constructs an Extension from individual components of ObjectIdentifier, -+ * criticality and the DER encoded OctetString. -+ * -+ * @param extensionId the ObjectIdentifier of the extension -+ * @param critical the boolean indicating if the extension is critical -+ * @param extensionValue the DER encoded octet string of the value. -+ */ -+ public Extension(ObjectIdentifier extensionId, boolean critical, -+ byte[] extensionValue) throws IOException { -+ this.extensionId = extensionId; -+ this.critical = critical; -+ // passed in a DER encoded octet string, strip off the tag -+ // and length -+ DerValue inDerVal = new DerValue(extensionValue); -+ this.extensionValue = inDerVal.getOctetString(); -+ } -+ -+ /** -+ * Constructs an Extension from another extension. To be used for -+ * creating decoded subclasses. -+ * -+ * @param ext the extension to create from. -+ */ -+ public Extension(Extension ext) { -+ this.extensionId = ext.extensionId; -+ this.critical = ext.critical; -+ this.extensionValue = ext.extensionValue; -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ if (extensionId == null) -+ throw new IOException("Null OID to encode for the extension!"); -+ -+ DerOutputStream bytes = new DerOutputStream(); -+ bytes.putOID(extensionId); -+ if (critical) -+ bytes.putBoolean(critical); -+ if (extensionValue != null) -+ bytes.putOctetString(extensionValue); -+ -+ out.write(DerValue.tag_Sequence, bytes); -+ } -+ -+ /** -+ * Returns true if extension is critical. -+ */ -+ public boolean isCritical() { -+ return (critical); -+ } -+ -+ public void setCritical(boolean c) { -+ critical = c; -+ } -+ -+ public void clearValue() { -+ extensionValue = null; -+ } -+ -+ /** -+ * Returns the ObjectIdentifier of the extension. -+ */ -+ public ObjectIdentifier getExtensionId() { -+ return (extensionId); -+ } -+ -+ public void setExtensionId(ObjectIdentifier oid) { -+ extensionId = oid; -+ } -+ -+ /** -+ * Returns the extension value as an byte array for further processing. -+ * Note, this is the raw DER value of the extension, not the DER -+ * encoded octet string which is in the certificate. -+ */ -+ public byte[] getExtensionValue() { -+ if (extensionValue == null) -+ return null; -+ -+ byte[] dup = new byte[extensionValue.length]; -+ System.arraycopy(extensionValue, 0, dup, 0, dup.length); -+ return dup; -+ } -+ -+ public void setExtensionValue(byte value[]) { -+ extensionValue = value; -+ } -+ -+ /** -+ * Returns the Extension in user readable form. -+ */ -+ public String toString() { -+ String s = "ObjectId: " + extensionId.toString(); -+ if (critical) { -+ s += " Criticality=true\n"; -+ } else { -+ s += " Criticality=false\n"; -+ } -+ return (s); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/Extensions.java b/org/mozilla/jss/netscape/security/x509/Extensions.java -new file mode 100644 -index 00000000..fd464d50 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/Extensions.java -@@ -0,0 +1,252 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.lang.reflect.Constructor; -+import java.lang.reflect.InvocationTargetException; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the Extensions attribute for the Certificate. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.11 -+ * @see CertAttrSet -+ */ -+public class Extensions extends Vector -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 4597917347772057433L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions"; -+ /** -+ * name -+ */ -+ public static final String NAME = "extensions"; -+ -+ private Hashtable map; -+ -+ // Parse the encoded extension -+ public void parseExtension(Extension ext) throws IOException { -+ try { -+ @SuppressWarnings("unchecked") -+ Class extClass = (Class) OIDMap.getClass(ext.getExtensionId()); -+ if (extClass == null) { // Unsupported extension -+ if (ext.isCritical()) { -+ throw new IOException("Unsupported CRITICAL extension: " -+ + ext.getExtensionId()); -+ } else { -+ map.put(ext.getExtensionId().toString(), ext); -+ addElement(ext); -+ return; -+ } -+ } -+ Class[] params = { Boolean.class, Object.class }; -+ Constructor cons = extClass.getConstructor(params); -+ -+ byte[] extData = ext.getExtensionValue(); -+ int extLen = extData.length; -+ Object value = Array.newInstance(byte.class, extLen); -+ -+ for (int i = 0; i < extLen; i++) { -+ Array.setByte(value, i, extData[i]); -+ } -+ Object[] passed = new Object[] { Boolean.valueOf(ext.isCritical()), -+ value }; -+ CertAttrSet certExt = cons.newInstance(passed); -+ map.put(certExt.getName(), (Extension) certExt); -+ addElement((Extension) certExt); -+ -+ } catch (NoSuchMethodException nosuch) { -+ throw new IOException(nosuch.toString()); -+ } catch (InvocationTargetException invk) { -+ throw new IOException(invk.getTargetException().toString()); -+ } catch (Exception e) { -+ throw new IOException(e.toString()); -+ } -+ } -+ -+ /** -+ * Default constructor for the certificate attribute. -+ */ -+ public Extensions() { -+ map = new Hashtable(); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the Extension from. -+ * @exception IOException on decoding errors. -+ */ -+ public Extensions(DerInputStream in) -+ throws IOException { -+ -+ map = new Hashtable(); -+ DerValue[] exts = in.getSequence(5); -+ -+ for (int i = 0; i < exts.length; i++) { -+ Extension ext = new Extension(exts[i]); -+ parseExtension(ext); -+ } -+ } -+ -+ /** -+ * Decode the extensions from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ DerInputStream str = val.toDerInputStream(); -+ -+ map = new Hashtable(); -+ DerValue[] exts = str.getSequence(5); -+ -+ for (int i = 0; i < exts.length; i++) { -+ Extension ext = new Extension(exts[i]); -+ parseExtension(ext); -+ } -+ } -+ -+ /** -+ * Encode the extensions in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @exception CertificateException on encoding errors. -+ * @exception IOException on errors. -+ */ -+ public void encode(OutputStream out) -+ throws CertificateException, IOException { -+ DerOutputStream extOut = new DerOutputStream(); -+ for (int i = 0; i < size(); i++) { -+ Object thisOne = elementAt(i); -+ if (thisOne instanceof CertAttrSet) -+ ((CertAttrSet) thisOne).encode(extOut); -+ else if (thisOne instanceof Extension) -+ ((Extension) thisOne).encode(extOut); -+ else -+ throw new CertificateException("Invalid extension object"); -+ } -+ -+ try (DerOutputStream seq = new DerOutputStream()) { -+ seq.write(DerValue.tag_Sequence, extOut); -+ out.write(seq.toByteArray()); -+ } -+ } -+ -+ /** -+ * Set the attribute value. -+ * -+ * @param name the extension name used in the cache. -+ * @param obj the object to set. -+ * @exception IOException if the object could not be cached. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ map.put(name, (Extension) obj); -+ addElement((Extension) obj); -+ } -+ -+ /** -+ * Get the attribute value. -+ * -+ * @param name the extension name used in the lookup. -+ * @exception IOException if named extension is not found. -+ */ -+ public Object get(String name) throws IOException { -+ Object obj = map.get(name); -+ if (obj == null) { -+ throw new IOException("No extension found with name " + name); -+ } -+ return (obj); -+ } -+ -+ /** -+ * Delete the attribute value. -+ * -+ * @param name the extension name used in the lookup. -+ * @exception IOException if named extension is not found. -+ */ -+ public void delete(String name) throws IOException { -+ Object obj = map.get(name); -+ if (obj == null) { -+ throw new IOException("No extension found with name " + name); -+ } -+ map.remove(name); -+ removeElement(obj); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ return map.keys(); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = super.hashCode(); -+ result = prime * result + ((map == null) ? 0 : map.hashCode()); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (!super.equals(obj)) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ Extensions other = (Extensions) obj; -+ if (map == null) { -+ if (other.map != null) -+ return false; -+ } else if (!map.equals(other.map)) -+ return false; -+ return true; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/FreshestCRLExtension.java b/org/mozilla/jss/netscape/security/x509/FreshestCRLExtension.java -new file mode 100644 -index 00000000..85301fc1 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/FreshestCRLExtension.java -@@ -0,0 +1,403 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.BufferedOutputStream; -+import java.io.FileOutputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.Vector; -+ -+import org.mozilla.jss.asn1.ASN1Util; -+import org.mozilla.jss.asn1.InvalidBERException; -+import org.mozilla.jss.asn1.SEQUENCE; -+ -+import org.mozilla.jss.netscape.security.util.BitArray; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+ -+/** -+ * An extension that tells applications where to find -+ * the latest (freshest) delta CRL for this certificate -+ * or full CRL. -+ * -+ *
-+ * cRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
-+ *
-+ * DistributionPoint ::= SEQUENCE {
-+ *      distributionPoint       [0]     DistributionPointName OPTIONAL,
-+ *      reasons                 [1]     ReasonFlags OPTIONAL,
-+ *      cRLIssuer               [2]     GeneralNames OPTIONAL }
-+ *
-+ * DistributionPointName ::= CHOICE {
-+ *      fullName                [0]     GeneralNames,
-+ *      nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
-+ *
-+ * ReasonFlags ::= BIT STRING {
-+ *      unused                  (0),
-+ *      keyCompromise           (1),
-+ *      cACompromise            (2),
-+ *      affiliationChanged      (3),
-+ *      superseded              (4),
-+ *      cessationOfOperation    (5),
-+ *      certificateHold         (6) }
-+ * 
-+ */ -+public class FreshestCRLExtension extends Extension -+ implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -8040203589629281781L; -+ -+ // vector of CRLDistributionPoint -+ private SEQUENCE distributionPoints = new SEQUENCE(); -+ -+ public FreshestCRLExtension() { -+ this.extensionId = PKIXExtensions.FreshestCRL_Id; -+ this.critical = false; -+ } -+ -+ // Cached DER-encoding to improve performance. -+ private byte[] cachedEncoding = null; -+ -+ // Attribute name -+ public static final String NAME = "FreshestCRL"; -+ -+ // The Object Identifier for this extension. -+ public static final String OID = "2.5.29.46"; -+ -+ static { -+ try { -+ OIDMap.addAttribute(FreshestCRLExtension.class.getName(), -+ OID, NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ /** -+ * This constructor is called by the CertificateExtensions class to decode -+ * an extension whose OID indicates it is a CRLDistributionsPoints -+ * extension. -+ */ -+ public FreshestCRLExtension(Boolean critical, Object value) -+ //throws IOException -+ { -+ try { -+ this.extensionId = PKIXExtensions.FreshestCRL_Id; -+ this.critical = critical.booleanValue(); -+ this.extensionValue = ((byte[]) value).clone(); -+ -+ // decode the value -+ try { -+ SEQUENCE.OF_Template seqOfCRLDP = -+ new SEQUENCE.OF_Template(CRLDistributionPoint.getTemplate()); -+ -+ distributionPoints = -+ (SEQUENCE) ASN1Util.decode(seqOfCRLDP, extensionValue); -+ } catch (InvalidBERException e) { -+ throw new IOException("Invalid BER-encoding: " + e, e); -+ } -+ } catch (IOException e) { -+ System.out.println("Big error"); -+ System.out.println(e); -+ e.printStackTrace(); -+ //throw e; -+ } -+ } -+ -+ /** -+ * Creates a new FreshestCRL extension, with the given -+ * distribution point as the first element. -+ */ -+ public FreshestCRLExtension(CRLDistributionPoint dp) { -+ this.extensionId = PKIXExtensions.FreshestCRL_Id; -+ this.critical = false; -+ distributionPoints.addElement(dp); -+ } -+ -+ /** -+ * Adds an additional distribution point to the end of the sequence. -+ */ -+ public void addPoint(CRLDistributionPoint dp) { -+ distributionPoints.addElement(dp); -+ cachedEncoding = null; -+ } -+ -+ /** -+ * Returns the number of distribution points in the sequence. -+ */ -+ public int getNumPoints() { -+ return distributionPoints.size(); -+ } -+ -+ /** -+ * Returns the DistributionPoint at the given index in the sequence. -+ */ -+ public CRLDistributionPoint getPointAt(int index) { -+ return (CRLDistributionPoint) distributionPoints.elementAt(index); -+ } -+ -+ /** -+ * Sets the criticality of this extension. PKIX dictates that this -+ * extension SHOULD NOT be critical, so applications can make it critical -+ * if they have a very good reason. By default, the extension is not -+ * critical. -+ */ -+ public void setCritical(boolean critical) { -+ this.critical = critical; -+ } -+ -+ /** -+ * Encodes this extension to the given DerOutputStream. -+ * This method re-encodes each time it is called, so it is not very -+ * efficient. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ extensionValue = ASN1Util.encode(distributionPoints); -+ super.encode(out); -+ } -+ -+ /** -+ * Should be called if any change is made to this data structure -+ * so that the cached DER encoding can be discarded. -+ */ -+ public void flushCachedEncoding() { -+ cachedEncoding = null; -+ } -+ -+ ///////////////////////////////////////////////////////////// -+ // CertAttrSet interface -+ // This interface is not really appropriate for this extension -+ // because it is so complicated. Therefore, we only provide a -+ // minimal implementation. -+ ///////////////////////////////////////////////////////////// -+ @Override -+ public String toString() { -+ return NAME; -+ } -+ -+ /** -+ * DER-encodes this extension to the given OutputStream. -+ */ -+ public void encode(OutputStream ostream) -+ throws CertificateException, IOException { -+ if (cachedEncoding == null) { -+ // only re-encode if necessary -+ DerOutputStream tmp = new DerOutputStream(); -+ encode(tmp); -+ cachedEncoding = tmp.toByteArray(); -+ } -+ ostream.write(cachedEncoding); -+ } -+ -+ public void decode(InputStream in) -+ throws CertificateException, IOException { -+ throw new IOException("Not supported"); -+ } -+ -+ public void set(String name, Object obj) -+ throws CertificateException, IOException { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:FreshestCRLExtension"); -+ } -+ -+ public Object get(String name) -+ throws CertificateException, IOException { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:FreshestCRLExtension"); -+ } -+ -+ public void delete(String name) -+ throws CertificateException, IOException { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:FreshestCRLExtension"); -+ } -+ -+ /* -+ * TODO replacewith empty collection -+ */ -+ public Enumeration getAttributeNames() { -+ return (new Vector()).elements(); -+ } -+ -+ public String getName() { -+ return NAME; -+ } -+ -+ /** -+ * Test driver. -+ */ -+ public static void main(String args[]) { -+ BufferedOutputStream bos = null; -+ try { -+ -+ if (args.length != 1) { -+ System.out.println("Usage: FreshestCRLExtentions " + -+ ""); -+ System.exit(-1); -+ } -+ -+ bos = new BufferedOutputStream( -+ new FileOutputStream(args[0])); -+ -+ // URI only -+ CRLDistributionPoint cdp = new CRLDistributionPoint(); -+ URIName uri = new URIName("http://www.mycrl.com/go/here"); -+ GeneralNames generalNames = new GeneralNames(); -+ generalNames.addElement(uri); -+ cdp.setFullName(generalNames); -+ FreshestCRLExtension crldpExt = -+ new FreshestCRLExtension(cdp); -+ -+ // DN only -+ cdp = new CRLDistributionPoint(); -+ X500Name dn = new X500Name("CN=Otis Smith,E=otis@fedoraproject.org" + -+ ",OU=Certificate Server,O=Fedora,C=US"); -+ generalNames = new GeneralNames(); -+ generalNames.addElement(dn); -+ cdp.setFullName(generalNames); -+ crldpExt.addPoint(cdp); -+ -+ // DN + reason -+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 }); -+ cdp = new CRLDistributionPoint(); -+ cdp.setFullName(generalNames); -+ cdp.setReasons(ba); -+ crldpExt.addPoint(cdp); -+ -+ // relative DN + reason + crlIssuer -+ cdp = new CRLDistributionPoint(); -+ RDN rdn = new RDN("OU=foobar dept"); -+ cdp.setRelativeName(rdn); -+ cdp.setReasons(ba); -+ cdp.setCRLIssuer(generalNames); -+ crldpExt.addPoint(cdp); -+ -+ crldpExt.setCritical(true); -+ crldpExt.encode(bos); -+ -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } finally { -+ if (bos != null) { -+ try { -+ bos.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ -+ /** -+ * Represents a reason that a cert may be revoked. These reasons are -+ * expressed in a ReasonFlags bit string. -+ */ -+ public static class Reason { -+ -+ private String name; -+ private byte bitMask; -+ -+ private Reason() { -+ } -+ -+ private Reason(String name, byte bitMask) { -+ this.name = name; -+ this.bitMask = bitMask; -+ map.put(name, this); -+ list.addElement(this); -+ } -+ -+ private static Hashtable map = new Hashtable(); -+ private static Vector list = new Vector(); -+ -+ public static Reason fromString(String name) { -+ return map.get(name); -+ } -+ -+ public String getName() { -+ return name; -+ } -+ -+ public byte getBitMask() { -+ return bitMask; -+ } -+ -+ /** -+ * Given a bit array representing reason flags, extracts the reasons -+ * and returns them as an array. -+ * -+ * @param bitFlags A bit vector containing reason flags. -+ * @return An array of reasons contained in the bit vector. -+ * May be zero-length but will not be null. -+ */ -+ public static Reason[] bitArrayToReasonArray(byte bitFlags) { -+ return bitArrayToReasonArray(new byte[] { bitFlags }); -+ } -+ -+ /** -+ * Given a bit array representing reason flags, extracts the reasons -+ * and returns them as an array. Currently, only the first byte -+ * of the bitflags are examined. -+ * -+ * @param bitFlags A bit vector containing reason flags. The format -+ * is big-endian (MSB first). Only the first byte is examined. -+ * @return An array of reasons contained in the bit vector. -+ * May be zero-length but will not be null. -+ */ -+ public static Reason[] bitArrayToReasonArray(byte[] bitFlags) { -+ byte first = bitFlags[0]; -+ int size = list.size(); -+ Vector result = new Vector(); -+ for (int i = 0; i < size; i++) { -+ Reason r = list.elementAt(i); -+ byte b = r.getBitMask(); -+ if ((first & b) != 0) { -+ result.addElement(r); -+ } -+ } -+ size = result.size(); -+ Reason[] retval = new Reason[size]; -+ for (int i = 0; i < size; i++) { -+ retval[i] = result.elementAt(i); -+ } -+ return retval; -+ } -+ -+ public static final Reason UNUSED = -+ new Reason("unused", (byte) 0x80); -+ public static final Reason KEY_COMPROMISE = -+ new Reason("keyCompromise", (byte) 0x40); -+ public static final Reason CA_COMPROMISE = -+ new Reason("cACompromise", (byte) 0x20); -+ public static final Reason AFFILIATION_CHANGED = -+ new Reason("affiliationChanged", (byte) 0x10); -+ public static final Reason SUPERSEDED = -+ new Reason("superseded", (byte) 0x08); -+ public static final Reason CESSATION_OF_OPERATION = -+ new Reason("cessationOfOperation", (byte) 0x04); -+ public static final Reason CERTIFICATE_HOLD = -+ new Reason("certificateHold", (byte) 0x02); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/GeneralName.java b/org/mozilla/jss/netscape/security/x509/GeneralName.java -new file mode 100644 -index 00000000..c3298828 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/GeneralName.java -@@ -0,0 +1,214 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class implements the ASN.1 GeneralName object class. -+ *

-+ * The ASN.1 syntax for this is: -+ * -+ *

-+ * GeneralName ::= CHOICE {
-+ *    otherName                       [0]     OtherName,
-+ *    rfc822Name                      [1]     IA5String,
-+ *    dNSName                         [2]     IA5String,
-+ *    x400Address                     [3]     ORAddress,
-+ *    directoryName                   [4]     Name,
-+ *    ediPartyName                    [5]     EDIPartyName,
-+ *    uniformResourceIdentifier       [6]     IA5String,
-+ *    iPAddress                       [7]     OCTET STRING,
-+ *    registeredID                    [8]     OBJECT IDENTIFIER
-+ * }
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.7 -+ */ -+public class GeneralName implements GeneralNameInterface { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 2244101501095555042L; -+ // Private data members -+ private GeneralNameInterface name = null; -+ -+ /** -+ * Default constructor for the class. -+ * -+ * @param name the selected CHOICE from the list. -+ */ -+ public GeneralName(GeneralNameInterface name) { -+ this.name = name; -+ } -+ -+ /** -+ * Create the object from its DER encoded value. -+ * -+ * @param encName the DER encoded GeneralName. -+ */ -+ public GeneralName(DerValue encName) throws IOException { -+ short tag = (byte) (encName.tag & 0x1f); -+ -+ // NB. this is always encoded with the IMPLICIT tag -+ // The checks only make sense if we assume implicit tagging, -+ // with explicit tagging the form is always constructed. -+ switch (tag) { -+ case GeneralNameInterface.NAME_RFC822: -+ if (encName.isContextSpecific() && !encName.isConstructed()) { -+ encName.resetTag(DerValue.tag_IA5String); -+ name = new RFC822Name(encName); -+ } else -+ throw new IOException("Invalid encoding of RFC822 name"); -+ break; -+ -+ case GeneralNameInterface.NAME_DNS: -+ if (encName.isContextSpecific() && !encName.isConstructed()) { -+ encName.resetTag(DerValue.tag_IA5String); -+ name = new DNSName(encName); -+ } else -+ throw new IOException("Invalid encoding of DNS name"); -+ break; -+ -+ case GeneralNameInterface.NAME_URI: -+ if (encName.isContextSpecific() && !encName.isConstructed()) { -+ encName.resetTag(DerValue.tag_IA5String); -+ name = new URIName(encName); -+ } else -+ throw new IOException("Invalid encoding of URI"); -+ break; -+ -+ case GeneralNameInterface.NAME_IP: -+ if (encName.isContextSpecific() && !encName.isConstructed()) { -+ encName.resetTag(DerValue.tag_OctetString); -+ name = new IPAddressName(encName); -+ } else -+ throw new IOException("Invalid encoding of IP address"); -+ break; -+ -+ case GeneralNameInterface.NAME_ANY: -+ if (encName.isContextSpecific() && encName.isConstructed()) { -+ encName.resetTag(DerValue.tag_OctetString); -+ name = new OtherName(encName); -+ } else -+ throw new IOException("Invalid encoding of other name"); -+ break; -+ -+ case GeneralNameInterface.NAME_OID: -+ if (encName.isContextSpecific() && !encName.isConstructed()) { -+ encName.resetTag(DerValue.tag_ObjectId); -+ name = new OIDName(encName); -+ } else -+ throw new IOException("Invalid encoding of OID name"); -+ break; -+ -+ case GeneralNameInterface.NAME_DIRECTORY: -+ if (encName.isContextSpecific() && encName.isConstructed()) { -+ // Unlike the other cases, DirectoryName is EXPLICITly -+ // tagged, because the X.500 Name type is a CHOICE. -+ // Therefore, the sequence is actually nested in the -+ // content of this value. We'll pretend it's an octet -+ // string so we can get at the content bytes. -+ encName.resetTag(DerValue.tag_OctetString); -+ byte[] content = encName.getOctetString(); -+ name = new X500Name(content); -+ } else -+ throw new IOException("Invalid encoding of Directory name"); -+ break; -+ -+ case GeneralNameInterface.NAME_EDI: -+ if (encName.isContextSpecific() && encName.isConstructed()) { -+ encName.resetTag(DerValue.tag_Sequence); -+ name = new EDIPartyName(encName); -+ } else -+ throw new IOException("Invalid encoding of EDI name"); -+ break; -+ -+ default: -+ throw new IOException("Unrecognized GeneralName tag, (" -+ + tag + ")"); -+ } -+ } -+ -+ /** -+ * Return the type of the general name. -+ */ -+ public int getType() { -+ return (name.getType()); -+ } -+ -+ /** -+ * Return the name as user readable string -+ */ -+ public String toString() { -+ return (name.toString()); -+ } -+ -+ /** -+ * Encode the name to the specified DerOutputStream. -+ * -+ * @param out the DerOutputStream to encode the the GeneralName to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ name.encode(tmp); -+ int nameType = name.getType(); -+ boolean constructedForm; -+ -+ if (nameType == GeneralNameInterface.NAME_ANY || -+ nameType == GeneralNameInterface.NAME_X400 || -+ nameType == GeneralNameInterface.NAME_DIRECTORY || -+ nameType == GeneralNameInterface.NAME_EDI) { -+ constructedForm = true; -+ } else { -+ constructedForm = false; -+ } -+ -+ if (nameType == GeneralNameInterface.NAME_DIRECTORY) { -+ // EXPLICIT tag, because Name is a CHOICE type -+ out.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ constructedForm, (byte) nameType), tmp); -+ } else { -+ // IMPLICIT tag, the default -+ out.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ constructedForm, (byte) nameType), tmp); -+ } -+ } -+ -+ /** -+ * Unwrap this GeneralName until we reach something that is not -+ * a GeneralName. -+ */ -+ public GeneralNameInterface unwrap() { -+ if (this == name) -+ return null; // can't happen, but just in case... -+ -+ if (name instanceof GeneralName) -+ return ((GeneralName) name).unwrap(); -+ else -+ return name; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/GeneralNameInterface.java b/org/mozilla/jss/netscape/security/x509/GeneralNameInterface.java -new file mode 100644 -index 00000000..d23a36ad ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/GeneralNameInterface.java -@@ -0,0 +1,60 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+ -+/** -+ * This interface specifies the abstract methods which have to be -+ * implemented by all the members of the GeneralNames ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.6 -+ */ -+public interface GeneralNameInterface extends java.io.Serializable { -+ /** -+ * The list of names supported. -+ */ -+ public static final int NAME_ANY = 0; -+ public static final int NAME_RFC822 = 1; -+ public static final int NAME_DNS = 2; -+ public static final int NAME_X400 = 3; -+ public static final int NAME_DIRECTORY = 4; -+ public static final int NAME_EDI = 5; -+ public static final int NAME_URI = 6; -+ public static final int NAME_IP = 7; -+ public static final int NAME_OID = 8; -+ -+ /** -+ * Return the type of the general name, as -+ * defined above. -+ */ -+ int getType(); -+ -+ /** -+ * Encode the name to the specified DerOutputStream. -+ * -+ * @param out the DerOutputStream to encode the GeneralName to. -+ * @exception IOException thrown if the GeneralName could not be -+ * encoded. -+ */ -+ void encode(DerOutputStream out) throws IOException; -+} -diff --git a/org/mozilla/jss/netscape/security/x509/GeneralNames.java b/org/mozilla/jss/netscape/security/x509/GeneralNames.java -new file mode 100644 -index 00000000..96347804 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/GeneralNames.java -@@ -0,0 +1,150 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This object class represents the GeneralNames type required in -+ * X509 certificates. -+ *

-+ * The ASN.1 syntax for this is: -+ * -+ *

-+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.7 -+ */ -+public class GeneralNames extends Vector { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 3204492869396713312L; -+ -+ /** -+ * Create the GeneralNames, decoding from the passed DerValue. -+ * -+ * Caution when using this constructor. It may be broken! -+ * Better to call addElement(gni) directly where gni is -+ * a GeneralNameInterface object -+ * -+ * @param derVal the DerValue to construct the GeneralNames from. -+ * @exception GeneralNamesException on decoding error. -+ * @exception IOException on error. -+ */ -+ public GeneralNames(DerValue derVal) -+ throws IOException, GeneralNamesException { -+ if (derVal.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for GeneralNames."); -+ } -+ if (derVal.data.available() == 0) { -+ throw new GeneralNamesException("No data available in " -+ + "passed DER encoded value."); -+ } -+ // Decode all the GeneralName's -+ while (derVal.data.available() != 0) { -+ DerValue encName = derVal.data.getDerValue(); -+ -+ GeneralName name = new GeneralName(encName); -+ addElement(name); -+ } -+ } -+ -+ /** -+ * Create the GeneralNames -+ * -+ * @param names a non-empty array of names to put into the -+ * generalNames -+ */ -+ -+ public GeneralNames(GeneralNameInterface[] names) -+ throws GeneralNamesException { -+ if (names == null || names.length == 0) -+ throw new GeneralNamesException("Cannot create empty GeneralNames"); -+ -+ for (int i = 0; i < names.length; i++) { -+ addElement(names[i]); -+ } -+ } -+ -+ /** -+ * The default constructor for this class. -+ */ -+ public GeneralNames() { -+ super(1, 1); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception GeneralNamesException on encoding error. -+ * @exception IOException on error. -+ */ -+ public void encode(DerOutputStream out) -+ throws IOException, GeneralNamesException { -+ if (size() == 0) { -+ return; -+ } -+ -+ Enumeration names = elements(); -+ DerOutputStream temp = new DerOutputStream(); -+ -+ while (names.hasMoreElements()) { -+ Object obj = names.nextElement(); -+ if (!(obj instanceof GeneralNameInterface)) { -+ throw new GeneralNamesException("Element in GeneralNames " -+ + "not of type GeneralName."); -+ } -+ GeneralNameInterface intf = (GeneralNameInterface) obj; -+ if (obj instanceof GeneralName) { -+ intf.encode(temp); -+ } else { -+ DerOutputStream gname = new DerOutputStream(); -+ intf.encode(gname); -+ int nameType = intf.getType(); -+ // constructed form -+ if (nameType == GeneralNameInterface.NAME_ANY || -+ nameType == GeneralNameInterface.NAME_X400 || -+ nameType == GeneralNameInterface.NAME_EDI) { -+ -+ temp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, (byte) nameType), gname); -+ } else if (nameType == GeneralNameInterface.NAME_DIRECTORY) { -+ // EXPLICIT tag because directoryName is a CHOICE -+ temp.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, (byte) nameType), gname); -+ } else -+ // primitive form -+ temp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, (byte) nameType), gname); -+ } -+ -+ } -+ -+ out.write(DerValue.tag_Sequence, temp); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/GeneralNamesException.java b/org/mozilla/jss/netscape/security/x509/GeneralNamesException.java -new file mode 100644 -index 00000000..5598ef8f ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/GeneralNamesException.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 org.mozilla.jss.netscape.security.x509; -+ -+import java.security.GeneralSecurityException; -+ -+/** -+ * Generic General Names Exception. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.4 -+ */ -+public class GeneralNamesException extends GeneralSecurityException { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -8320001725384815795L; -+ -+ /** -+ * Constructs a GeneralNamesException with no detail message. -+ */ -+ public GeneralNamesException() { -+ super(); -+ } -+ -+ /** -+ * Constructs the exception with the specified error message. -+ * -+ * @param message the requisite error message. -+ */ -+ public GeneralNamesException(String message) { -+ super(message); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/GeneralSubtree.java b/org/mozilla/jss/netscape/security/x509/GeneralSubtree.java -new file mode 100644 -index 00000000..9305e6fc ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/GeneralSubtree.java -@@ -0,0 +1,162 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.Serializable; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.PrettyPrintFormat; -+ -+/** -+ * Represent the GeneralSubtree ASN.1 object, whose syntax is: -+ * -+ *
-+ * GeneralSubtree ::= SEQUENCE {
-+ *    base             GeneralName,
-+ *    minimum  [0]     BaseDistance DEFAULT 0,
-+ *    maximum  [1]     BaseDistance OPTIONAL
-+ * }
-+ * BaseDistance ::= INTEGER (0..MAX)
-+ * 
-+ * -+ * @version 1.5 -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class GeneralSubtree implements Serializable { -+ -+ private static final long serialVersionUID = -2835481424013062770L; -+ private static final byte TAG_MIN = 0; -+ private static final byte TAG_MAX = 1; -+ private static final int MIN_DEFAULT = 0; -+ -+ private GeneralName name; -+ private int minimum = MIN_DEFAULT; -+ private int maximum = -1; -+ -+ private transient PrettyPrintFormat pp = new PrettyPrintFormat(":"); -+ -+ /** -+ * The default constructor for the class. -+ * -+ * @param name the GeneralName -+ * @param min the minimum BaseDistance -+ * @param max the maximum BaseDistance -+ */ -+ public GeneralSubtree(GeneralName name, int min, int max) { -+ this.name = name; -+ this.minimum = min; -+ this.maximum = max; -+ } -+ -+ /** -+ * Create the object from its DER encoded form. -+ * -+ * @param val the DER encoded from of the same. -+ */ -+ public GeneralSubtree(DerValue val) throws IOException { -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for GeneralSubtree."); -+ } -+ name = new GeneralName(val.data.getDerValue()); -+ -+ // NB. this is always encoded with the IMPLICIT tag -+ // The checks only make sense if we assume implicit tagging, -+ // with explicit tagging the form is always constructed. -+ while (val.data.available() != 0) { -+ DerValue opt = val.data.getDerValue(); -+ -+ if (opt.isContextSpecific(TAG_MIN) && !opt.isConstructed()) { -+ opt.resetTag(DerValue.tag_Integer); -+ minimum = (opt.getInteger()).toInt(); -+ -+ } else if (opt.isContextSpecific(TAG_MAX) && !opt.isConstructed()) { -+ opt.resetTag(DerValue.tag_Integer); -+ maximum = (opt.getInteger()).toInt(); -+ } else -+ throw new IOException("Invalid encoding of GeneralSubtree."); -+ } -+ } -+ -+ /** -+ * Return a printable string of the GeneralSubtree. -+ */ -+ public String toString() { -+ String s = "\n GeneralSubtree: [\n" + -+ " GeneralName: " + ((name == null) ? "" : name.toString()) + -+ "\n Minimum: " + minimum; -+ if (maximum == -1) { -+ s += "\t Maximum: undefined"; -+ } else -+ s += "\t Maximum: " + maximum; -+ s += " ]\n"; -+ return (s); -+ } -+ -+ public String toPrint(int indent) { -+ String s = "\n" + pp.indent(indent) + "GeneralSubtree: [\n" + pp.indent(indent + 2) + -+ "GeneralName: " + ((name == null) ? "" : name.toString()) + -+ "\n" + pp.indent(indent + 2) + "Minimum: " + minimum; -+ if (maximum == -1) { -+ s += "\n" + pp.indent(indent + 2) + "Maximum: undefined"; -+ } else -+ s += "\n" + pp.indent(indent + 2) + "Maximum: " + maximum; -+ s += "]\n"; -+ return (s); -+ } -+ -+ /** -+ * Encode the GeneralSubtree. -+ * -+ * @param out the DerOutputStream to encode this object to. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream seq = new DerOutputStream(); -+ -+ name.encode(seq); -+ -+ if (minimum != MIN_DEFAULT) { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putInteger(new BigInt(minimum)); -+ seq.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_MIN), tmp); -+ } -+ if (maximum != -1) { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putInteger(new BigInt(maximum)); -+ seq.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_MAX), tmp); -+ } -+ out.write(DerValue.tag_Sequence, seq); -+ } -+ -+ public GeneralName getGeneralName() { -+ return name; -+ } -+ -+ public int getMaxValue() { -+ return maximum; -+ } -+ -+ public int getMinValue() { -+ return minimum; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/GeneralSubtrees.java b/org/mozilla/jss/netscape/security/x509/GeneralSubtrees.java -new file mode 100644 -index 00000000..a27ff8b5 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/GeneralSubtrees.java -@@ -0,0 +1,109 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.Serializable; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.PrettyPrintFormat; -+ -+/** -+ * Represent the GeneralSubtrees ASN.1 object. -+ * -+ * @version 1.4 -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class GeneralSubtrees implements Serializable { -+ -+ private static final long serialVersionUID = 6308776640697100848L; -+ private Vector trees; -+ private transient PrettyPrintFormat pp = new PrettyPrintFormat(":"); -+ -+ /** -+ * The default constructor for the class. -+ * -+ * @param trees the sequence of GeneralSubtree. -+ */ -+ public GeneralSubtrees(Vector trees) { -+ this.trees = trees; -+ } -+ -+ /** -+ * Create the object from the passed DER encoded form. -+ * -+ * @param val the DER encoded form of the same. -+ */ -+ public GeneralSubtrees(DerValue val) throws IOException { -+ trees = new Vector(1, 1); -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding of GeneralSubtrees."); -+ } -+ while (val.data.available() != 0) { -+ DerValue opt = val.data.getDerValue(); -+ GeneralSubtree tree = new GeneralSubtree(opt); -+ trees.addElement(tree); -+ } -+ } -+ -+ /** -+ * Return a printable string of the GeneralSubtree. -+ */ -+ public String toString() { -+ String s = " GeneralSubtrees:\n" + trees.toString() -+ + "\n"; -+ -+ return (s); -+ } -+ -+ public String toPrint(int indent) { -+ -+ StringBuffer s = new StringBuffer(); -+ GeneralSubtree element; -+ -+ for (Enumeration e = trees.elements(); e.hasMoreElements();) { -+ element = e.nextElement(); -+ s.append(pp.indent(indent + 4) + element.toPrint(indent) + "\n"); -+ } -+ -+ return (s.toString()); -+ } -+ -+ /** -+ * Encode the GeneralSubtrees. -+ * -+ * @param out the DerOutputStrean to encode this object to. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream seq = new DerOutputStream(); -+ -+ for (int i = 0; i < trees.size(); i++) { -+ trees.elementAt(i).encode(seq); -+ } -+ out.write(DerValue.tag_Sequence, seq); -+ } -+ -+ public Vector getSubtrees() { -+ return trees; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/GenericValueConverter.java b/org/mozilla/jss/netscape/security/x509/GenericValueConverter.java -new file mode 100644 -index 00000000..2c7d9f54 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/GenericValueConverter.java -@@ -0,0 +1,143 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.CharacterCodingException; -+import java.nio.charset.CharsetEncoder; -+ -+import org.mozilla.jss.netscape.security.util.ASN1CharStrConvMap; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * A GenericValueConverter converts a string that is not associated with -+ * a particular attribute to a DER encoded ASN.1 character string type. -+ * Currently supports PrintableString, IA5String, BMPString T.61String and -+ * Universal String. -+ * -+ *

-+ * The conversion is done as follows. An encoder is obtained for the all the character sets from the global default -+ * ASN1CharStrConvMap. The encoders are then used to convert the string to the smallest character set first -- -+ * printableString. If the string contains characters outside of that character set, it is converted to the next -+ * character set -- IA5String character set. If that is not enough it is converted to a BMPString, then Universal String -+ * which contains all characters. -+ * -+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc. -+ * -+ */ -+ -+public class GenericValueConverter implements AVAValueConverter { -+ public GenericValueConverter() { -+ } -+ -+ /** -+ * Converts a string to a DER encoded ASN.1 primtable string, defined here -+ * as a PrintableString, IA5String, T.61String, BMPString or -+ * UniversalString. The string is not expected to be encoded in any form. -+ * -+ *

-+ * If an encoder is not available for a character set that is needed to convert the string, the string cannot be -+ * converted and an IOException is thrown. For example, if the string contains characters outside the -+ * PrintableString character and only a PrintableString encoder is available then an IOException is thrown. -+ * -+ * @param s A string representing a generic attribute string value. -+ * -+ * @return The DER value of the attribute. -+ * -+ * @exception IOException if the string cannot be converted, such as -+ * when an encoder needed is -+ * unavailable. -+ */ -+ public DerValue getValue(String s) -+ throws IOException { -+ return getValue(s, null); -+ } -+ -+ public DerValue getValue(String valueString, byte[] tags) throws IOException { -+ // try to convert to printable, then t61 the universal - -+ // i.e. from minimal coverage to the broadest. -+ -+ if (tags == null || tags.length == 0) -+ tags = DefEncodingTags; -+ -+ for (int i = 0; i < tags.length; i++) { -+ try { -+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(tags[i]); -+ if (encoder == null) -+ continue; -+ -+ CharBuffer charBuffer = CharBuffer.wrap(valueString.toCharArray()); -+ ByteBuffer byteBuffer = encoder.encode(charBuffer); -+ -+ return new DerValue(tags[i], byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit()); -+ -+ } catch (CharacterCodingException e) { -+ continue; -+ } -+ } -+ -+ throw new IOException( -+ "Cannot convert the string value to a ASN.1 type"); -+ } -+ -+ /** -+ * Creates a DerValue from the byte array of BER encoded value. -+ * -+ * NOTE: currently only supports DER encoding (a form of BER) on input . -+ * -+ * @param berStream Byte array of a BER encoded value. -+ * -+ * @return DerValue object. -+ * -+ * @exception IOException If the BER value cannot be converted to a -+ * valid Directory String DER value. -+ */ -+ public DerValue getValue(byte[] berByteStream) -+ throws IOException { -+ // accepts any tag. -+ DerValue value = new DerValue(berByteStream); -+ return value; -+ } -+ -+ /** -+ * Converts a DerValue of ASN1 Character string type to a java string -+ * (the string is not encoded in any form). -+ * -+ * @param avaValue A DerValue -+ * @return A string representing the attribute value. -+ * @exception IOException if a decoder needed for the -+ * conversion is not available or if BER value -+ * is not one of the ASN1 character string types -+ * here. -+ */ -+ public String getAsString(DerValue avaValue) -+ throws IOException { -+ return avaValue.getASN1CharString(); -+ } -+ -+ private static byte DefEncodingTags[] = { -+ DerValue.tag_PrintableString, -+ DerValue.tag_IA5String, -+ DerValue.tag_BMPString, -+ DerValue.tag_UTF8String, -+ DerValue.tag_T61String, -+ DerValue.tag_UniversalString -+ }; -+} -diff --git a/org/mozilla/jss/netscape/security/x509/HoldInstructionExtension.java b/org/mozilla/jss/netscape/security/x509/HoldInstructionExtension.java -new file mode 100644 -index 00000000..b6f55800 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/HoldInstructionExtension.java -@@ -0,0 +1,356 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * Represent the CRL Hold Instruction Code Extension. -+ * -+ *

-+ * The hold instruction code is a non-critical CRL entry extension that provides a registered instruction identifier -+ * which indicates the action to be taken after encountering a certificate that has been placed on hold. -+ * -+ * @see Extension -+ * @see CertAttrSet -+ */ -+ -+public class HoldInstructionExtension extends Extension -+ implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -6706557233070964984L; -+ /** -+ * Attribute name. -+ */ -+ public static final String NAME = "HoldInstruction"; -+ public static final String HOLD_INSTRUCTION = "value"; -+ -+ /** -+ * The Object Identifier for this extension. -+ */ -+ public static final String OID = "2.5.29.23"; -+ -+ public static final String NONE_HOLD_INSTR_OID_STR = -+ "1.2.840.10040.2.1"; -+ public static final ObjectIdentifier NONE_HOLD_INSTR_OID = -+ new ObjectIdentifier(NONE_HOLD_INSTR_OID_STR); -+ -+ public static final String CALL_ISSUER_HOLD_INSTR_OID_STR = -+ "1.2.840.10040.2.2"; -+ public static final ObjectIdentifier CALL_ISSUER_HOLD_INSTR_OID = -+ new ObjectIdentifier(CALL_ISSUER_HOLD_INSTR_OID_STR); -+ -+ public static final String REJECT_HOLD_INSTR_OID_STR = -+ "1.2.840.10040.2.3"; -+ public static final ObjectIdentifier REJECT_HOLD_INSTR_OID = -+ new ObjectIdentifier(REJECT_HOLD_INSTR_OID_STR); -+ -+ private ObjectIdentifier holdInstructionCodeOIDs[] = { NONE_HOLD_INSTR_OID, -+ CALL_ISSUER_HOLD_INSTR_OID, -+ REJECT_HOLD_INSTR_OID }; -+ private ObjectIdentifier holdInstructionCodeOID = null; -+ -+ private String holdInstructionDescription[] = { "None", -+ "Call Issuer", -+ "Reject" }; -+ -+ static { -+ try { -+ OIDMap.addAttribute(HoldInstructionExtension.class.getName(), -+ OID, NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ private int getHoldInstructionCodeFromOID(ObjectIdentifier oid) { -+ for (int i = 0; i < holdInstructionCodeOIDs.length; i++) { -+ if (oid.equals(holdInstructionCodeOIDs[i])) -+ return (i + 1); -+ } -+ return 0; -+ } -+ -+ private String getHoldInstructionDescription(ObjectIdentifier oid) { -+ String description = "Invalid"; -+ if (oid != null) { -+ int i = getHoldInstructionCodeFromOID(oid); -+ if (i > 0 && i < 4) -+ description = holdInstructionDescription[i - 1]; -+ } -+ return (description); -+ } -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ if (holdInstructionCodeOID == null) -+ throw new IOException("Unintialized hold instruction extension"); -+ -+ try (DerOutputStream os = new DerOutputStream()) { -+ os.putOID(holdInstructionCodeOID); -+ this.extensionValue = os.toByteArray(); -+ } -+ } -+ -+ /** -+ * Create a HoldInstructionExtension with the date. -+ * The criticality is set to false. -+ * -+ * @param code the value to be set for the extension. -+ */ -+ public HoldInstructionExtension(int code) -+ throws IOException { -+ if (code < 1 || code > 3) -+ throw new IOException("Invalid hold instruction code"); -+ holdInstructionCodeOID = holdInstructionCodeOIDs[code - 1]; -+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a HoldInstructionExtension with the date. -+ * The criticality is set to false. -+ * -+ * @param oidStr the value to be set for the extension. -+ */ -+ public HoldInstructionExtension(String oidStr) -+ throws IOException { -+ ObjectIdentifier oid = new ObjectIdentifier(oidStr); -+ if (oid == null || getHoldInstructionCodeFromOID(oid) == 0) -+ throw new IOException("Invalid hold instruction code"); -+ holdInstructionCodeOID = oid; -+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a HoldInstructionExtension with the date. -+ * The criticality is set to false. -+ * -+ * @param oid the value to be set for the extension. -+ */ -+ public HoldInstructionExtension(ObjectIdentifier oid) -+ throws IOException { -+ if (getHoldInstructionCodeFromOID(oid) == 0) -+ throw new IOException("Invalid hold instruction code"); -+ holdInstructionCodeOID = oid; -+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a HoldInstructionExtension with the date. -+ * The criticality is set to false. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param code the value to be set for the extension. -+ */ -+ public HoldInstructionExtension(Boolean critical, int code) -+ throws IOException { -+ if (code < 1 || code > 3) -+ throw new IOException("Invalid hold instruction code"); -+ holdInstructionCodeOID = holdInstructionCodeOIDs[code - 1]; -+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id; -+ this.critical = critical.booleanValue(); -+ encodeThis(); -+ } -+ -+ /** -+ * Create a HoldInstructionExtension with the date. -+ * The criticality is set to false. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param oidStr the value to be set for the extension. -+ */ -+ public HoldInstructionExtension(Boolean critical, String oidStr) -+ throws IOException { -+ ObjectIdentifier oid = new ObjectIdentifier(oidStr); -+ if (oid == null || getHoldInstructionCodeFromOID(oid) == 0) -+ throw new IOException("Invalid hold instruction code"); -+ holdInstructionCodeOID = oid; -+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id; -+ this.critical = critical.booleanValue(); -+ encodeThis(); -+ } -+ -+ /** -+ * Create a HoldInstructionExtension with the date. -+ * The criticality is set to false. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param oid the value to be set for the extension. -+ */ -+ public HoldInstructionExtension(Boolean critical, ObjectIdentifier oid) -+ throws IOException { -+ if (getHoldInstructionCodeFromOID(oid) == 0) -+ throw new IOException("Invalid hold instruction code"); -+ holdInstructionCodeOID = oid; -+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id; -+ this.critical = critical.booleanValue(); -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public HoldInstructionExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id; -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ if (val.tag == DerValue.tag_ObjectId) { -+ DerInputStream derInputStream = new DerInputStream(val.toByteArray()); -+ holdInstructionCodeOID = derInputStream.getOID(); -+ if (getHoldInstructionCodeFromOID(holdInstructionCodeOID) == 0) -+ throw new IOException("Invalid encoding for HoldInstructionExtension"); -+ } else { -+ throw new IOException("Invalid encoding for HoldInstructionExtension"); -+ } -+ } -+ -+ /** -+ * Get the hold instruction code. -+ */ -+ public ObjectIdentifier getHoldInstructionCode() { -+ return holdInstructionCodeOID; -+ } -+ -+ public String getHoldInstructionCodeDescription() { -+ return getHoldInstructionDescription(holdInstructionCodeOID); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (name.equalsIgnoreCase(HOLD_INSTRUCTION)) { -+ if (!(obj instanceof ObjectIdentifier)) { -+ throw new IOException("Attribute must be of type String."); -+ } -+ holdInstructionCodeOID = (ObjectIdentifier) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by" + -+ " CertAttrSet:HoldInstructionCode."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(HOLD_INSTRUCTION)) { -+ return holdInstructionCodeOID; -+ } else { -+ throw new IOException("Attribute name not recognized by" + -+ " CertAttrSet:HoldInstructionCode."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(HOLD_INSTRUCTION)) { -+ holdInstructionCodeOID = null; -+ } else { -+ throw new IOException("Attribute name not recognized by" + -+ " CertAttrSet:HoldInstructionCode."); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the HoldInstructionExtension. -+ */ -+ public String toString() { -+ String s = super.toString() + "Hold Instruction Code: " + -+ getHoldInstructionDescription(holdInstructionCodeOID) + "\n"; -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ this.extensionId = PKIXExtensions.HoldInstructionCode_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(HOLD_INSTRUCTION); -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/IA5StringConverter.java b/org/mozilla/jss/netscape/security/x509/IA5StringConverter.java -new file mode 100644 -index 00000000..125e4b7e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/IA5StringConverter.java -@@ -0,0 +1,123 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.CharacterCodingException; -+import java.nio.charset.CharsetEncoder; -+ -+import org.mozilla.jss.netscape.security.util.ASN1CharStrConvMap; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * A AVAValueConverter that converts a IA5String attribute to a DerValue -+ * and vice versa. An example an attribute that is a IA5String string is "E". -+ * -+ * @see AVAValueConverter -+ * -+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc. -+ */ -+ -+public class IA5StringConverter implements AVAValueConverter { -+ // public constructors -+ -+ /* -+ * Contructs a IA5String Converter. -+ */ -+ public IA5StringConverter() { -+ } -+ -+ /* -+ * Converts a string with ASN.1 IA5String characters to a DerValue. -+ * -+ * @param valueString a string with IA5String characters. -+ * -+ * @return a DerValue. -+ * -+ * @exception IOException if a IA5String encoder is not -+ * available for the conversion. -+ */ -+ public DerValue getValue(String valueString) -+ throws IOException { -+ return getValue(valueString, null); -+ } -+ -+ public DerValue getValue(String valueString, byte[] tags) throws IOException { -+ try { -+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(DerValue.tag_IA5String); -+ if (encoder == null) -+ throw new IOException("No encoder for IA5String"); -+ -+ CharBuffer charBuffer = CharBuffer.wrap(valueString.toCharArray()); -+ ByteBuffer byteBuffer = encoder.encode(charBuffer); -+ -+ return new DerValue(DerValue.tag_IA5String, -+ byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit()); -+ -+ } catch (CharacterCodingException e) { -+ throw new IllegalArgumentException("Invalid IA5String AVA Value string"); -+ } -+ } -+ -+ /* -+ * Converts a BER encoded value of IA5String to a DER encoded value. -+ * Checks if the BER encoded value is a IA5String. -+ * NOTE only DER encoding is currently supported on for the BER -+ * encoded value. -+ * -+ * @param berStream a byte array of the BER encoded value. -+ * -+ * @return a DerValue. -+ * -+ * @exception IOException if the BER value cannot be converted -+ * to a IA5String DER value. -+ */ -+ public DerValue getValue(byte[] berStream) -+ throws IOException { -+ DerValue value = new DerValue(berStream); -+ if (value.tag == DerValue.tag_IA5String) -+ return value; -+ if (value.tag == DerValue.tag_PrintableString) -+ return value; -+ throw new IOException("Invalid IA5String AVA Value."); -+ } -+ -+ /* -+ * Converts a DerValue of IA5String to a java string with IA5String -+ * characters. -+ * -+ * @param avaValue a DerValue. -+ * -+ * @return a string with IA5String characters. -+ * -+ * @exception IOException if the DerValue is not a IA5String i.e. -+ * The DerValue cannot be converted to a string -+ * with IA5String characters. -+ */ -+ public String getAsString(DerValue avaValue) -+ throws IOException { -+ if (avaValue.tag == DerValue.tag_IA5String) -+ return avaValue.getIA5String(); -+ if (avaValue.tag == DerValue.tag_PrintableString) -+ return avaValue.getPrintableString(); -+ throw new IOException("Invalid IA5String AVA Value."); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/IPAddressName.java b/org/mozilla/jss/netscape/security/x509/IPAddressName.java -new file mode 100644 -index 00000000..efc14fa3 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/IPAddressName.java -@@ -0,0 +1,277 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.util.StringTokenizer; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class implements the IPAddressName as required by the GeneralNames -+ * ASN.1 object. -+ * -+ * @see GeneralName -+ * @see GeneralNameInterface -+ * @see GeneralNames -+ * -+ * @version 1.2 -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class IPAddressName implements GeneralNameInterface { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -4240184399679453666L; -+ private byte[] address; -+ -+ /** -+ * Create the IPAddressName object from the passed encoded Der value. -+ * -+ * @param derValue the encoded DER IPAddressName. -+ * @exception IOException on error. -+ */ -+ public IPAddressName(DerValue derValue) throws IOException { -+ address = derValue.getOctetString(); -+ } -+ -+ /** -+ * Create the IPAddressName object with the specified name. -+ * -+ * @param name the IPAddressName. -+ */ -+ public IPAddressName(byte[] address) { -+ this.address = address; -+ } -+ -+ protected static final char IPv4_LEN = 4; -+ protected static final char IPv6_LEN = 16; -+ protected static final IPAddr IPv4 = new IPv4Addr(); -+ protected static final IPAddr IPv6 = new IPv6Addr(); -+ -+ /** -+ * Create the IPAddressName object with a string representing the -+ * ip address and a string representing the netmask, with encoding -+ * having ip address encoding followed by the netmask encoding. -+ * This form is needed for name constraints extension. -+ * -+ * @param s the ip address in the format: n.n.n.n or x:x:x:x:x:x:x:x (RFC 1884) -+ * @param netmask the netmask address in the format: n.n.n.n or x:x:x:x:x:x:x:x (RFC 1884) -+ */ -+ public IPAddressName(String s, String netmask) { -+ // Based on PKIX RFC2459. IPAddress has -+ // 8 bytes (instead of 4 bytes) in the -+ // context of NameConstraints -+ IPAddr ipAddr = null; -+ if (s.indexOf(':') != -1) { -+ ipAddr = IPv6; -+ address = new byte[IPv6_LEN * 2]; -+ } else { -+ ipAddr = IPv4; -+ address = new byte[IPv4_LEN * 2]; -+ } -+ StringTokenizer st = new StringTokenizer(s, ","); -+ int numFilled = ipAddr.getIPAddr(st.nextToken(), address, 0); -+ if (st.hasMoreTokens()) { -+ ipAddr.getIPAddr(st.nextToken(), address, numFilled); -+ } else { -+ for (int i = numFilled; i < address.length; i++) -+ address[i] = (byte) 0xff; -+ } -+ } -+ -+ /** -+ * Create the IPAddressName object with a string representing the -+ * ip address. -+ * -+ * @param s the ip address in the format: n.n.n.n or x:x:x:x:x:x:x:x -+ */ -+ public IPAddressName(String s) { -+ IPAddr ipAddr = null; -+ if (s.indexOf(':') != -1) { -+ ipAddr = IPv6; -+ address = new byte[IPv6_LEN]; -+ } else { -+ ipAddr = IPv4; -+ address = new byte[IPv4_LEN]; -+ } -+ ipAddr.getIPAddr(s, address, 0); -+ } -+ -+ /** -+ * Return the type of the GeneralName. -+ */ -+ public int getType() { -+ return (GeneralNameInterface.NAME_IP); -+ } -+ -+ /** -+ * Encode the IPAddress name into the DerOutputStream. -+ * -+ * @param out the DER stream to encode the IPAddressName to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putOctetString(address); -+ } -+ -+ /** -+ * Return a printable string of IPaddress -+ */ -+ public String toString() { -+ if (address.length == 4) { -+ return ("IPAddress: " + (address[0] & 0xff) + "." -+ + (address[1] & 0xff) + "." -+ + (address[2] & 0xff) + "." + (address[3] & 0xff)); -+ } else { -+ StringBuffer r = new StringBuffer("IPAddress: " + Integer.toHexString(address[0] & 0xff)); -+ String hexString = Integer.toHexString(address[1] & 0xff); -+ if (hexString.length() == 1) { -+ r.append("0" + hexString); -+ } else { -+ r.append(hexString); -+ } -+ for (int i = 2; i < address.length;) { -+ r.append(":" + Integer.toHexString(address[i] & 0xff)); -+ hexString = Integer.toHexString(address[i + 1] & 0xff); -+ if (hexString.length() == 1) { -+ r.append("0" + hexString); -+ } else { -+ r.append(hexString); -+ } -+ i += 2; -+ } -+ return r.toString(); -+ } -+ } -+} -+ -+interface IPAddr { -+ public int getIPAddr(String s, byte[] address, int start); -+ -+ public int getLength(); -+} -+ -+class IPv4Addr implements IPAddr { -+ protected static final int IPv4_LEN = 4; -+ -+ /** -+ * Gets an IP v4 address in the form n.n.n.n. -+ */ -+ public int getIPAddr(String s, byte[] address, int start) { -+ StringTokenizer st = new StringTokenizer(s, "."); -+ int nt = st.countTokens(); -+ if (nt != IPv4_LEN) -+ throw new InvalidIPAddressException(s); -+ try { -+ int end = start + nt; -+ for (int i = start; i < end; i++) { -+ Integer j = new Integer(st.nextToken()); -+ address[i] = (byte) j.intValue(); -+ } -+ } catch (NumberFormatException e) { -+ throw new InvalidIPAddressException(s); -+ } -+ return nt; -+ } -+ -+ public int getLength() { -+ return IPv4_LEN; -+ } -+} -+ -+class IPv6Addr implements IPAddr { -+ /** -+ * Gets an IP address in the forms as defined in RFC1884:
-+ *

    -+ *
  • x:x:x:x:x:x:x:x -+ *
  • ...::xxx (using :: shorthand) -+ *
  • ...:n.n.n.n (with n.n.n.n at the end) -+ *
-+ */ -+ public int getIPAddr(String s, byte[] address, int start) { -+ int lastcolon = -2; -+ int end = start + 16; -+ int idx = start; -+ for (int i = start; i < address.length; i++) -+ address[i] = 0; -+ if (s.indexOf('.') != -1) { // has n.n.n.n at the end -+ lastcolon = s.lastIndexOf(':'); -+ if (lastcolon == -1) -+ throw new InvalidIPAddressException(s); -+ end -= 4; -+ IPAddressName.IPv4.getIPAddr( -+ s.substring(lastcolon + 1), address, end); -+ } -+ try { -+ String s1 = s; -+ if (lastcolon != -2) -+ s1 = s.substring(0, lastcolon + 1); -+ int lastDoubleColon = s1.indexOf("::"); -+ String l = s1, r = null; -+ StringTokenizer lt = null, rt = null; -+ if (lastDoubleColon != -1) { -+ l = s1.substring(0, lastDoubleColon); -+ r = s1.substring(lastDoubleColon + 2); -+ if (l.length() == 0) -+ l = null; -+ if (r.length() == 0) -+ r = null; -+ } -+ int at = 0; -+ if (l != null) { -+ lt = new StringTokenizer(l, ":", false); -+ at += lt.countTokens(); -+ } -+ if (r != null) { -+ rt = new StringTokenizer(r, ":", false); -+ at += rt.countTokens(); -+ } -+ if (at > 8 || -+ (lastcolon != -2 && (at > 6 || (lastDoubleColon == -1 && at != 6)))) -+ throw new InvalidIPAddressException(s); -+ if (l != null) { -+ while (lt.hasMoreTokens()) { -+ String tok = lt.nextToken(); -+ int j = Integer.parseInt(tok, 16); -+ address[idx++] = (byte) ((j >> 8) & 0xFF); -+ address[idx++] = (byte) (j & 0xFF); -+ } -+ } -+ if (r != null) { -+ idx = end - (rt.countTokens() * 2); -+ while (rt.hasMoreTokens()) { -+ String tok = rt.nextToken(); -+ int j = Integer.parseInt(tok, 16); -+ address[idx++] = (byte) ((j >> 8) & 0xFF); -+ address[idx++] = (byte) (j & 0xFF); -+ } -+ } -+ } catch (NumberFormatException e) { -+ throw new InvalidIPAddressException(s); -+ } -+ return 16; -+ } -+ -+ public int getLength() { -+ return 16; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/InvalidIPAddressException.java b/org/mozilla/jss/netscape/security/x509/InvalidIPAddressException.java -new file mode 100644 -index 00000000..72cadca4 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/InvalidIPAddressException.java -@@ -0,0 +1,33 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+public class InvalidIPAddressException extends RuntimeException { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -1601934234587845028L; -+ -+ public InvalidIPAddressException() { -+ super(); -+ } -+ -+ public InvalidIPAddressException(String ip) { -+ super("Invalid IP Address '" + ip + "'"); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/InvalidityDateExtension.java b/org/mozilla/jss/netscape/security/x509/InvalidityDateExtension.java -new file mode 100755 -index 00000000..cc63c148 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/InvalidityDateExtension.java -@@ -0,0 +1,242 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.security.cert.CertificateException; -+import java.util.Date; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the CRL Invalidity Date Extension. -+ * -+ *

-+ * This CRL entry extension, if present, provides the date on which it is known or suspected that the private key was -+ * compromised or that the certificate otherwise became invalid. Invalidity date may be earlier than the revocation -+ * date. -+ * -+ * @see Extension -+ * @see CertAttrSet -+ */ -+ -+public class InvalidityDateExtension extends Extension -+ implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 2191026017389643053L; -+ /** -+ * Attribute name. -+ */ -+ public static final String NAME = "InvalidityDate"; -+ public static final String INVALIDITY_DATE = "value"; -+ -+ /** -+ * The Object Identifier for this extension. -+ */ -+ public static final String OID = "2.5.29.24"; -+ -+ private Date invalidityDate = null; -+ -+ static { -+ try { -+ OIDMap.addAttribute(InvalidityDateExtension.class.getName(), -+ OID, NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ if (invalidityDate == null) -+ throw new IOException("Unintialized invalidity date extension"); -+ try (DerOutputStream os = new DerOutputStream()) { -+ os.putGeneralizedTime(this.invalidityDate); -+ this.extensionValue = os.toByteArray(); -+ } -+ } -+ -+ /** -+ * Create a InvalidityDateExtension with the date. -+ * The criticality is set to false. -+ * -+ * @param dateOfInvalidity the value to be set for the extension. -+ */ -+ public InvalidityDateExtension(Date dateOfInvalidity) -+ throws IOException { -+ this.invalidityDate = dateOfInvalidity; -+ this.extensionId = PKIXExtensions.InvalidityDate_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a InvalidityDateExtension with the date. -+ * The criticality is set to false. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param dateOfInvalidity the value to be set for the extension. -+ */ -+ public InvalidityDateExtension(Boolean critical, Date dateOfInvalidity) -+ throws IOException { -+ this.invalidityDate = dateOfInvalidity; -+ this.extensionId = PKIXExtensions.InvalidityDate_Id; -+ this.critical = critical.booleanValue(); -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public InvalidityDateExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.InvalidityDate_Id; -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ if (val.tag == DerValue.tag_GeneralizedTime) { -+ DerInputStream derInputStream = new DerInputStream(val.toByteArray()); -+ this.invalidityDate = derInputStream.getGeneralizedTime(); -+ } else { -+ throw new IOException("Invalid encoding for InvalidityDateExtension"); -+ } -+ } -+ -+ /** -+ * Get the invalidity date. -+ */ -+ public Date getInvalidityDate() { -+ return invalidityDate; -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (name.equalsIgnoreCase(INVALIDITY_DATE)) { -+ if (!(obj instanceof Date)) { -+ throw new IOException("Attribute must be of type Date."); -+ } -+ invalidityDate = (Date) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by" + -+ " CertAttrSet:InvalidityDate."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(INVALIDITY_DATE)) { -+ if (invalidityDate == null) -+ return null; -+ else -+ return invalidityDate; -+ } else { -+ throw new IOException("Attribute name not recognized by" + -+ " CertAttrSet:InvalidityDate."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(INVALIDITY_DATE)) { -+ invalidityDate = null; -+ } else { -+ throw new IOException("Attribute name not recognized by" + -+ " CertAttrSet:InvalidityDate."); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the InvalidityDateExtension. -+ */ -+ public String toString() { -+ String s = super.toString() + "Invalidity Date: " + -+ ((invalidityDate == null) ? "" : invalidityDate.toString()) -+ + "\n"; -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ this.extensionId = PKIXExtensions.InvalidityDate_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(INVALIDITY_DATE); -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/IssuerAlternativeNameExtension.java b/org/mozilla/jss/netscape/security/x509/IssuerAlternativeNameExtension.java -new file mode 100644 -index 00000000..84556d78 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/IssuerAlternativeNameExtension.java -@@ -0,0 +1,239 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This represents the Issuer Alternative Name Extension. -+ * -+ * This extension, if present, allows the issuer to specify multiple -+ * alternative names. -+ * -+ *

-+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating -+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding -+ * of the extension value). -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.7 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class IssuerAlternativeNameExtension -+ extends Extension implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -269518027483586255L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = -+ "x509.info.extensions.IssuerAlternativeName"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "IssuerAlternativeName"; -+ public static final String ISSUER_NAME = "issuer_name"; -+ -+ // private data members -+ GeneralNames names; -+ -+ // Encode this extension -+ private void encodeThis() throws IOException { -+ DerOutputStream os = new DerOutputStream(); -+ try { -+ names.encode(os); -+ } catch (GeneralNamesException e) { -+ throw new IOException(e); -+ } -+ this.extensionValue = os.toByteArray(); -+ } -+ -+ /** -+ * Create a IssuerAlternativeNameExtension with the passed GeneralNames. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param names the GeneralNames for the issuer. -+ * @exception IOException on error. -+ */ -+ public IssuerAlternativeNameExtension(Boolean critical, GeneralNames names) -+ throws IOException { -+ this.names = names; -+ this.extensionId = PKIXExtensions.IssuerAlternativeName_Id; -+ this.critical = critical.booleanValue(); -+ encodeThis(); -+ } -+ -+ /** -+ * Create a IssuerAlternativeNameExtension with the passed GeneralNames. -+ * -+ * @param names the GeneralNames for the issuer. -+ * @exception IOException on error. -+ */ -+ public IssuerAlternativeNameExtension(GeneralNames names) -+ throws IOException { -+ this.names = names; -+ this.extensionId = PKIXExtensions.IssuerAlternativeName_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a default IssuerAlternativeNameExtension. -+ */ -+ public IssuerAlternativeNameExtension() { -+ extensionId = PKIXExtensions.IssuerAlternativeName_Id; -+ critical = false; -+ names = new GeneralNames(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public IssuerAlternativeNameExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.IssuerAlternativeName_Id; -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ try { -+ names = new GeneralNames(val); -+ } catch (GeneralNamesException e) { -+ throw new IOException("IssuerAlternativeNameExtension: " + e, e); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the IssuerAlternativeName. -+ */ -+ public String toString() { -+ if (names == null) -+ return ""; -+ String s = super.toString() + "IssuerAlternativeName [\n" -+ + names.toString() + "]\n"; -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding error. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ extensionId = PKIXExtensions.IssuerAlternativeName_Id; -+ critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (name.equalsIgnoreCase(ISSUER_NAME)) { -+ if (!(obj instanceof GeneralNames)) { -+ throw new IOException("Attribute value should be of" + -+ " type GeneralNames."); -+ } -+ names = (GeneralNames) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:IssuerAlternativeName."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(ISSUER_NAME)) { -+ return (names); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:IssuerAlternativeName."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(ISSUER_NAME)) { -+ names = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:IssuerAlternativeName."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(ISSUER_NAME); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/IssuingDistributionPoint.java b/org/mozilla/jss/netscape/security/x509/IssuingDistributionPoint.java -new file mode 100644 -index 00000000..8125bfca ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/IssuingDistributionPoint.java -@@ -0,0 +1,323 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.BufferedOutputStream; -+import java.io.ByteArrayOutputStream; -+import java.io.FileOutputStream; -+import java.io.IOException; -+import java.io.OutputStream; -+ -+import org.mozilla.jss.netscape.security.util.BitArray; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+ -+import org.mozilla.jss.asn1.ANY; -+import org.mozilla.jss.asn1.ASN1Value; -+import org.mozilla.jss.asn1.BOOLEAN; -+import org.mozilla.jss.asn1.EXPLICIT; -+import org.mozilla.jss.asn1.InvalidBERException; -+import org.mozilla.jss.asn1.SEQUENCE; -+import org.mozilla.jss.asn1.Tag; -+ -+/** -+ *

-+ * issuingDistributionPoint ::= SEQUENCE {
-+ *         distributionPoint       [0] DistributionPointName OPTIONAL,
-+ *         onlyContainsUserCerts   [1] BOOLEAN DEFAULT FALSE,
-+ *         onlyContainsCACerts     [2] BOOLEAN DEFAULT FALSE,
-+ *         onlySomeReasons         [3] ReasonFlags OPTIONAL,
-+ *         indirectCRL             [4] BOOLEAN DEFAULT FALSE }
-+ *
-+ * DistributionPointName ::= CHOICE {
-+ *         fullName                [0]     GeneralNames,
-+ *         nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
-+ *
-+ * ReasonFlags ::= BIT STRING {
-+ *         unused                  (0),
-+ *         keyCompromise           (1),
-+ *         cACompromise            (2),
-+ *         affiliationChanged      (3),
-+ *         superseded              (4),
-+ *         cessationOfOperation    (5),
-+ *         certificateHold         (6) }
-+ *
-+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-+ *
-+ * GeneralName ::= CHOICE {
-+ *         otherName                       [0]     OtherName,
-+ *         rfc822Name                      [1]     IA5String,
-+ *         dNSName                         [2]     IA5String,
-+ *         x400Address                     [3]     ORAddress,
-+ *         directoryName                   [4]     Name,
-+ *         ediPartyName                    [5]     EDIPartyName,
-+ *         uniformResourceIdentifier       [6]     IA5String,
-+ *         iPAddress                       [7]     OCTET STRING,
-+ *         registeredID                    [8]     OBJECT IDENTIFIER}
-+ *
-+ * OtherName ::= SEQUENCE {
-+ *         type-id    OBJECT IDENTIFIER,
-+ *         value      [0] EXPLICIT ANY DEFINED BY type-id }
-+ *
-+ * EDIPartyName ::= SEQUENCE {
-+ *         nameAssigner            [0]     DirectoryString OPTIONAL,
-+ *         partyName               [1]     DirectoryString }
-+ *
-+ * RelativeDistinguishedName ::=
-+ *         SET OF AttributeTypeAndValue
-+ *
-+ * AttributeTypeAndValue ::= SEQUENCE {
-+ *         type     AttributeType,
-+ *         value    AttributeValue }
-+ *
-+ * AttributeType ::= OBJECT IDENTIFIER
-+ *
-+ * AttributeValue ::= ANY DEFINED BY AttributeType
-+ * 
-+ * -+ * See the documentation in CRLDistributionPoint for -+ * the DistributionPointName and ReasonFlags ASN.1 types. -+ */ -+public class IssuingDistributionPoint implements ASN1Value { -+ -+ // at most one of the following two may be specified. One or both can -+ // be null. -+ private GeneralNames fullName = null; -+ private RDN relativeName = null; -+ -+ private boolean onlyContainsUserCerts = false; // DEFAULT FALSE -+ private boolean onlyContainsCACerts = false; // DEFAULT FALSE -+ private BitArray onlySomeReasons = null; // optional, may be null -+ private boolean indirectCRL = false; // DEFAULT FALSE -+ -+ // cache encoding of fullName -+ private ANY fullNameEncoding; -+ -+ /** -+ * Returns the fullName of the DistributionPointName, which may be null. -+ */ -+ public GeneralNames getFullName() { -+ return fullName; -+ } -+ -+ /** -+ * Returns the relativeName of the DistributionPointName, which may be null. -+ */ -+ public RDN getRelativeName() { -+ return relativeName; -+ } -+ -+ /** -+ * Sets the fullName of the DistributionPointName. It may be set to null. -+ * If it is set to a non-null value, relativeName will be -+ * set to null, because at most one of these two attributes -+ * can be specified at a time. -+ * -+ * @exception GeneralNamesException If an error occurs encoding the -+ * name. -+ */ -+ public void setFullName(GeneralNames fullName) -+ throws GeneralNamesException, IOException { -+ this.fullName = fullName; -+ if (fullName != null) { -+ // encode the name to catch any problems with it -+ DerOutputStream derOut = new DerOutputStream(); -+ fullName.encode(derOut); -+ try { -+ ANY raw = new ANY(derOut.toByteArray()); -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ raw.encodeWithAlternateTag(Tag.get(0), bos); -+ fullNameEncoding = new ANY(bos.toByteArray()); -+ } catch (InvalidBERException e) { -+ // assume this won't happen, since it would imply a bug -+ // in DerOutputStream -+ throw new GeneralNamesException(e.toString()); -+ } -+ -+ this.relativeName = null; -+ } -+ } -+ -+ /** -+ * Sets the relativeName of the DistributionPointName. It may be set to null. -+ * If it is set to a non-null value, fullName will be -+ * set to null, because at most one of these two attributes -+ * can be specified at a time. -+ */ -+ public void setRelativeName(RDN relativeName) { -+ this.relativeName = relativeName; -+ if (relativeName != null) { -+ this.fullName = null; -+ } -+ } -+ -+ public boolean getOnlyContainsUserCerts() { -+ return onlyContainsUserCerts; -+ } -+ -+ public void setOnlyContainsUserCerts(boolean b) { -+ onlyContainsUserCerts = b; -+ } -+ -+ public boolean getOnlyContainsCACerts() { -+ return onlyContainsCACerts; -+ } -+ -+ public void setOnlyContainsCACerts(boolean b) { -+ onlyContainsCACerts = b; -+ } -+ -+ /** -+ * Returns the reason flags for this distribution point. May be null. -+ */ -+ public BitArray getOnlySomeReasons() { -+ return onlySomeReasons; -+ } -+ -+ /** -+ * Sets the reason flags for this distribution point. May be set to null. -+ */ -+ public void setOnlySomeReasons(BitArray reasons) { -+ this.onlySomeReasons = reasons; -+ } -+ -+ public boolean getIndirectCRL() { -+ return indirectCRL; -+ } -+ -+ public void setIndirectCRL(boolean b) { -+ indirectCRL = b; -+ } -+ -+ ///////////////////////////////////////////////////////////// -+ // DER encoding -+ ///////////////////////////////////////////////////////////// -+ private static final Tag TAG = SEQUENCE.TAG; -+ -+ public Tag getTag() { -+ return TAG; -+ } -+ -+ public void encode(OutputStream ostream) throws IOException { -+ encode(TAG, ostream); -+ } -+ -+ public void encode(Tag implicitTag, OutputStream ostream) -+ throws IOException { -+ -+ SEQUENCE seq = new SEQUENCE(); -+ DerOutputStream derOut; -+ -+ try { -+ -+ // Encodes the DistributionPointName. Because DistributionPointName -+ // is a CHOICE, the [0] tag is forced to be EXPLICIT. -+ if (fullName != null) { -+ EXPLICIT distPoint = new EXPLICIT(Tag.get(0), fullNameEncoding); -+ seq.addElement(distPoint); -+ } else if (relativeName != null) { -+ derOut = new DerOutputStream(); -+ relativeName.encode(derOut); -+ ANY raw = new ANY(derOut.toByteArray()); -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ raw.encodeWithAlternateTag(Tag.get(1), bos); -+ ANY distPointName = new ANY(bos.toByteArray()); -+ EXPLICIT distPoint = new EXPLICIT(Tag.get(0), distPointName); -+ seq.addElement(distPoint); -+ } -+ -+ if (onlyContainsUserCerts != false) { -+ seq.addElement(Tag.get(1), new BOOLEAN(true)); -+ } -+ if (onlyContainsCACerts != false) { -+ seq.addElement(Tag.get(2), new BOOLEAN(true)); -+ } -+ -+ // Encodes the ReasonFlags. -+ if (onlySomeReasons != null) { -+ derOut = new DerOutputStream(); -+ derOut.putUnalignedBitString(onlySomeReasons); -+ ANY raw = new ANY(derOut.toByteArray()); -+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); -+ raw.encodeWithAlternateTag(Tag.get(3), bos); -+ ANY reasonEncoding = new ANY(bos.toByteArray()); -+ seq.addElement(reasonEncoding); -+ } -+ -+ if (indirectCRL != false) { -+ seq.addElement(Tag.get(4), new BOOLEAN(true)); -+ } -+ -+ seq.encode(implicitTag, ostream); -+ -+ } catch (InvalidBERException e) { -+ // this shouldn't happen unless there is a bug in one of -+ // the Sun encoding classes -+ throw new IOException(e.toString()); -+ } -+ } -+ -+ public static void main(String args[]) { -+ BufferedOutputStream bos = null; -+ -+ try { -+ if (args.length != 1) { -+ System.out.println("Usage: IssuingDistributionPoint "); -+ System.exit(-1); -+ } -+ -+ bos = new BufferedOutputStream( -+ new FileOutputStream(args[0])); -+ -+ SEQUENCE idps = new SEQUENCE(); -+ -+ IssuingDistributionPoint idp = new IssuingDistributionPoint(); -+ -+ X500Name dn = new X500Name("CN=Skovw Wjasldk,E=nicolson@netscape.com" + -+ ",OU=Certificate Server,O=Netscape,C=US"); -+ GeneralNames generalNames = new GeneralNames(); -+ generalNames.addElement(dn); -+ idp.setFullName(generalNames); -+ idps.addElement(idp); -+ -+ idp = new IssuingDistributionPoint(); -+ URIName uri = new URIName("http://www.mycrl.com/go/here"); -+ generalNames = new GeneralNames(); -+ generalNames.addElement(uri); -+ idp.setFullName(generalNames); -+ idp.setOnlyContainsUserCerts(true); -+ idp.setOnlyContainsCACerts(true); -+ idp.setIndirectCRL(true); -+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 }); -+ idp.setOnlySomeReasons(ba); -+ idps.addElement(idp); -+ -+ idps.encode(bos); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } finally { -+ if (bos != null) { -+ try { -+ bos.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/IssuingDistributionPointExtension.java b/org/mozilla/jss/netscape/security/x509/IssuingDistributionPointExtension.java -new file mode 100644 -index 00000000..4cc26d93 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/IssuingDistributionPointExtension.java -@@ -0,0 +1,425 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.BufferedOutputStream; -+import java.io.FileOutputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.security.cert.CertificateException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.asn1.ASN1Util; -+ -+import org.mozilla.jss.netscape.security.util.BitArray; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * A critical CRL extension that identifies the CRL distribution point -+ * for a particular CRL -+ * -+ *
-+ * issuingDistributionPoint ::= SEQUENCE {
-+ *         distributionPoint       [0] DistributionPointName OPTIONAL,
-+ *         onlyContainsUserCerts   [1] BOOLEAN DEFAULT FALSE,
-+ *         onlyContainsCACerts     [2] BOOLEAN DEFAULT FALSE,
-+ *         onlySomeReasons         [3] ReasonFlags OPTIONAL,
-+ *         indirectCRL             [4] BOOLEAN DEFAULT FALSE }
-+ *
-+ * DistributionPointName ::= CHOICE {
-+ *         fullName                [0]     GeneralNames,
-+ *         nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
-+ *
-+ * ReasonFlags ::= BIT STRING {
-+ *         unused                  (0),
-+ *         keyCompromise           (1),
-+ *         cACompromise            (2),
-+ *         affiliationChanged      (3),
-+ *         superseded              (4),
-+ *         cessationOfOperation    (5),
-+ *         certificateHold         (6) }
-+ *
-+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-+ *
-+ * GeneralName ::= CHOICE {
-+ *         otherName                       [0]     OtherName,
-+ *         rfc822Name                      [1]     IA5String,
-+ *         dNSName                         [2]     IA5String,
-+ *         x400Address                     [3]     ORAddress,
-+ *         directoryName                   [4]     Name,
-+ *         ediPartyName                    [5]     EDIPartyName,
-+ *         uniformResourceIdentifier       [6]     IA5String,
-+ *         iPAddress                       [7]     OCTET STRING,
-+ *         registeredID                    [8]     OBJECT IDENTIFIER}
-+ *
-+ * OtherName ::= SEQUENCE {
-+ *         type-id    OBJECT IDENTIFIER,
-+ *         value      [0] EXPLICIT ANY DEFINED BY type-id }
-+ *
-+ * EDIPartyName ::= SEQUENCE {
-+ *         nameAssigner            [0]     DirectoryString OPTIONAL,
-+ *         partyName               [1]     DirectoryString }
-+ *
-+ * RelativeDistinguishedName ::=
-+ *         SET OF AttributeTypeAndValue
-+ *
-+ * AttributeTypeAndValue ::= SEQUENCE {
-+ *         type     AttributeType,
-+ *         value    AttributeValue }
-+ *
-+ * AttributeType ::= OBJECT IDENTIFIER
-+ *
-+ * AttributeValue ::= ANY DEFINED BY AttributeType
-+ * 
-+ */ -+public class IssuingDistributionPointExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -1281544042375527550L; -+ -+ /** -+ * The Object Identifier for this extension. -+ */ -+ public static final String OID = "2.5.29.28"; -+ -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "IssuingDistributionPoint"; -+ public static final String ISSUING_DISTRIBUTION_POINT = "issuing_distribution_point"; -+ -+ // Private data members -+ private IssuingDistributionPoint issuingDistributionPoint = null; -+ -+ // Cached DER-encoding to improve performance. -+ private byte[] cachedEncoding = null; -+ -+ static { -+ try { -+ OIDMap.addAttribute(IssuingDistributionPointExtension.class.getName(), -+ OID, NAME); -+ } catch (CertificateException e) { -+ } -+ } -+ -+ /** -+ * This constructor is very important, since it will be called -+ * by the system. -+ */ -+ public IssuingDistributionPointExtension(Boolean critical, Object value) -+ throws IOException { -+ -+ this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id; -+ this.critical = critical.booleanValue(); -+ this.extensionValue = ((byte[]) value).clone(); -+ -+ byte[] extValue = this.extensionValue; -+ issuingDistributionPoint = new IssuingDistributionPoint(); -+ DerValue val = new DerValue(extValue); -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint"); -+ } -+ -+ while (val.data.available() != 0) { -+ DerValue opt = val.data.getDerValue(); -+ -+ if (opt != null) { -+ for (int i = 0; i < 5; i++) { -+ if (opt.isContextSpecific((byte) i)) { -+ if ((i == 0 && opt.isConstructed() && opt.data.available() != 0) || -+ (i != 0 && (!opt.isConstructed()) && opt.data.available() != 0)) { -+ -+ if (i == 0) { -+ DerValue opt1 = opt.data.getDerValue(); -+ if (opt1 != null) { -+ if (opt1.isContextSpecific((byte) 0)) { -+ if (opt1.isConstructed() && opt1.data.available() != 0) { -+ opt1.resetTag(DerValue.tag_Sequence); -+ -+ try { -+ GeneralNames fullName = new GeneralNames(opt1); -+ if (fullName != null) { -+ issuingDistributionPoint.setFullName(fullName); -+ } -+ } catch (GeneralNamesException e) { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e); -+ } catch (IOException e) { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e); -+ } -+ } else { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint"); -+ } -+ -+ } else if (opt1.isContextSpecific((byte) 1)) { -+ if (opt1.isConstructed() && opt1.data.available() != 0) { -+ opt1.resetTag(DerValue.tag_Set); -+ -+ try { -+ RDN relativeName = new RDN(opt1); -+ if (relativeName != null) { -+ issuingDistributionPoint.setRelativeName(relativeName); -+ } -+ } catch (IOException e) { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e); -+ } -+ } else { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint"); -+ } -+ } -+ } -+ -+ } else if (i == 3) { -+ opt.resetTag(DerValue.tag_BitString); -+ try { -+ BitArray reasons = opt.getUnalignedBitString(); -+ if (reasons == null) { -+ throw new IOException("Unable to get the unaligned bit string."); -+ } -+ issuingDistributionPoint.setOnlySomeReasons(reasons); -+ -+ @SuppressWarnings("unused") -+ byte[] a = reasons.toByteArray(); // check for errors -+ } catch (IOException e) { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e); -+ } -+ -+ } else { -+ opt.resetTag(DerValue.tag_Boolean); -+ try { -+ boolean b = opt.getBoolean(); -+ if (i == 1) { -+ issuingDistributionPoint.setOnlyContainsUserCerts(b); -+ } else if (i == 2) { -+ issuingDistributionPoint.setOnlyContainsCACerts(b); -+ } else if (i == 4) { -+ issuingDistributionPoint.setIndirectCRL(b); -+ } -+ } catch (IOException e) { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e); -+ } -+ } -+ } else { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint"); -+ } -+ } -+ } -+ } else { -+ throw new IOException("Invalid encoding of IssuingDistributionPoint"); -+ } -+ } -+ -+ } -+ -+ /** -+ * Creates a new IssuingDistributionPoint extension, with the given -+ * issuing distribution point as the first element. -+ */ -+ public IssuingDistributionPointExtension(IssuingDistributionPoint idp) { -+ this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id; -+ this.critical = true; -+ issuingDistributionPoint = idp; -+ } -+ -+ /** -+ * Returns the issuing distribution point. -+ */ -+ public IssuingDistributionPoint getIssuingDistributionPoint() { -+ return issuingDistributionPoint; -+ } -+ -+ /** -+ * Sets the criticality of this extension. PKIX dictates that this -+ * extension SHOULD be critical, so applications can make it not critical -+ * if they have a very good reason. By default, the extension is critical. -+ */ -+ public void setCritical(boolean critical) { -+ this.critical = critical; -+ } -+ -+ /** -+ * Gets the criticality of this extension. PKIX dictates that this -+ * extension SHOULD be critical, so by default, the extension is critical. -+ */ -+ public boolean getCritical(boolean critical) { -+ return this.critical; -+ } -+ -+ /** -+ * Encodes this extension to the given DerOutputStream. -+ * This method re-encodes each time it is called, so it is not very -+ * efficient. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ extensionValue = ASN1Util.encode(issuingDistributionPoint); -+ super.encode(out); -+ } -+ -+ /** -+ * Should be called if any change is made to this data structure -+ * so that the cached DER encoding can be discarded. -+ */ -+ public void flushCachedEncoding() { -+ cachedEncoding = null; -+ } -+ -+ /** -+ * Returns a printable representation of the IssuingDistributionPointExtension -+ */ -+ @Override -+ public String toString() { -+ return NAME; -+ } -+ -+ /** -+ * DER-encodes this extension to the given OutputStream. -+ */ -+ public void encode(OutputStream ostream) -+ throws CertificateException, IOException { -+ if (cachedEncoding == null) { -+ // only re-encode if necessary -+ DerOutputStream tmp = new DerOutputStream(); -+ encode(tmp); -+ cachedEncoding = tmp.toByteArray(); -+ } -+ ostream.write(cachedEncoding); -+ } -+ -+ public void decode(InputStream in) -+ throws CertificateException, IOException { -+ throw new IOException("Not supported"); -+ } -+ -+ public void set(String name, Object obj) -+ throws CertificateException, IOException { -+ if (name.equalsIgnoreCase(ISSUING_DISTRIBUTION_POINT)) { -+ if (!(obj instanceof IssuingDistributionPoint)) { -+ throw new IOException("Attribute value should be of type IssuingDistributionPoint."); -+ } -+ issuingDistributionPoint = (IssuingDistributionPoint) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:IssuingDistributionPointExtension"); -+ } -+ } -+ -+ public Object get(String name) -+ throws CertificateException, IOException { -+ if (name.equalsIgnoreCase(ISSUING_DISTRIBUTION_POINT)) { -+ return issuingDistributionPoint; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:IssuingDistributionPointExtension"); -+ } -+ } -+ -+ public void delete(String name) -+ throws CertificateException, IOException { -+ if (name.equalsIgnoreCase(ISSUING_DISTRIBUTION_POINT)) { -+ issuingDistributionPoint = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:IssuingDistributionPointExtension"); -+ } -+ } -+ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(ISSUING_DISTRIBUTION_POINT); -+ return (elements.elements()); -+ // return (new Vector()).elements(); -+ } -+ -+ public String getName() { -+ return NAME; -+ } -+ -+ /** -+ * Test driver. -+ */ -+ public static void main(String args[]) { -+ -+ BufferedOutputStream bos = null; -+ try { -+ -+ if (args.length != 1) { -+ System.out.println("Usage: IssuingDistributionPointExtension " + -+ ""); -+ System.exit(-1); -+ } -+ -+ bos = new BufferedOutputStream( -+ new FileOutputStream(args[0])); -+ -+ // URI only -+ IssuingDistributionPoint idp = new IssuingDistributionPoint(); -+ URIName uri = new URIName("http://www.mycrl.com/go/here"); -+ GeneralNames generalNames = new GeneralNames(); -+ generalNames.addElement(uri); -+ idp.setFullName(generalNames); -+ IssuingDistributionPointExtension idpExt = -+ new IssuingDistributionPointExtension(idp); -+ -+ // DN only -+ idp = new IssuingDistributionPoint(); -+ X500Name dn = new X500Name("CN=Otis Smith,E=otis@fedoraproject.org" + -+ ",OU=Certificate Server,O=Fedora,C=US"); -+ generalNames = new GeneralNames(); -+ generalNames.addElement(dn); -+ idp.setFullName(generalNames); -+ idpExt.set(IssuingDistributionPointExtension.ISSUING_DISTRIBUTION_POINT, idp); -+ -+ // DN + reason -+ BitArray ba = new BitArray(5, new byte[] { (byte) 0x28 }); -+ idp = new IssuingDistributionPoint(); -+ idp.setFullName(generalNames); -+ idp.setOnlySomeReasons(ba); -+ idpExt.set(IssuingDistributionPointExtension.ISSUING_DISTRIBUTION_POINT, idp); -+ -+ // relative DN + reason + crlIssuer -+ idp = new IssuingDistributionPoint(); -+ RDN rdn = new RDN("OU=foobar dept"); -+ idp.setRelativeName(rdn); -+ idp.setOnlySomeReasons(ba); -+ idp.setOnlyContainsCACerts(true); -+ idp.setOnlyContainsUserCerts(true); -+ idp.setIndirectCRL(true); -+ idpExt.set(IssuingDistributionPointExtension.ISSUING_DISTRIBUTION_POINT, idp); -+ -+ idpExt.setCritical(false); -+ idpExt.encode(bos); -+ -+ -+ -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } finally { -+ if (bos != null) { -+ try { -+ bos.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/KeyIdentifier.java b/org/mozilla/jss/netscape/security/x509/KeyIdentifier.java -new file mode 100644 -index 00000000..5d4c183d ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/KeyIdentifier.java -@@ -0,0 +1,87 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the Key Identifier ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.4 -+ */ -+public class KeyIdentifier implements java.io.Serializable { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 2412286879441154979L; -+ private byte[] octetString; -+ -+ /** -+ * Create a KeyIdentifier with the passed bit settings. -+ * -+ * @param octetString the octet string identifying the key identifier. -+ */ -+ public KeyIdentifier(byte[] octetString) { -+ this.octetString = octetString; -+ } -+ -+ /** -+ * Create a KeyIdentifier from the DER encoded value. -+ * -+ * @param val the DerValue -+ */ -+ public KeyIdentifier(DerValue val) throws IOException { -+ octetString = val.getOctetString(); -+ } -+ -+ /** -+ * Return the value of the KeyIdentifier as byte array. -+ */ -+ public byte[] getIdentifier() { -+ return octetString.clone(); -+ } -+ -+ /** -+ * Returns a printable representation of the KeyUsage. -+ */ -+ public String toString() { -+ org.mozilla.jss.netscape.security.util.PrettyPrintFormat pp = -+ new org.mozilla.jss.netscape.security.util.PrettyPrintFormat(" ", 20); -+ String octetbits = pp.toHexString(octetString); -+ -+ String s = "KeyIdentifier [\n"; -+ s += octetbits; -+ s += "]\n"; -+ return (s); -+ } -+ -+ /** -+ * Write the KeyIdentifier to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException -+ */ -+ void encode(DerOutputStream out) throws IOException { -+ out.putOctetString(octetString); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/KeyUsageExtension.java b/org/mozilla/jss/netscape/security/x509/KeyUsageExtension.java -new file mode 100644 -index 00000000..6baf8d55 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/KeyUsageExtension.java -@@ -0,0 +1,420 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BitArray; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the Key Usage Extension. -+ * -+ *

-+ * This extension, if present, defines the purpose (e.g., encipherment, signature, certificate signing) of the key -+ * contained in the certificate. The usage restriction might be employed when a multipurpose key is to be restricted -+ * (e.g., when an RSA key should be used only for signing or only for key encipherment). -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.9 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class KeyUsageExtension extends Extension -+ implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 2899719374157256708L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions.KeyUsage"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "KeyUsage"; -+ public static final String DIGITAL_SIGNATURE = "digital_signature"; -+ public static final String NON_REPUDIATION = "non_repudiation"; -+ public static final String KEY_ENCIPHERMENT = "key_encipherment"; -+ public static final String DATA_ENCIPHERMENT = "data_encipherment"; -+ public static final String KEY_AGREEMENT = "key_agreement"; -+ public static final String KEY_CERTSIGN = "key_certsign"; -+ public static final String CRL_SIGN = "crl_sign"; -+ public static final String ENCIPHER_ONLY = "encipher_only"; -+ public static final String DECIPHER_ONLY = "decipher_only"; -+ -+ public static final int DIGITAL_SIGNATURE_BIT = 0; -+ public static final int NON_REPUDIATION_BIT = 1; -+ public static final int KEY_ENCIPHERMENT_BIT = 2; -+ public static final int DATA_ENCIPHERMENT_BIT = 3; -+ public static final int KEY_AGREEMENT_BIT = 4; -+ public static final int KEY_CERTSIGN_BIT = 5; -+ public static final int CRL_SIGN_BIT = 6; -+ public static final int ENCIPHER_ONLY_BIT = 7; -+ public static final int DECIPHER_ONLY_BIT = 8; -+ -+ public static final int NBITS = 9; -+ -+ public static String[] names = new String[NBITS]; -+ -+ static { -+ names[DIGITAL_SIGNATURE_BIT] = DIGITAL_SIGNATURE; -+ names[NON_REPUDIATION_BIT] = NON_REPUDIATION; -+ names[KEY_ENCIPHERMENT_BIT] = KEY_ENCIPHERMENT; -+ names[DATA_ENCIPHERMENT_BIT] = DATA_ENCIPHERMENT; -+ names[KEY_AGREEMENT_BIT] = KEY_AGREEMENT; -+ names[KEY_CERTSIGN_BIT] = KEY_CERTSIGN; -+ names[CRL_SIGN_BIT] = CRL_SIGN; -+ names[ENCIPHER_ONLY_BIT] = ENCIPHER_ONLY; -+ names[DECIPHER_ONLY_BIT] = DECIPHER_ONLY; -+ } -+ -+ // Private data members -+ private boolean[] bitString; -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ try (DerOutputStream os = new DerOutputStream()) { -+ os.putUnalignedBitString(this.bitString); -+ this.extensionValue = os.toByteArray(); -+ } -+ } -+ -+ /** -+ * Check if bit is set. -+ * -+ * @param position the position in the bit string to check. -+ */ -+ private boolean isSet(int position) { -+ if (bitString.length <= position) -+ return false; -+ return bitString[position]; -+ } -+ -+ /** -+ * Set the bit at the specified position. -+ */ -+ private void set(int position, boolean val) { -+ // enlarge bitString if necessary -+ if (position >= bitString.length) { -+ boolean[] tmp = new boolean[position + 1]; -+ System.arraycopy(bitString, 0, tmp, 0, bitString.length); -+ bitString = tmp; -+ } -+ bitString[position] = val; -+ } -+ -+ /** -+ * Create a KeyUsageExtension with the passed bit settings. The criticality -+ * is set to true. -+ * -+ * @param bitString the bits to be set for the extension. -+ */ -+ public KeyUsageExtension(boolean critical, byte[] bitString) throws IOException { -+ this.bitString = -+ new BitArray(bitString.length * 8, bitString).toBooleanArray(); -+ this.extensionId = PKIXExtensions.KeyUsage_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ public KeyUsageExtension(byte[] bitString) throws IOException { -+ this.bitString = -+ new BitArray(bitString.length * 8, bitString).toBooleanArray(); -+ this.extensionId = PKIXExtensions.KeyUsage_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a KeyUsageExtension with the passed bit settings. The criticality -+ * is set to true. -+ * -+ * @param bitString the bits to be set for the extension. -+ */ -+ public KeyUsageExtension(boolean critical, boolean[] bitString) throws IOException { -+ this.bitString = bitString; -+ this.extensionId = PKIXExtensions.KeyUsage_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ public KeyUsageExtension(boolean[] bitString) throws IOException { -+ this.bitString = bitString; -+ this.extensionId = PKIXExtensions.KeyUsage_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a KeyUsageExtension with the passed bit settings. The criticality -+ * is set to true. -+ * -+ * @param bitString the bits to be set for the extension. -+ */ -+ public KeyUsageExtension(BitArray bitString) throws IOException { -+ this.bitString = bitString.toBooleanArray(); -+ this.extensionId = PKIXExtensions.KeyUsage_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value of the same. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public KeyUsageExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.KeyUsage_Id; -+ this.critical = critical.booleanValue(); -+ /* -+ * The following check should be activated again after -+ * the PKIX profiling work becomes standard and the check -+ * is not a barrier to interoperability ! -+ * if (!this.critical) { -+ * throw new IOException("KeyUsageExtension not marked critical," -+ * + " invalid profile."); -+ * } -+ */ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ BitArray bitArray = val.getUnalignedBitString(); -+ if (bitArray == null) { -+ throw new IOException("Invalid bit string"); -+ } -+ this.bitString = bitArray.toBooleanArray(); -+ -+ } -+ -+ /** -+ * Create a default key usage. -+ */ -+ public KeyUsageExtension() { -+ extensionId = PKIXExtensions.KeyUsage_Id; -+ critical = true; -+ bitString = new boolean[0]; -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (!(obj instanceof Boolean)) { -+ throw new IOException("Attribute must be of type Boolean."); -+ } -+ boolean val = ((Boolean) obj).booleanValue(); -+ if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) { -+ set(0, val); -+ } else if (name.equalsIgnoreCase(NON_REPUDIATION)) { -+ set(1, val); -+ } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) { -+ set(2, val); -+ } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) { -+ set(3, val); -+ } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) { -+ set(4, val); -+ } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) { -+ set(5, val); -+ } else if (name.equalsIgnoreCase(CRL_SIGN)) { -+ set(6, val); -+ } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) { -+ set(7, val); -+ } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) { -+ set(8, val); -+ } else { -+ throw new IOException("Attribute name not recognized by" -+ + " CertAttrSet:KeyUsage."); -+ } -+ encodeThis(); -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) { -+ return Boolean.valueOf(isSet(0)); -+ } else if (name.equalsIgnoreCase(NON_REPUDIATION)) { -+ return Boolean.valueOf(isSet(1)); -+ } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) { -+ return Boolean.valueOf(isSet(2)); -+ } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) { -+ return Boolean.valueOf(isSet(3)); -+ } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) { -+ return Boolean.valueOf(isSet(4)); -+ } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) { -+ return Boolean.valueOf(isSet(5)); -+ } else if (name.equalsIgnoreCase(CRL_SIGN)) { -+ return Boolean.valueOf(isSet(6)); -+ } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) { -+ return Boolean.valueOf(isSet(7)); -+ } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) { -+ return Boolean.valueOf(isSet(8)); -+ } else { -+ throw new IOException("Attribute name not recognized by" -+ + " CertAttrSet:KeyUsage."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) { -+ set(0, false); -+ } else if (name.equalsIgnoreCase(NON_REPUDIATION)) { -+ set(1, false); -+ } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) { -+ set(2, false); -+ } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) { -+ set(3, false); -+ } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) { -+ set(4, false); -+ } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) { -+ set(5, false); -+ } else if (name.equalsIgnoreCase(CRL_SIGN)) { -+ set(6, false); -+ } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) { -+ set(7, false); -+ } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) { -+ set(8, false); -+ } else { -+ throw new IOException("Attribute name not recognized by" -+ + " CertAttrSet:KeyUsage."); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the KeyUsage. -+ */ -+ public String toString() { -+ String s = super.toString() + "KeyUsage [\n"; -+ -+ try { -+ if (isSet(0)) { -+ s += " DigitalSignature\n"; -+ } -+ if (isSet(1)) { -+ s += " Non_repudiation\n"; -+ } -+ if (isSet(2)) { -+ s += " Key_Encipherment\n"; -+ } -+ if (isSet(3)) { -+ s += " Data_Encipherment\n"; -+ } -+ if (isSet(4)) { -+ s += " Key_Agreement\n"; -+ } -+ if (isSet(5)) { -+ s += " Key_CertSign\n"; -+ } -+ if (isSet(6)) { -+ s += " Crl_Sign\n"; -+ } -+ if (isSet(7)) { -+ s += " Encipher_Only\n"; -+ } -+ if (isSet(8)) { -+ s += " Decipher_Only\n"; -+ } -+ } catch (ArrayIndexOutOfBoundsException ex) { -+ } -+ -+ s += "]\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ if (this.extensionValue == null) { -+ this.extensionId = PKIXExtensions.KeyUsage_Id; -+ this.critical = true; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(DIGITAL_SIGNATURE); -+ elements.addElement(NON_REPUDIATION); -+ elements.addElement(KEY_ENCIPHERMENT); -+ elements.addElement(DATA_ENCIPHERMENT); -+ elements.addElement(KEY_AGREEMENT); -+ elements.addElement(KEY_CERTSIGN); -+ elements.addElement(CRL_SIGN); -+ elements.addElement(ENCIPHER_ONLY); -+ elements.addElement(DECIPHER_ONLY); -+ -+ return (elements.elements()); -+ } -+ -+ public boolean[] getBits() { -+ return bitString.clone(); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/LdapDNStrConverter.java b/org/mozilla/jss/netscape/security/x509/LdapDNStrConverter.java -new file mode 100644 -index 00000000..2c2d421c ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/LdapDNStrConverter.java -@@ -0,0 +1,144 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+/** -+ * Abstract class that converts a Ldap DN String to an X500Name, RDN or AVA -+ * and vice versa, except the string is a java string in unicode. -+ * -+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc. -+ */ -+ -+public abstract class LdapDNStrConverter { -+ // -+ // public parsing methods. -+ // -+ -+ /** -+ * Converts a Ldap DN string to a X500Name object. -+ * -+ * @param dn a Ldap DN String. -+ * -+ * @return an X500Name object for the Ldap DN String. -+ */ -+ public abstract X500Name parseDN(String dn) -+ throws IOException; -+ -+ /** -+ * Like parseDN with a specified DER encoding order for Directory Strings. -+ */ -+ public abstract X500Name parseDN(String dn, byte[] tags) -+ throws IOException; -+ -+ /** -+ * Converts a Ldap DN string to a RDN object. -+ * -+ * @param rdn a Ldap DN String -+ * -+ * @return an RDN object. -+ */ -+ public abstract RDN parseRDN(String rdn) -+ throws IOException; -+ -+ /** -+ * Like parseRDN with a specified DER encoding order for Directory Strings. -+ */ -+ public abstract RDN parseRDN(String rdn, byte[] tags) -+ throws IOException; -+ -+ /** -+ * Converts a Ldap DN string to a AVA object. -+ * -+ * @param ava a Ldap DN string. -+ * @return an AVA object. -+ */ -+ public abstract AVA parseAVA(String ava) -+ throws IOException; -+ -+ /** -+ * Like parseAVA with a specified DER encoding order for Directory Strings. -+ */ -+ public abstract AVA parseAVA(String rdn, byte[] tags) -+ throws IOException; -+ -+ // -+ // public encoding methods. -+ // -+ -+ /** -+ * Converts a X500Name object to a Ldap dn string. -+ * -+ * @param dn an X500Name object. -+ * @return a Ldap DN String. -+ */ -+ public abstract String encodeDN(X500Name dn) throws IOException; -+ -+ /** -+ * Converts an RDN object to a Ldap dn string. -+ * -+ * @param rdn an RDN object. -+ * @return a Ldap dn string. -+ */ -+ public abstract String encodeRDN(RDN rdn) throws IOException; -+ -+ /** -+ * Converts an AVA object to a Ldap dn string. -+ * -+ * @param ava An AVA object. -+ * @return A Ldap dn string. -+ */ -+ public abstract String encodeAVA(AVA ava) throws IOException; -+ -+ // -+ // public static methods -+ // -+ -+ /** -+ * Gets a global default Ldap DN String converter. -+ * Currently it is LdapV3DNStrConverter object using the default -+ * X500NameAttrMap and accepts unknown OIDs. -+ * -+ * @see netscape.security.x509.LdapV3DNStrConverter -+ * -+ * @return The global default LdapDNStrConverter instance. -+ */ -+ public static LdapDNStrConverter getDefault() { -+ return defaultConverter; -+ } -+ -+ /** -+ * Set the global default LdapDNStrConverter object. -+ * -+ * @param defConverter A LdapDNStrConverter object to become -+ * the global default. -+ */ -+ public static void setDefault(LdapDNStrConverter defConverter) { -+ if (defConverter == null) -+ throw new IllegalArgumentException( -+ "The default Ldap DN String converter cannot be set to null."); -+ defaultConverter = defConverter; -+ } -+ -+ // -+ // private static variables -+ // -+ -+ private static LdapDNStrConverter defaultConverter = new LdapV3DNStrConverter(); -+} -diff --git a/org/mozilla/jss/netscape/security/x509/LdapV3DNStrConverter.java b/org/mozilla/jss/netscape/security/x509/LdapV3DNStrConverter.java -new file mode 100644 -index 00000000..2e8829b7 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/LdapV3DNStrConverter.java -@@ -0,0 +1,824 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.ByteArrayOutputStream; -+import java.io.CharArrayWriter; -+import java.io.IOException; -+import java.io.PushbackReader; -+import java.io.StringReader; -+import java.io.UnsupportedEncodingException; -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.CharacterCodingException; -+import java.nio.charset.Charset; -+import java.nio.charset.CharsetDecoder; -+import java.nio.charset.UnsupportedCharsetException; -+import java.util.Arrays; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * A converter that converts Ldap v3 DN strings as specified in -+ * draft-ietf-asid-ldapv3-dn-03.txt to a X500Name, RDN or AVA and -+ * vice versa. -+ * -+ * @see LdapDNStrConverter -+ * @see X500Name -+ * @see RDN -+ * @see AVA -+ * @see X500NameAttrMap -+ * -+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc. -+ */ -+ -+public class LdapV3DNStrConverter extends LdapDNStrConverter { -+ // -+ // Constructors -+ // -+ -+ /** -+ * Constructs a LdapV3DNStrConverter using the global default -+ * X500NameAttrMap and accept OIDs not in the default X500NameAttrMap. -+ * -+ * @see X500NameAttrMap -+ */ -+ public LdapV3DNStrConverter() { -+ attrMap = X500NameAttrMap.getDefault(); -+ -+ acceptUnknownOids = true; -+ } -+ -+ /** -+ * Constructs a LdapV3DNStrConverter using the specified X500NameAttrMap -+ * and a boolean indicating whether to accept OIDs not listed in the -+ * X500NameAttrMap. -+ * -+ * @param attributeMap a X500NameAttrMap -+ * @param doAcceptUnknownOids whether to convert unregistered OIDs -+ * (oids not in the X500NameAttrMap) -+ * @see X500NameAttrMap -+ */ -+ public LdapV3DNStrConverter(X500NameAttrMap attributeMap, -+ boolean doAcceptUnknownOids) { -+ attrMap = attributeMap; -+ acceptUnknownOids = doAcceptUnknownOids; -+ -+ } -+ -+ // -+ // public parsing methods -+ // From LdapDNStrConverter interface -+ // -+ -+ /** -+ * Parse a Ldap v3 DN string to a X500Name. -+ * -+ * @param dn a LDAP v3 DN String -+ * @return a X500Name -+ * @exception IOException if an error occurs during the conversion. -+ */ -+ public X500Name parseDN(String dn) -+ throws IOException { -+ return parseDN(dn, null); -+ } -+ -+ /** -+ * Like parseDN(String) with a DER encoding order given as argument for -+ * Directory Strings. -+ */ -+ public X500Name parseDN(String dn, byte[] encodingOrder) -+ throws IOException { -+ StringReader dn_reader = new StringReader(dn); -+ PushbackReader in = new PushbackReader(dn_reader, 5); -+ -+ return parseDN(in, encodingOrder); -+ } -+ -+ /** -+ * Parse a Ldap v3 DN string with a RDN component to a RDN -+ * -+ * @param rdn a LDAP v3 DN String -+ * @return a RDN -+ * @exception IOException if an error occurs during the conversion. -+ */ -+ public RDN parseRDN(String rdn) -+ throws IOException { -+ return parseRDN(rdn, null); -+ } -+ -+ /** -+ * Like parseRDN(String) with a DER encoding order given as argument for -+ * Directory Strings. -+ */ -+ public RDN parseRDN(String rdn, byte[] encodingOrder) -+ throws IOException { -+ StringReader rdn_reader = new StringReader(rdn); -+ PushbackReader in = new PushbackReader(rdn_reader, 5); -+ -+ return parseRDN(in, null); -+ } -+ -+ /** -+ * Parse a Ldap v3 DN string with a AVA component to a AVA. -+ * -+ * @param ava a LDAP v3 DN string -+ * @return a AVA -+ */ -+ public AVA parseAVA(String ava) -+ throws IOException { -+ return parseAVA(ava, null); -+ } -+ -+ /** -+ * Like parseDN(String) with a DER encoding order given as argument for -+ * Directory Strings. -+ */ -+ public AVA parseAVA(String ava, byte[] encodingOrder) -+ throws IOException { -+ StringReader ava_reader = new StringReader(ava); -+ PushbackReader in = new PushbackReader(ava_reader, 5); -+ -+ return parseAVA(in, encodingOrder); -+ } -+ -+ // -+ // public parsing methods called by other methods. -+ // -+ -+ /** -+ * Parses a Ldap DN string in a string reader to a X500Name. -+ * -+ * @param in Pushback string reader for a Ldap DN string. -+ * The pushback reader must have a pushback buffer size > 2. -+ * -+ * @return a X500Name -+ * -+ * @exception IOException if any reading or parsing error occurs. -+ */ -+ public X500Name parseDN(PushbackReader in) -+ throws IOException { -+ return parseDN(in, null); -+ } -+ -+ /** -+ * Like parseDN(PushbackReader in) with a DER encoding order given as -+ * argument for Directory Strings. -+ */ -+ public X500Name parseDN(PushbackReader in, byte[] encodingOrder) -+ throws IOException { -+ RDN rdn; -+ int lastChar; -+ Vector rdnVector = new Vector(); -+ RDN names[]; -+ int i, j; -+ -+ do { -+ rdn = parseRDN(in, encodingOrder); -+ rdnVector.addElement(rdn); -+ lastChar = in.read(); -+ } while (lastChar == ',' || lastChar == ';'); -+ -+ names = new RDN[rdnVector.size()]; -+ for (i = 0, j = rdnVector.size() - 1; i < rdnVector.size(); i++, j--) -+ names[j] = rdnVector.elementAt(i); -+ return new X500Name(names); -+ } -+ -+ /** -+ * Parses Ldap DN string with a rdn component -+ * from a string reader to a RDN. The string reader will point -+ * to the separator after the rdn component or -1 if at end of string. -+ * -+ * @param in Pushback string reader containing a Ldap DN string with -+ * at least one rdn component. -+ * The pushback reader must have a pushback buffer size > 2. -+ * -+ * @return RDN object of the first rdn component in the Ldap DN string. -+ * -+ * @exception IOException if any read or parse error occurs. -+ */ -+ public RDN parseRDN(PushbackReader in) -+ throws IOException { -+ return parseRDN(in, null); -+ } -+ -+ /** -+ * Like parseRDN(PushbackReader) with a DER encoding order given as -+ * argument for Directory Strings. -+ */ -+ public RDN parseRDN(PushbackReader in, byte[] encodingOrder) -+ throws IOException { -+ Vector avaVector = new Vector(); -+ AVA ava; -+ int lastChar; -+ AVA assertion[]; -+ -+ do { -+ ava = parseAVA(in, encodingOrder); -+ avaVector.addElement(ava); -+ lastChar = in.read(); -+ } while (lastChar == '+'); -+ -+ if (lastChar != -1) -+ in.unread(lastChar); -+ -+ assertion = new AVA[avaVector.size()]; -+ for (int i = 0; i < avaVector.size(); i++) -+ assertion[i] = avaVector.elementAt(i); -+ return new RDN(assertion); -+ } -+ -+ /** -+ * Parses a Ldap DN string with a AVA component -+ * from a string reader to an AVA. The string reader will point -+ * to the AVA separator after the ava string or -1 if end of string. -+ * -+ * @param in a Pushback reader containg a Ldap string with -+ * at least one AVA component. -+ * The Pushback reader must have a pushback buffer size > 2. -+ * -+ * @return AVA object of the first AVA component in the Ldap DN string. -+ */ -+ public AVA parseAVA(PushbackReader in) -+ throws IOException { -+ return parseAVA(in, null); -+ } -+ -+ /** -+ * Like parseAVA(PushbackReader) with a DER encoding order given as -+ * argument for Directory Strings. -+ */ -+ public AVA parseAVA(PushbackReader in, byte[] encodingOrder) -+ throws IOException { -+ int c; -+ ObjectIdentifier oid; -+ DerValue value; -+ StringBuffer keywordBuf; -+ StringBuffer valueBuf; -+ ByteArrayOutputStream berStream; -+ char hexChar1, hexChar2; -+ CharArrayWriter hexCharsBuf; -+ String endChars; -+ -+ /* First get the keyword indicating the attribute's type, -+ * and map it to the appropriate OID. -+ */ -+ keywordBuf = new StringBuffer(); -+ for (;;) { -+ c = in.read(); -+ if (c == '=') -+ break; -+ if (c == -1) { -+ throw new IOException("Bad AVA format: Missing '='"); -+ } -+ keywordBuf.append((char) c); -+ } -+ oid = parseAVAKeyword(keywordBuf.toString()); -+ -+ /* Now parse the value. "#hex", a quoted string, or a string -+ * terminated by "+", ",", ";", ">". Whitespace before or after -+ * the value is stripped. -+ */ -+ for (c = in.read(); c == ' '; c = in.read()) -+ continue; -+ if (c == -1) -+ throw new IOException("Bad AVA format: Missing attribute value"); -+ -+ if (c == '#') { -+ /* -+ * NOTE per LDAPv3 dn string ietf standard the value represented -+ * by this form is a BER value. But we only support DER value here -+ * which is only a form of BER. -+ */ -+ berStream = new ByteArrayOutputStream(); -+ int b; -+ for (;;) { -+ hexChar1 = (char) (c = in.read()); -+ if (c == -1 || octoEndChars.indexOf(c) > 0) // end of value -+ break; -+ hexChar2 = (char) (c = in.read()); -+ if (hexDigits.indexOf(hexChar1) == -1 || -+ hexDigits.indexOf(hexChar2) == -1) -+ throw new IOException("Bad AVA value: bad hex value."); -+ b = (Character.digit(hexChar1, 16) << 4) + -+ Character.digit(hexChar2, 16); -+ berStream.write(b); -+ } -+ if (berStream.size() == 0) -+ throw new IOException("bad AVA format: invalid hex value"); -+ -+ value = parseAVAValue(berStream.toByteArray(), oid); -+ -+ while (c == ' ' && c != -1) -+ c = in.read(); -+ } else { -+ valueBuf = new StringBuffer(); -+ boolean quoted = false; -+ if (c == '"') { -+ quoted = true; -+ endChars = quotedEndChars; -+ if ((c = in.read()) == -1) -+ throw new IOException("Bad AVA format: Missing attrValue"); -+ } else { -+ endChars = valueEndChars; -+ } -+ -+ // QUOTATION * ( quotechar / pair ) QUOTATION -+ // quotechar = any character except '\' or QUOTATION -+ // pair = '\' ( special | '\' | QUOTATION | hexpair ) -+ while (c != -1 && endChars.indexOf(c) == -1) { -+ if (c == '\\') { -+ if ((c = in.read()) == -1) -+ throw new IOException("Bad AVA format: expecting " + -+ "escaped char."); -+ // expect escaping of special chars, space and CR. -+ if (specialChars.indexOf((char) c) != -1 || c == '\n' || -+ c == '\\' || c == '"' || c == ' ') { -+ valueBuf.append((char) c); -+ } else if (hexDigits.indexOf(c) != -1) { -+ hexCharsBuf = new CharArrayWriter(); -+ // handle sequence of '\' hexpair -+ do { -+ hexChar1 = (char) c; -+ hexChar2 = (char) (c = in.read()); -+ if (hexDigits.indexOf((char) c) == -1) -+ throw new IOException("Bad AVA format: " + -+ "invalid escaped hex pair"); -+ hexCharsBuf.write(hexChar1); -+ hexCharsBuf.write(hexChar2); -+ // read ahead to next '\' hex-char if any. -+ if ((c = in.read()) == -1) -+ break; -+ if (c != '\\') { -+ in.unread(c); -+ break; -+ } -+ if ((c = in.read()) == -1) -+ throw new IOException("Bad AVA format: " + -+ "expecting escaped char."); -+ if (hexDigits.indexOf((char) c) == -1) { -+ in.unread(c); -+ in.unread('\\'); -+ break; -+ } -+ } while (true); -+ valueBuf.append( -+ getStringFromHexpairs(hexCharsBuf.toCharArray())); -+ } else { -+ throw new IOException("Bad AVA format: " + -+ "invalid escaping"); -+ } -+ } else -+ valueBuf.append((char) c); -+ c = in.read(); -+ } -+ -+ value = parseAVAValue( -+ valueBuf.toString().trim(), oid, encodingOrder); -+ -+ if (quoted) { // move to next non-white space -+ do { -+ c = in.read(); -+ } while (c == ' '); -+ if (c != -1 && valueEndChars.indexOf(c) == -1) -+ throw new IOException( -+ "Bad AVA format: separator expected at end of ava."); -+ } -+ } -+ -+ if (c != -1) -+ in.unread(c); -+ -+ return new AVA(oid, value); -+ } -+ -+ /** -+ * Converts a AVA keyword from a Ldap DN string to an ObjectIdentifier -+ * from the attribute map or, if this keyword is an OID not -+ * in the attribute map, create a new ObjectIdentifier for the keyword -+ * if acceptUnknownOids is true. -+ * -+ * @param avaKeyword AVA keyword from a Ldap DN string. -+ * -+ * @return a ObjectIdentifier object -+ * @exception IOException if the keyword is an OID not in the attribute -+ * map and acceptUnknownOids is false, or -+ * if an error occurs during conversion. -+ */ -+ public ObjectIdentifier parseAVAKeyword(String avaKeyword) -+ throws IOException { -+ String keyword = avaKeyword.toUpperCase().trim(); -+ String oid_str = null; -+ ObjectIdentifier oid, new_oid; -+ -+ if (Character.digit(keyword.charAt(0), 10) != -1) { -+ // value is an oid string of 1.2.3.4 -+ oid_str = keyword; -+ } else if (keyword.startsWith("oid.") || keyword.startsWith("OID.")) { -+ // value is an oid string of oid.1.2.3.4 or OID.1.2... -+ oid_str = keyword.substring(4); -+ } -+ -+ if (oid_str != null) { -+ // value is an oid string of 1.2.3.4 or oid.1.2.3.4 or OID.1.2... -+ new_oid = new ObjectIdentifier(oid_str); -+ oid = attrMap.getOid(new_oid); -+ if (oid == null) { -+ if (!acceptUnknownOids) -+ throw new IOException("Unknown AVA OID."); -+ oid = new_oid; -+ } -+ } else { -+ oid = attrMap.getOid(keyword); -+ if (oid == null) -+ throw new IOException("Unknown AVA keyword '" + keyword + "'."); -+ } -+ -+ return oid; -+ } -+ -+ /** -+ * Converts a AVA value from a Ldap dn string to a -+ * DerValue according the attribute type. For example, a value for -+ * CN, OU or O is expected to be a Directory String and will be converted -+ * to a DerValue of ASN.1 type PrintableString, T61String or -+ * UniversalString. A Directory String is a ASN.1 CHOICE of Printable, -+ * T.61 or Universal string. -+ * -+ * @param avaValueString a attribute value from a Ldap DN string. -+ * @param oid OID of the attribute. -+ * -+ * @return DerValue for the value. -+ * -+ * @exception IOException if an error occurs during conversion. -+ * @see AVAValueConverter -+ */ -+ public DerValue parseAVAValue(String avaValueString, ObjectIdentifier oid) -+ throws IOException { -+ return parseAVAValue(avaValueString, oid, null); -+ } -+ -+ /** -+ * Like parseAVAValue(String) with a DER encoding order given as argument -+ * for Directory Strings. -+ */ -+ public DerValue parseAVAValue( -+ String avaValueString, ObjectIdentifier oid, byte[] encodingOrder) -+ throws IOException { -+ AVAValueConverter valueConverter = attrMap.getValueConverter(oid); -+ if (valueConverter == null) { -+ if (!acceptUnknownOids) { -+ throw new IllegalArgumentException( -+ "Unrecognized OID for AVA value conversion"); -+ } else { -+ valueConverter = new GenericValueConverter(); -+ } -+ } -+ return valueConverter.getValue(avaValueString, encodingOrder); -+ } -+ -+ /** -+ * Converts a value in BER encoding, for example given in octothorpe form -+ * in a Ldap v3 dn string, to a DerValue. Checks if the BER encoded value -+ * is a legal value for the attribute. -+ *

-+ * NOTE: only DER encoded values are supported for the BER encoded value. -+ * -+ * @param berValue a value in BER encoding -+ * @param oid ObjectIdentifier of the attribute. -+ * -+ * @return DerValue for the BER encoded value -+ * @exception IOException if an error occurs during conversion. -+ */ -+ public DerValue parseAVAValue(byte[] berValue, ObjectIdentifier oid) -+ throws IOException { -+ AVAValueConverter valueConverter = attrMap.getValueConverter(oid); -+ if (valueConverter == null && !acceptUnknownOids) { -+ throw new IllegalArgumentException( -+ "Unrecognized OID for AVA value conversion"); -+ } else { -+ valueConverter = new GenericValueConverter(); -+ } -+ return valueConverter.getValue(berValue); -+ } -+ -+ // -+ // public encoding methods. -+ // -+ -+ /** -+ * Converts a X500Name object to a Ldap v3 DN string (except in unicode). -+ * -+ * @param x500name a X500Name -+ * -+ * @return a Ldap v3 DN String (except in unicode). -+ * -+ * @exception IOException if an error is encountered during conversion. -+ */ -+ public String encodeDN(X500Name x500name) -+ throws IOException { -+ RDN[] rdns = x500name.getNames(); -+ // String fullname = null; -+ StringBuffer fullname = new StringBuffer(); -+ String s; -+ int i; -+ if (rdns.length == 0) -+ return ""; -+ i = rdns.length - 1; -+ fullname.append(encodeRDN(rdns[i--])); -+ while (i >= 0) { -+ s = encodeRDN(rdns[i--]); -+ fullname.append(","); -+ fullname.append(s); -+ } -+ ; -+ return fullname.toString(); -+ } -+ -+ /** -+ * Converts a RDN to a Ldap v3 DN string (except in unicode). -+ * -+ * @param rdn a RDN -+ * -+ * @return a LDAP v3 DN string (except in unicode). -+ * -+ * @exception IOException if an error is encountered during conversion. -+ */ -+ public String encodeRDN(RDN rdn) -+ throws IOException { -+ AVA[] avas = rdn.getAssertion(); -+ // String relname = null; -+ StringBuffer relname = new StringBuffer(); -+ String s; -+ int i = 0; -+ -+ relname.append(encodeAVA(avas[i++])); -+ while (i < avas.length) { -+ s = encodeAVA(avas[i++]); -+ relname.append("+"); -+ relname.append(s); -+ } -+ ; -+ return relname.toString(); -+ } -+ -+ /** -+ * Converts a AVA to a Ldap v3 DN String (except in unicode). -+ * -+ * @param ava an AVA -+ * -+ * @return a Ldap v3 DN string (except in unicode). -+ * -+ * @exception IOException If an error is encountered during exception. -+ */ -+ public String encodeAVA(AVA ava) -+ throws IOException { -+ if (ava == null) { -+ return ""; -+ } -+ ObjectIdentifier oid = ava.getOid(); -+ DerValue value = ava.getValue(); -+ String keyword, valueStr; -+ -+ // get attribute name -+ -+ keyword = encodeOID(oid); -+ valueStr = encodeValue(value, oid); -+ -+ return keyword + "=" + valueStr; -+ } -+ -+ /** -+ * Converts an OID to a attribute keyword in a Ldap v3 DN string -+ * - either a keyword if known or a string of "1.2.3.4" syntax. -+ * -+ * @param oid a ObjectIdentifier -+ * -+ * @return a keyword to use in a Ldap V3 DN string. -+ * -+ * @exception IOException if an error is encountered during conversion. -+ */ -+ public String encodeOID(ObjectIdentifier oid) -+ throws IOException { -+ String keyword = attrMap.getName(oid); -+ if (keyword == null) { -+ if (acceptUnknownOids) -+ keyword = oid.toString(); -+ else -+ throw new IOException("Unknown OID"); -+ } -+ return keyword; -+ } -+ -+ /** -+ * Converts a value as a DerValue to a string in a Ldap V3 DN String. -+ * If the value cannot be converted to a string it will be encoded in -+ * octothorpe form. -+ * -+ * @param attrValue a value as a DerValue. -+ * @param oid OID for the attribute. -+ * @return a string for the value in a LDAP v3 DN String -+ * @exception IOException if an error occurs during conversion. -+ */ -+ public String encodeValue(DerValue attrValue, ObjectIdentifier oid) -+ throws IOException { -+ /* -+ * Construct the value with as little copying and garbage -+ * production as practical. -+ */ -+ StringBuffer retval = new StringBuffer(30); -+ int i; -+ String temp = null; -+ AVAValueConverter valueConverter; -+ -+ X500NameAttrMap lAttrMap = attrMap; -+ -+ if (attrValue.tag == DerValue.tag_UTF8String) { -+ lAttrMap = X500NameAttrMap.getDirDefault(); -+ -+ } -+ -+ valueConverter = lAttrMap.getValueConverter(oid); -+ if (valueConverter == null) { -+ if (acceptUnknownOids) -+ valueConverter = new GenericValueConverter(); -+ else -+ throw new IOException( -+ "Unknown AVA type for encoding AVA value"); -+ } -+ -+ try { -+ temp = valueConverter.getAsString(attrValue); -+ -+ if (temp == null) { -+ // convert to octothorpe form. -+ byte data[] = attrValue.toByteArray(); -+ -+ retval.append('#'); -+ for (i = 0; i < data.length; i++) { -+ retval.append(hexDigits.charAt((data[i] >> 4) & 0x0f)); -+ retval.append(hexDigits.charAt(data[i] & 0x0f)); -+ } -+ -+ } else { -+ -+ retval.append(encodeString(temp)); -+ -+ } -+ } catch (IOException e) { -+ throw new IllegalArgumentException("malformed AVA DER Value"); -+ } -+ -+ return retval.toString(); -+ } -+ -+ /** -+ * converts a raw value string to a string in Ldap V3 DN string format. -+ * -+ * @param valueStr a 'raw' value string. -+ * @return a attribute value string in Ldap V3 DN string format. -+ */ -+ public String encodeString(String valueStr) { -+ int i, j; -+ int len; -+ StringBuffer retval = new StringBuffer(); -+ -+ /* -+ * generate string according to ldapv3 DN. escaping is used. -+ * Strings generated this way are acceptable by rfc1779 -+ * implementations. -+ */ -+ len = valueStr.length(); -+ -+ // get index of first space at the end of the string. -+ for (j = len - 1; j >= 0 && valueStr.charAt(j) == ' '; j--) -+ continue; -+ -+ // escape spaces at the beginning of the string. -+ for (i = 0; i <= j && valueStr.charAt(i) == ' '; i++) { -+ retval.append('\\'); -+ retval.append(valueStr.charAt(i)); -+ } -+ -+ // escape special characters in the middle of the string. -+ for (; i <= j; i++) { -+ if (valueStr.charAt(i) == '\\') { -+ retval.append('\\'); -+ retval.append(valueStr.charAt(i)); -+ } else if (specialChars.indexOf(valueStr.charAt(i)) != -1) { -+ retval.append('\\'); -+ retval.append(valueStr.charAt(i)); -+ } else if (valueStr.charAt(i) == '"') { -+ retval.append('\\'); -+ retval.append(valueStr.charAt(i)); -+ } else -+ retval.append(valueStr.charAt(i)); -+ } -+ -+ // esacape spaces at the end. -+ for (; i < valueStr.length(); i++) { -+ retval.append('\\'); -+ retval.append(' '); -+ } -+ -+ return retval.toString(); -+ } -+ -+ // -+ // public get/set methods -+ // -+ -+ /** -+ * gets the X500NameAttrMap used by the converter. -+ * -+ * @return X500NameAttrMap used by this converter. -+ */ -+ public X500NameAttrMap getAttrMap() { -+ return attrMap; -+ } -+ -+ /** -+ * returns true if the converter accepts unregistered attributes i.e. -+ * OIDS not in the X500NameAttrMap. -+ * -+ * @return true if converter converts attributes not in the -+ * X500NameAttrMap. -+ */ -+ public boolean getAcceptUnknownOids() { -+ return acceptUnknownOids; -+ } -+ -+ // -+ // private and protected variables -+ // -+ -+ protected X500NameAttrMap attrMap; -+ protected boolean acceptUnknownOids; -+ -+ // -+ // private and protected static variables & methods. -+ // -+ -+ protected static final String specialChars = ",+=<>#;"; -+ -+ protected static final String valueEndChars = "+,;>"; -+ protected static final String quotedEndChars = "\""; -+ protected static final String octoEndChars = " " + valueEndChars; -+ -+ /* -+ * Values that aren't printable strings are emitted as BER-encoded -+ * hex data. -+ */ -+ protected static final String hexDigits = "0123456789ABCDEFabcdef"; -+ -+ /** -+ * Parse a sequence of hex pairs, each pair a UTF8 byte to a java string. -+ * For example, "4C75C48D" is "Luc", the last c with caron. -+ */ -+ protected static char[] getStringFromHexpairs(char[] hexPairs) throws UnsupportedEncodingException { -+ try { -+ byte[] buffer = new byte[hexPairs.length / 2]; -+ -+ for (int i = 0; i < buffer.length; i++) { -+ buffer[i] = (byte) -+ ((Character.digit(hexPairs[i * 2], 16) << 4) + -+ Character.digit(hexPairs[i * 2 + 1], 16)); -+ } -+ -+ Charset charset = Charset.forName("UTF-8"); -+ CharsetDecoder decoder = charset.newDecoder(); -+ -+ CharBuffer charBuffer = decoder.decode(ByteBuffer.wrap(buffer)); -+ -+ return Arrays.copyOfRange(charBuffer.array(), -+ charBuffer.arrayOffset(), charBuffer.arrayOffset() + charBuffer.limit()); -+ -+ } catch (UnsupportedCharsetException e) { -+ throw new UnsupportedEncodingException( -+ "No UTF8 byte to char converter to use for " + -+ "parsing LDAP DN String"); -+ -+ } catch (CharacterCodingException e) { -+ throw new IllegalArgumentException( -+ "Invalid hex pair in LDAP DN String."); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/Makefile b/org/mozilla/jss/netscape/security/x509/Makefile -new file mode 100644 -index 00000000..8fd7054b ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/Makefile -@@ -0,0 +1,45 @@ -+#! gmake -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+####################################################################### -+# (1) Include initial platform-independent assignments (MANDATORY). # -+####################################################################### -+ -+include manifest.mn -+ -+####################################################################### -+# (2) Include "global" configuration information. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/config.mk -+ -+####################################################################### -+# (3) Include "component" configuration information. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (4) Include "local" platform-dependent assignments (OPTIONAL). # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (5) Execute "global" rules. (OPTIONAL) # -+####################################################################### -+ -+include $(CORE_DEPTH)/coreconf/rules.mk -+ -+####################################################################### -+# (6) Execute "component" rules. (OPTIONAL) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -diff --git a/org/mozilla/jss/netscape/security/x509/NSCCommentExtension.java b/org/mozilla/jss/netscape/security/x509/NSCCommentExtension.java -new file mode 100644 -index 00000000..57fa8550 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/NSCCommentExtension.java -@@ -0,0 +1,229 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+import org.mozilla.jss.netscape.security.util.PrettyPrintFormat; -+ -+/** -+ * This class defines the NSCCommentExtension -+ * -+ * @author asondhi -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class NSCCommentExtension extends Extension implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 4066287070285105375L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions.CommentExtension"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "NSCCommentExtension"; -+ public static final String INFOS = "infos"; -+ public static final ObjectIdentifier OID = -+ new ObjectIdentifier("2.16.840.1.113730.1.13"); -+ public String mComment = null; -+ -+ // Private data members -+ private Vector mInfos; -+ -+ private transient PrettyPrintFormat pp = new PrettyPrintFormat(":"); -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ try (DerOutputStream os = new DerOutputStream()) { -+ os.putIA5String(mComment); -+ // DerOutputStream tmp = new DerOutputStream(); -+ // os.write(DerValue.tag_Sequence,tmp); -+ extensionValue = os.toByteArray(); -+ } -+ } -+ -+ /** -+ * Create a NSCCommentExtension with the Vector of CertificatePolicyInfo. -+ * -+ * @param infos the Vector of CertificatePolicyInfo. -+ */ -+ public NSCCommentExtension(boolean critical, String comment) throws IOException { -+ this.mComment = comment; -+ this.extensionId = new ObjectIdentifier("2.16.840.1.113730.1.13"); -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a default NSCCommentExtension. -+ */ -+ public NSCCommentExtension(boolean critical) { -+ this.extensionId = new ObjectIdentifier("2.16.840.1.113730.1.13"); -+ this.critical = critical; -+ mInfos = new Vector(1, 1); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public NSCCommentExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = new ObjectIdentifier("2.16.840.1.113730.1.13"); -+ -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ -+ mComment = val.getIA5String(); -+ } -+ -+ /** -+ * Returns a printable representation of the policy extension. -+ */ -+ public String toString() { -+ if (mInfos == null) -+ return ""; -+ String s = super.toString() + "Netscape Comment [\n" -+ + mInfos.toString() + "]\n"; -+ -+ return (s); -+ } -+ -+ public String toPrint(int indent) { -+ String s; -+ s = "Comment :\n" + pp.indent(indent + 4) + -+ ((mComment == null) ? "" : mComment.trim()) + "\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ extensionId = new ObjectIdentifier("2.16.840.1.113730.1.13"); -+ critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ public String getComment() { -+ return mComment; -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ @SuppressWarnings("unchecked") -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (name.equalsIgnoreCase(INFOS)) { -+ if (!(obj instanceof Vector)) { -+ throw new IOException("Attribute value should be of" + -+ " type Vector."); -+ } -+ mInfos = (Vector) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:NSCCommentExtension."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(INFOS)) { -+ return (mInfos); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:NSCCommentExtension."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(INFOS)) { -+ mInfos = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:NSCCommentExtension."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(INFOS); -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/NameConstraintsExtension.java b/org/mozilla/jss/netscape/security/x509/NameConstraintsExtension.java -new file mode 100644 -index 00000000..7712249a ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/NameConstraintsExtension.java -@@ -0,0 +1,315 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.PrettyPrintFormat; -+ -+/** -+ * This class defines the Name Constraints Extension. -+ *

-+ * The name constraints extension provides permitted and excluded subtrees that place restrictions on names that may be -+ * included within a certificate issued by a given CA. Restrictions may apply to the subject distinguished name or -+ * subject alternative names. Any name matching a restriction in the excluded subtrees field is invalid regardless of -+ * information appearing in the permitted subtrees. -+ *

-+ * The ASN.1 syntax for this is: -+ * -+ *

-+ * NameConstraints ::= SEQUENCE {
-+ *    permittedSubtrees [0]  GeneralSubtrees OPTIONAL,
-+ *    excludedSubtrees  [1]  GeneralSubtrees OPTIONAL
-+ * }
-+ * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
-+ * GeneralSubtree ::== SEQUENCE {
-+ *    base                   GeneralName,
-+ *    minimum           [0]  BaseDistance DEFAULT 0,
-+ *    maximum           [1]  BaseDistance OPTIONAL }
-+ * BaseDistance ::== INTEGER (0..MAX)
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.10 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class NameConstraintsExtension extends Extension implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -3506940192931244539L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions.NameConstraints"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "NameConstraints"; -+ public static final String PERMITTED_SUBTREES = "permitted_subtrees"; -+ public static final String EXCLUDED_SUBTREES = "excluded_subtrees"; -+ -+ // Private data members -+ private static final byte TAG_PERMITTED = 0; -+ private static final byte TAG_EXCLUDED = 1; -+ -+ private GeneralSubtrees permitted; -+ private GeneralSubtrees excluded; -+ -+ private transient PrettyPrintFormat pp = new PrettyPrintFormat(":"); -+ -+ // Encode this extension value. -+ private void encodeThis() throws IOException { -+ try (DerOutputStream seq = new DerOutputStream()) { -+ -+ DerOutputStream tagged = new DerOutputStream(); -+ if ((permitted != null) && (permitted.getSubtrees().size() > 0)) { -+ DerOutputStream tmp = new DerOutputStream(); -+ permitted.encode(tmp); -+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, TAG_PERMITTED), tmp); -+ } -+ if ((excluded != null) && (excluded.getSubtrees().size() > 0)) { -+ DerOutputStream tmp = new DerOutputStream(); -+ excluded.encode(tmp); -+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, TAG_EXCLUDED), tmp); -+ } -+ if (permitted == null && excluded == null) { -+ extensionValue = null; // no need to encode this extension -+ } else { -+ seq.write(DerValue.tag_Sequence, tagged); -+ this.extensionValue = seq.toByteArray(); -+ } -+ } -+ } -+ -+ /** -+ * The default constructor for this class. Either parameter -+ * can be set to null to indicate it is omitted but both -+ * cannot be null. -+ * -+ * @param permitted the permitted GeneralSubtrees (null for optional). -+ * @param excluded the excluded GeneralSubtrees (null for optional). -+ */ -+ public NameConstraintsExtension(GeneralSubtrees permitted, -+ GeneralSubtrees excluded) -+ throws IOException { -+ init(false, permitted, excluded); -+ } -+ -+ public NameConstraintsExtension(boolean critical, -+ GeneralSubtrees permitted, GeneralSubtrees excluded) -+ throws IOException { -+ init(critical, permitted, excluded); -+ } -+ -+ private void init(boolean critical, -+ GeneralSubtrees permitted, GeneralSubtrees excluded) -+ throws IOException { -+ if (permitted == null && excluded == null) { -+ throw new IOException("NameConstraints: Invalid arguments"); -+ } -+ this.permitted = permitted; -+ this.excluded = excluded; -+ -+ this.extensionId = PKIXExtensions.NameConstraints_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public NameConstraintsExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.NameConstraints_Id; -+ this.critical = critical.booleanValue(); -+ -+ if (!(value instanceof byte[])) -+ throw new IOException("Illegal argument type"); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ System.arraycopy(value, 0, extValue, 0, len); -+ -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for" + -+ " NameConstraintsExtension."); -+ } -+ -+ // NB. this is always encoded with the IMPLICIT tag -+ // The checks only make sense if we assume implicit tagging, -+ // with explicit tagging the form is always constructed. -+ while (val.data.available() != 0) { -+ DerValue opt = val.data.getDerValue(); -+ -+ if (opt.isContextSpecific(TAG_PERMITTED) && opt.isConstructed()) { -+ if (permitted != null) { -+ throw new IOException("Duplicate permitted " + -+ "GeneralSubtrees in NameConstraintsExtension."); -+ } -+ opt.resetTag(DerValue.tag_Sequence); -+ permitted = new GeneralSubtrees(opt); -+ -+ } else if (opt.isContextSpecific(TAG_EXCLUDED) && -+ opt.isConstructed()) { -+ if (excluded != null) { -+ throw new IOException("Duplicate excluded " + -+ "GeneralSubtrees in NameConstraintsExtension."); -+ } -+ opt.resetTag(DerValue.tag_Sequence); -+ excluded = new GeneralSubtrees(opt); -+ } else -+ throw new IOException("Invalid encoding of " + -+ "NameConstraintsExtension."); -+ } -+ } -+ -+ /** -+ * Return the printable string. -+ */ -+ public String toString() { -+ return (super.toString() + "NameConstraints: [" + -+ ((permitted == null) ? "" : -+ ("\n Permitted:" + permitted.toString())) + -+ ((excluded == null) ? "" : -+ ("\n Excluded:" + excluded.toString())) + " ]\n"); -+ } -+ -+ public String toPrint(int indent) { -+ return ("GeneralSubtrees: " + -+ ((permitted == null) ? "" : -+ ("\n" + pp.indent(indent + 2) + "Permitted:" + permitted.toPrint(indent + 4))) + -+ ((excluded == null) ? "" : -+ ("\n" + pp.indent(indent + 2) + "Excluded:" + excluded.toPrint(indent + 4))) + "\n"); -+ -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (this.extensionValue == null) { -+ this.extensionId = PKIXExtensions.NameConstraints_Id; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) { -+ if (!(obj instanceof GeneralSubtrees)) { -+ throw new IOException("Attribute value should be" -+ + " of type GeneralSubtrees."); -+ } -+ permitted = (GeneralSubtrees) obj; -+ } else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) { -+ if (!(obj instanceof GeneralSubtrees)) { -+ throw new IOException("Attribute value should be " -+ + "of type GeneralSubtrees."); -+ } -+ excluded = (GeneralSubtrees) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:NameConstraintsExtension."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) { -+ return (permitted); -+ } else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) { -+ return (excluded); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:NameConstraintsExtension."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) { -+ permitted = null; -+ } else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) { -+ excluded = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:NameConstraintsExtension."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(PERMITTED_SUBTREES); -+ elements.addElement(EXCLUDED_SUBTREES); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/NoticeReference.java b/org/mozilla/jss/netscape/security/x509/NoticeReference.java -new file mode 100644 -index 00000000..1855ee31 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/NoticeReference.java -@@ -0,0 +1,96 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.Serializable; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the NoticeReference. -+ * -+ * NoticeReference ::= SEQUENCE { -+ * organization DisplayText, -+ * noticeNumbers SEQUENCE OF INTEGER -+ * } -+ * -+ * @author Thomas Kwan -+ */ -+public class NoticeReference implements Serializable { -+ -+ private static final long serialVersionUID = 1986080941078808200L; -+ private DisplayText mOrg = null; -+ private int mNumbers[] = null; -+ -+ public NoticeReference(DisplayText org, int numbers[]) { -+ mOrg = org; -+ mNumbers = numbers; -+ } -+ -+ public NoticeReference(DerValue val) throws IOException { -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for NoticeReference"); -+ } -+ mOrg = new DisplayText(val.data.getDerValue()); -+ DerValue integers = val.data.getDerValue(); -+ if (integers.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for NoticeReference (integers)"); -+ } -+ Vector num = new Vector(); -+ while (integers.data.available() != 0) { -+ DerValue i = integers.data.getDerValue(); -+ BigInt bigI = i.getInteger(); -+ num.addElement(bigI); -+ } -+ if (num.size() <= 0) -+ return; -+ mNumbers = new int[num.size()]; -+ for (int i = 0; i < num.size(); i++) { -+ mNumbers[i] = num.elementAt(i).toInt(); -+ } -+ } -+ -+ public DisplayText getOrganization() { -+ return mOrg; -+ } -+ -+ public int[] getNumbers() { -+ return mNumbers; -+ } -+ -+ /** -+ * Write the NoticeReference to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ mOrg.encode(tmp); -+ DerOutputStream iseq = new DerOutputStream(); -+ for (int i = 0; i < mNumbers.length; i++) { -+ iseq.putInteger(new BigInt(mNumbers[i])); -+ } -+ tmp.write(DerValue.tag_Sequence, iseq); -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/OIDMap.java b/org/mozilla/jss/netscape/security/x509/OIDMap.java -new file mode 100644 -index 00000000..750bc80a ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/OIDMap.java -@@ -0,0 +1,337 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.File; -+import java.io.FileInputStream; -+import java.io.IOException; -+import java.security.cert.CertificateException; -+import java.util.Hashtable; -+import java.util.Iterator; -+import java.util.Properties; -+ -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * This class defines the mapping from OID & name to classes and vice -+ * versa. Used by CertificateExtensions & PKCS10 to get the java -+ * classes associated with a particular OID/name. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.12 -+ */ -+public class OIDMap { -+ -+ /** -+ * Location for where the OID/Classes maps are stored on -+ * the local system. -+ */ -+ public static final String EXTENSIONS_HOME = -+ (System.getProperty("java.home") + File.separator + "lib" -+ + File.separator + "security" + File.separator + "cert" -+ + File.separator); -+ /** -+ * File names for where OIDs and Classes are registered -+ * for V3 extensions. -+ */ -+ public static final String EXTENSIONS_OIDS = "x509extensions.oid"; -+ public static final String EXTENSIONS_CLASSES = "x509extensions.classes"; -+ -+ // Make default names easier -+ private static final String ROOT = X509CertImpl.NAME + "." + -+ X509CertInfo.NAME + "." + -+ X509CertInfo.EXTENSIONS; -+ private static final String AUTH_KEY_IDENTIFIER = ROOT + "." + -+ AuthorityKeyIdentifierExtension.NAME; -+ private static final String SUB_KEY_IDENTIFIER = ROOT + "." + -+ SubjectKeyIdentifierExtension.NAME; -+ private static final String KEY_USAGE = ROOT + "." + -+ KeyUsageExtension.NAME; -+ private static final String PRIVATE_KEY_USAGE = ROOT + "." + -+ PrivateKeyUsageExtension.NAME; -+ private static final String POLICY_MAPPINGS = ROOT + "." + -+ PolicyMappingsExtension.NAME; -+ private static final String SUB_ALT_NAME = ROOT + "." + -+ SubjectAlternativeNameExtension.NAME; -+ private static final String ISSUER_ALT_NAME = ROOT + "." + -+ IssuerAlternativeNameExtension.NAME; -+ private static final String BASIC_CONSTRAINTS = ROOT + "." + -+ BasicConstraintsExtension.NAME; -+ private static final String NAME_CONSTRAINTS = ROOT + "." + -+ NameConstraintsExtension.NAME; -+ private static final String POLICY_CONSTRAINTS = ROOT + "." + -+ PolicyConstraintsExtension.NAME; -+ private static final String CERT_POLICIES = //ROOT + "." + -+ CertificatePoliciesExtension.NAME; -+ private static final String SUBJ_DIR_ATTR = //ROOT + "." + -+ SubjectDirAttributesExtension.NAME; -+ public static final String EXT_KEY_USAGE_NAME = "ExtendedKeyUsageExtension"; -+ public static final String EXT_INHIBIT_ANY_POLICY_NAME = "InhibitAnyPolicyExtension"; -+ private static final String EXT_KEY_USAGE = //ROOT + "." + -+ EXT_KEY_USAGE_NAME; -+ -+ private static final String CRL_NUMBER = ROOT + "." + -+ CRLNumberExtension.NAME; -+ private static final String CRL_REASON = ROOT + "." + -+ CRLReasonExtension.NAME; -+ -+ private static final Hashtable oid2Name = new Hashtable(); -+ private static final Hashtable name2OID = new Hashtable(); -+ private static final Hashtable name2Class = new Hashtable(); -+ -+ // Initialize recognized extensions from EXTENSIONS_{OIDS/CLASSES} files -+ static { -+ loadNames(); -+ loadClasses(); -+ addClass(CRLDistributionPointsExtension.class); -+ } -+ -+ // Load the default name to oid map (EXTENSIONS_OIDS) -+ private static void loadNamesDefault(Properties props) { -+ props.put(SUB_KEY_IDENTIFIER, "2.5.29.14"); -+ props.put(KEY_USAGE, "2.5.29.15"); -+ props.put(PRIVATE_KEY_USAGE, "2.5.29.16"); -+ props.put(SUB_ALT_NAME, "2.5.29.17"); -+ props.put(ISSUER_ALT_NAME, "2.5.29.18"); -+ props.put(BASIC_CONSTRAINTS, "2.5.29.19"); -+ props.put(CRL_NUMBER, "2.5.29.20"); -+ props.put(CRL_REASON, "2.5.29.21"); -+ props.put(NAME_CONSTRAINTS, "2.5.29.30"); -+ props.put(POLICY_MAPPINGS, "2.5.29.33"); -+ props.put(POLICY_CONSTRAINTS, "2.5.29.36"); -+ props.put(CERT_POLICIES, "2.5.29.32"); -+ props.put(AUTH_KEY_IDENTIFIER, "2.5.29.35"); -+ props.put(SUBJ_DIR_ATTR, "2.5.29.9"); -+ props.put(EXT_KEY_USAGE, "2.5.29.37"); -+ } -+ -+ // Load the default name to class map (EXTENSIONS_CLASSES) -+ private static void loadClassDefault(Properties props) { -+ props.put(AUTH_KEY_IDENTIFIER, -+ "org.mozilla.jss.netscape.security.x509.AuthorityKeyIdentifierExtension"); -+ props.put(SUB_KEY_IDENTIFIER, -+ "org.mozilla.jss.netscape.security.x509.SubjectKeyIdentifierExtension"); -+ props.put(KEY_USAGE, -+ "org.mozilla.jss.netscape.security.x509.KeyUsageExtension"); -+ props.put(PRIVATE_KEY_USAGE, -+ "org.mozilla.jss.netscape.security.x509.PrivateKeyUsageExtension"); -+ props.put(POLICY_MAPPINGS, -+ "org.mozilla.jss.netscape.security.x509.PolicyMappingsExtension"); -+ props.put(SUB_ALT_NAME, -+ "org.mozilla.jss.netscape.security.x509.SubjectAlternativeNameExtension"); -+ props.put(ISSUER_ALT_NAME, -+ "org.mozilla.jss.netscape.security.x509.IssuerAlternativeNameExtension"); -+ props.put(BASIC_CONSTRAINTS, -+ "org.mozilla.jss.netscape.security.x509.BasicConstraintsExtension"); -+ props.put(NAME_CONSTRAINTS, -+ "org.mozilla.jss.netscape.security.x509.NameConstraintsExtension"); -+ props.put(POLICY_CONSTRAINTS, -+ "org.mozilla.jss.netscape.security.x509.PolicyConstraintsExtension"); -+ props.put(CERT_POLICIES, -+ "org.mozilla.jss.netscape.security.x509.CertificatePoliciesExtension"); -+ props.put(SUBJ_DIR_ATTR, -+ "org.mozilla.jss.netscape.security.x509.SubjectDirAttributesExtension"); -+ props.put(EXT_KEY_USAGE, -+ "org.mozilla.jss.netscape.security.extensions.ExtendedKeyUsageExtension"); -+ props.put(CRL_NUMBER, "org.mozilla.jss.netscape.security.x509.CRLNumberExtension"); -+ props.put(CRL_REASON, "org.mozilla.jss.netscape.security.x509.CRLReasonExtension"); -+ } -+ -+ // Return the file along with location -+ private static File certificatePropFile(String fileName) { -+ return (new File(EXTENSIONS_HOME + fileName)); -+ } -+ -+ // Load the names to oid map -+ private static void loadNames() { -+ Properties props = new Properties(); -+ File namesMap = certificatePropFile(EXTENSIONS_OIDS); -+ -+ if (!namesMap.exists()) { -+ loadNamesDefault(props); -+ } else { -+ FileInputStream fis = null; -+ try { -+ fis = new FileInputStream(namesMap); -+ props.load(fis); -+ } catch (IOException e) { -+ loadNamesDefault(props); -+ } finally { -+ if (fis != null) { -+ try { -+ fis.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ -+ Iterator names = props.stringPropertyNames().iterator(); -+ while (names.hasNext()) { -+ String name = names.next(); -+ String oidName = props.getProperty(name); -+ ObjectIdentifier oid = new ObjectIdentifier(oidName); -+ -+ name2OID.put(name, oid); -+ oid2Name.put(oid, name); -+ } -+ } -+ -+ // Load the names to classes map -+ private static void loadClasses() { -+ Properties props = new Properties(); -+ File classMap = certificatePropFile(EXTENSIONS_CLASSES); -+ -+ if (!classMap.exists()) { -+ loadClassDefault(props); -+ } else { -+ FileInputStream fis = null; -+ try { -+ fis = new FileInputStream(classMap); -+ props.load(fis); -+ } catch (IOException e) { -+ loadClassDefault(props); -+ } finally { -+ if (fis != null) { -+ try { -+ fis.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ -+ Iterator names = props.stringPropertyNames().iterator(); -+ while (names.hasNext()) { -+ String name = names.next(); -+ String className = props.getProperty(name); -+ -+ name2Class.put(name, className); -+ } -+ } -+ -+ /** -+ * Add an extension to the OIDMap. -+ * -+ * Assumes existence of static OID and NAME fields with unique values. -+ */ -+ public static void addClass(Class clazz) { -+ try { -+ addAttribute(clazz.getName(), -+ (String) clazz.getField("OID").get(null), -+ (String) clazz.getField("NAME").get(null)); -+ } catch (Throwable e) { -+ System.out.println( -+ "Error adding class " + clazz.getName() + " to OIDMap: " + e); -+ } -+ } -+ -+ /** -+ * Add a name to lookup table. -+ * -+ * @param className the name of the fully qualified class implementing -+ * the asn object. -+ * @param oid the string representation of the object identifier for -+ * the class. -+ * @param name the name of the attribute. -+ * @exception CertificateException on errors. -+ */ -+ public static void addAttribute(String className, String oid, String name) -+ throws CertificateException { -+ ObjectIdentifier objId = new ObjectIdentifier(oid); -+ if (oid2Name.get(objId) != null) { -+ throw new CertificateException("Object identifier already exists."); -+ } -+ if (name2OID.get(name) != null) { -+ throw new CertificateException("Name already exists."); -+ } -+ if (name2Class.get(className) != null) { -+ throw new CertificateException("Class already exists."); -+ } -+ oid2Name.put(objId, name); -+ name2OID.put(name, objId); -+ name2Class.put(name, className); -+ } -+ -+ /** -+ * Return user friendly name associated with the OID. -+ * -+ * @param oid the name of the object identifier to be returned. -+ * @return the user friendly name or null if no name -+ * is registered for this oid. -+ */ -+ public static String getName(ObjectIdentifier oid) { -+ return oid2Name.get(oid); -+ } -+ -+ /** -+ * Return Object identifier for user friendly name. -+ * -+ * @param name the user friendly name. -+ * @return the Object Identifier or null if no oid -+ * is registered for this name. -+ */ -+ public static ObjectIdentifier getOID(String name) { -+ return name2OID.get(name); -+ } -+ -+ /** -+ * Return the java class object associated with the user friendly name. -+ * -+ * @param name the user friendly name. -+ * @exception CertificateException if class cannot be instantiated. -+ */ -+ public static Class getClass(String name) throws CertificateException { -+ String className = name2Class.get(name); -+ if (className == null) -+ return null; -+ try { -+ Class extClass = Class.forName(className); -+ return (extClass); -+ } catch (Exception e) { -+ throw new CertificateException("Error instantiating class for " -+ + name + " " + e.toString()); -+ } -+ } -+ -+ /** -+ * Return the java class object associated with the object identifier.. -+ * -+ * @param oid the name of the object identifier to be returned. -+ * @exception CertificateException if class cannot be instatiated. -+ */ -+ public static Class getClass(ObjectIdentifier oid) -+ throws CertificateException { -+ String name = getName(oid); -+ if (name == null) -+ return null; -+ String className = name2Class.get(name); -+ if (className == null) -+ return null; -+ try { -+ Class extClass = Class.forName(className); -+ return (extClass); -+ } catch (Exception e) { -+ throw new CertificateException("Error instantiating class for " -+ + name + " " + e.toString()); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/OIDName.java b/org/mozilla/jss/netscape/security/x509/OIDName.java -new file mode 100644 -index 00000000..a9b05f74 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/OIDName.java -@@ -0,0 +1,90 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * This class implements the OIDName as required by the GeneralNames -+ * ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.3 -+ * @see GeneralName -+ * @see GeneralNames -+ * @see GeneralNameInterface -+ */ -+public class OIDName implements GeneralNameInterface { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 9198510631835117121L; -+ private ObjectIdentifier oid; -+ -+ /** -+ * Create the OIDName object from the passed encoded Der value. -+ * -+ * @param derValue the encoded DER OIDName. -+ * @exception IOException on error. -+ */ -+ public OIDName(DerValue derValue) throws IOException { -+ oid = derValue.getOID(); -+ } -+ -+ /** -+ * Create the OIDName object with the specified name. -+ * -+ * @param name the OIDName. -+ */ -+ public OIDName(ObjectIdentifier oid) { -+ this.oid = oid; -+ } -+ -+ public OIDName(String oid) { -+ this.oid = new ObjectIdentifier(oid); -+ } -+ -+ /** -+ * Return the type of the GeneralName. -+ */ -+ public int getType() { -+ return (GeneralNameInterface.NAME_OID); -+ } -+ -+ /** -+ * Encode the OID name into the DerOutputStream. -+ * -+ * @param out the DER stream to encode the OIDName to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putOID(oid); -+ } -+ -+ /** -+ * Convert the name into user readable string. -+ */ -+ public String toString() { -+ return ("OIDName: " + oid.toString()); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/OtherName.java b/org/mozilla/jss/netscape/security/x509/OtherName.java -new file mode 100644 -index 00000000..a0a3a4cb ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/OtherName.java -@@ -0,0 +1,214 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * This class implements the OtherName as required by the GeneralNames -+ * ASN.1 object. -+ * -+ * OtherName ::= SEQUENCE { -+ * type-id OBJECT IDENTIFIER, -+ * value [0] EXPLICIT ANY DEFINED BY type-id -+ * } -+ * -+ * @see GeneralName -+ * @see GeneralNameInterface -+ * @see GeneralNames -+ * -+ * @version 1.2 -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class OtherName implements GeneralNameInterface { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -3533614377346132611L; -+ private ObjectIdentifier mOID = null; -+ private byte[] mData = null; -+ -+ /** -+ * Create the IPAddressName object from the passed encoded Der value. -+ * -+ * @param derValue the encoded DER IPAddressName. -+ * @exception IOException on error. -+ */ -+ public OtherName(DerValue derValue) throws IOException { -+ decodeThis(derValue); -+ } -+ -+ public OtherName(ObjectIdentifier oid, byte data[]) throws IOException { -+ mOID = oid; -+ DerOutputStream dos = new DerOutputStream(); -+ try { -+ dos.putDerValue(new DerValue(data)); -+ } catch (IOException e) { -+ } finally { -+ dos.close(); -+ } -+ mData = dos.toByteArray(); -+ } -+ -+ /** -+ * Constructs a string-based other name. -+ */ -+ public OtherName(ObjectIdentifier oid, byte tag, String value) throws IOException { -+ mOID = oid; -+ DerOutputStream dos = new DerOutputStream(); -+ try { -+ if (tag == DerValue.tag_PrintableString) { -+ dos.putPrintableString(value); -+ } else if (tag == DerValue.tag_IA5String) { -+ dos.putIA5String(value); -+ } else if (tag == DerValue.tag_BMPString) { -+ dos.putBMPString(value); -+ } else if (tag == DerValue.tag_UTF8String) { -+ dos.putUTF8String(value); -+ } -+ } catch (IOException e) { -+ } finally { -+ dos.close(); -+ } -+ mData = dos.toByteArray(); -+ } -+ -+ public OtherName(ObjectIdentifier oid, String value) throws IOException { -+ mOID = oid; -+ DerOutputStream dos = new DerOutputStream(); -+ try { -+ dos.putPrintableString(value); -+ } catch (IOException e) { -+ } finally { -+ dos.close(); -+ } -+ mData = dos.toByteArray(); -+ } -+ -+ /** -+ * Create the IPAddressName object with the specified name. -+ * -+ * @param name the IPAddressName. -+ */ -+ public OtherName(byte[] data) { -+ try { -+ decodeThis(new DerValue(data)); -+ } catch (IOException e) { -+ } -+ } -+ -+ public ObjectIdentifier getOID() { -+ return mOID; -+ } -+ -+ /** -+ * Return the type of the GeneralName. -+ */ -+ public int getType() { -+ return (GeneralNameInterface.NAME_ANY); -+ } -+ -+ /** -+ * Encode the IPAddress name into the DerOutputStream. -+ * -+ * @param out the DER stream to encode the IPAddressName to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ //encoding the attributes -+ tmp.putOID(mOID); -+ DerOutputStream tmp1 = new DerOutputStream(); -+ tmp1.write(mData); -+ tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, -+ (byte) 0x80), tmp1); -+ -+ out.write(DerValue.tag_SequenceOf, tmp); -+ } -+ -+ public void decode(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ decodeThis(val); -+ } -+ -+ // Decode this extension value -+ private void decodeThis(DerValue derVal) throws IOException { -+ -+ // if (derVal.tag != DerValue.tag_Sequence) { -+ // throw new IOException("Invalid encoding for other name"); -+ // } -+ -+ // Decode all the Attributes -+ mOID = derVal.data.getOID(); -+ // skip tag -+ DerValue tag = derVal.data.getDerValue(); -+ // read data -+ DerValue data = tag.data.getDerValue(); -+ mData = data.toByteArray(); -+ } -+ -+ public byte[] getValue() { -+ return mData; -+ } -+ -+ /** -+ * Return a printable string of IPaddress -+ */ -+ public String toString() { -+ if (mData != null) { -+ try { -+ DerValue data = new DerValue(mData); -+ if (data.tag == DerValue.tag_PrintableString) { -+ return "OtherName: (PrintableString)" + mOID + "," + data.getPrintableString(); -+ } else if (data.tag == DerValue.tag_IA5String) { -+ return "OtherName: (IA5String)" + mOID + "," + data.getIA5String(); -+ } else if (data.tag == DerValue.tag_BMPString) { -+ return "OtherName: (BMPString)" + mOID + "," + data.getIA5String(); -+ } else if (data.tag == DerValue.tag_UTF8String) { -+ return "OtherName: (UTF8String)" + mOID + "," + data.getUTF8String(); -+ } else { -+ return "OtherName: (Any)" + mOID + "," + toStr(data.toByteArray()); -+ } -+ } catch (IOException e) { -+ -+ return "OtherName: (Any)" + mOID + "," + toStr(mData); -+ } -+ } else { -+ return "OtherName: "; -+ } -+ } -+ -+ public String toStr(byte data[]) { -+ StringBuffer b = new StringBuffer(); -+ for (int i = 0; i < data.length; i++) { -+ if ((data[i] & 0xff) < 16) { -+ b.append("0"); -+ } -+ b.append(Integer.toString((data[i] & 0xff), 0x10)); -+ } -+ return b.toString(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/PKIXExtensions.java b/org/mozilla/jss/netscape/security/x509/PKIXExtensions.java -new file mode 100644 -index 00000000..61dc9c8e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/PKIXExtensions.java -@@ -0,0 +1,185 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * Lists all the object identifiers of the X509 extensions of the PKIX profile. -+ * -+ *

-+ * Extensions are addiitonal attributes which can be inserted in a X509 v3 certificate. For example a -+ * "Driving License Certificate" could have the driving license number as a extension. -+ * -+ *

-+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating -+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding -+ * of the extension value). -+ * -+ * @see Extension -+ * -+ * @version 1.4 -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public class PKIXExtensions { -+ // The object identifiers -+ private static final int AuthorityKey_data[] = { 2, 5, 29, 35 }; -+ private static final int SubjectKey_data[] = { 2, 5, 29, 14 }; -+ private static final int KeyUsage_data[] = { 2, 5, 29, 15 }; -+ private static final int PrivateKeyUsage_data[] = { 2, 5, 29, 16 }; -+ private static final int CertificatePolicies_data[] = { 2, 5, 29, 32 }; -+ private static final int PolicyMappings_data[] = { 2, 5, 29, 33 }; -+ private static final int SubjectAlternativeName_data[] = { 2, 5, 29, 17 }; -+ private static final int IssuerAlternativeName_data[] = { 2, 5, 29, 18 }; -+ private static final int SubjectDirectoryAttributes_data[] = { 2, 5, 29, 9 }; -+ private static final int BasicConstraints_data[] = { 2, 5, 29, 19 }; -+ private static final int NameConstraints_data[] = { 2, 5, 29, 30 }; -+ private static final int PolicyConstraints_data[] = { 2, 5, 29, 36 }; -+ private static final int CRLDistributionPoints_data[] = { 2, 5, 29, 31 }; -+ private static final int CRLNumber_data[] = { 2, 5, 29, 20 }; -+ private static final int IssuingDistributionPoint_data[] = { 2, 5, 29, 28 }; -+ private static final int DeltaCRLIndicator_data[] = { 2, 5, 29, 27 }; -+ private static final int ReasonCode_data[] = { 2, 5, 29, 21 }; -+ private static final int HoldInstructionCode_data[] = { 2, 5, 29, 23 }; -+ private static final int InvalidityDate_data[] = { 2, 5, 29, 24 }; -+ private static final int CertificateIssuer_data[] = { 2, 5, 29, 29 }; -+ private static final int FreshestCRL_data[] = { 2, 5, 29, 46 }; -+ -+ /** -+ * Identifies the particular public key used to sign the certificate. -+ */ -+ public static final ObjectIdentifier AuthorityKey_Id = new ObjectIdentifier(AuthorityKey_data); -+ -+ /** -+ * Identifies the particular public key used in an application. -+ */ -+ public static final ObjectIdentifier SubjectKey_Id = new ObjectIdentifier(SubjectKey_data); -+ -+ /** -+ * Defines the purpose of the key contained in the certificate. -+ */ -+ public static final ObjectIdentifier KeyUsage_Id = new ObjectIdentifier(KeyUsage_data); -+ -+ /** -+ * Allows the certificate issuer to specify a different validity period -+ * for the private key than the certificate. -+ */ -+ public static final ObjectIdentifier PrivateKeyUsage_Id = new ObjectIdentifier(PrivateKeyUsage_data); -+ -+ /** -+ * Contains the sequence of policy information terms. -+ */ -+ public static final ObjectIdentifier CertificatePolicies_Id = new ObjectIdentifier(CertificatePolicies_data); -+ -+ /** -+ * Lists pairs of objectidentifiers of policies considered equivalent by the -+ * issuing CA to the subject CA. -+ */ -+ public static final ObjectIdentifier PolicyMappings_Id = new ObjectIdentifier(PolicyMappings_data); -+ -+ /** -+ * Allows additional identities to be bound to the subject of the certificate. -+ */ -+ public static final ObjectIdentifier SubjectAlternativeName_Id = new ObjectIdentifier(SubjectAlternativeName_data); -+ -+ /** -+ * Allows additional identities to be associated with the certificate issuer. -+ */ -+ public static final ObjectIdentifier IssuerAlternativeName_Id = -+ new ObjectIdentifier(IssuerAlternativeName_data); -+ -+ /** -+ * Identifies additional directory attributes. -+ * This extension is always non-critical. -+ */ -+ public static final ObjectIdentifier SubjectDirectoryAttributes_Id = new ObjectIdentifier( -+ SubjectDirectoryAttributes_data); -+ -+ /** -+ * Identifies whether the subject of the certificate is a CA and how deep -+ * a certification path may exist through that CA. -+ */ -+ public static final ObjectIdentifier BasicConstraints_Id = -+ new ObjectIdentifier(BasicConstraints_data); -+ -+ /** -+ * Provides for permitted and excluded subtrees that place restrictions -+ * on names that may be included within a certificate issued by a given CA. -+ */ -+ public static final ObjectIdentifier NameConstraints_Id = new ObjectIdentifier(NameConstraints_data); -+ -+ /** -+ * Used to either prohibit policy mapping or limit the set of policies -+ * that can be in subsequent certificates. -+ */ -+ public static final ObjectIdentifier PolicyConstraints_Id = new ObjectIdentifier(PolicyConstraints_data); -+ -+ /** -+ * Identifies how CRL information is obtained. -+ */ -+ public static final ObjectIdentifier CRLDistributionPoints_Id = new ObjectIdentifier(CRLDistributionPoints_data); -+ -+ /** -+ * Conveys a monotonically increasing sequence number for each CRL -+ * issued by a given CA. -+ */ -+ public static final ObjectIdentifier CRLNumber_Id = new ObjectIdentifier(CRLNumber_data); -+ -+ /** -+ * Identifies the CRL distribution point for a particular CRL. -+ */ -+ public static final ObjectIdentifier IssuingDistributionPoint_Id = new ObjectIdentifier( -+ IssuingDistributionPoint_data); -+ -+ /** -+ * Identifies the delta CRL. -+ */ -+ public static final ObjectIdentifier DeltaCRLIndicator_Id = new ObjectIdentifier(DeltaCRLIndicator_data); -+ -+ /** -+ * Identifies the reason for the certificate revocation. -+ */ -+ public static final ObjectIdentifier ReasonCode_Id = new ObjectIdentifier(ReasonCode_data); -+ -+ /** -+ * This extension provides a registered instruction identifier indicating -+ * the action to be taken, after encountering a certificate that has been -+ * placed on hold. -+ */ -+ public static final ObjectIdentifier HoldInstructionCode_Id = new ObjectIdentifier(HoldInstructionCode_data); -+ -+ /** -+ * Identifies the date on which it is known or suspected that the private -+ * key was compromised or that the certificate otherwise became invalid. -+ */ -+ public static final ObjectIdentifier InvalidityDate_Id = new ObjectIdentifier(InvalidityDate_data); -+ -+ /** -+ * Identifies the date on which it is known or suspected that the private -+ * key was compromised or that the certificate otherwise became invalid. -+ */ -+ public static final ObjectIdentifier CertificateIssuer_Id = new ObjectIdentifier(CertificateIssuer_data); -+ -+ /** -+ * Identifies how delta CRL information is obtained. -+ */ -+ public static final ObjectIdentifier FreshestCRL_Id = new ObjectIdentifier(FreshestCRL_data); -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/PolicyConstraint.java b/org/mozilla/jss/netscape/security/x509/PolicyConstraint.java -new file mode 100644 -index 00000000..e7f2c1dd ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/PolicyConstraint.java -@@ -0,0 +1,136 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the PolicyConstraint ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.4 -+ */ -+public class PolicyConstraint { -+ private static final byte TAG_SET = 0; -+ private static final byte TAG_REQUIRE = 1; -+ private static final byte TAG_INHIBIT = 2; -+ -+ private CertificatePolicySet set = null; -+ private int require = -1; -+ private int inhibit = -1; -+ -+ /** -+ * The default constructor for this object -+ * -+ * @param set the CertificatePolicySet (null for optional). -+ * @param require require explicit policy (-1 for optional). -+ * @param inhibit inhibit policy mapping (-1 for optional). -+ */ -+ public PolicyConstraint(CertificatePolicySet set, int require, int inhibit) { -+ this.set = set; -+ this.require = require; -+ this.inhibit = inhibit; -+ } -+ -+ /** -+ * Create the PolicyConstraint from the DerValue. -+ * -+ * @param val the DerValue of the PolicyConstraint. -+ * @exception IOException on decoding errors. -+ */ -+ public PolicyConstraint(DerValue val) throws IOException { -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Sequence tag missing for PolicyConstraint."); -+ } -+ DerInputStream in = val.data; -+ while (in != null && in.available() != 0) { -+ DerValue next = in.getDerValue(); -+ switch (next.tag & 0x1f) { -+ case TAG_SET: -+ this.set = new CertificatePolicySet(next.data); -+ break; -+ -+ case TAG_REQUIRE: -+ next = next.data.getDerValue(); -+ this.require = (next.getInteger()).toInt(); -+ break; -+ -+ case TAG_INHIBIT: -+ next = next.data.getDerValue(); -+ this.inhibit = (next.getInteger()).toInt(); -+ break; -+ -+ default: -+ throw new IOException("Invalid tag option for PolicyConstraint."); -+ } -+ } -+ } -+ -+ /** -+ * Return user readable form of the object. -+ */ -+ public String toString() { -+ String s = ((set != null) ? -+ "PolicyConstraint: [\n" -+ + " PolicySet:[" + set.toString() + "]\n" -+ + " Require:" + require + "\n" -+ + " Inhibit:" + inhibit + "\n" -+ + "]\n" : -+ "PolicyConstraint: [\n" -+ + " PolicySet:[null]\n" -+ + " Require:" + require + "\n" -+ + " Inhibit:" + inhibit + "\n" -+ + "]\n"); -+ return (s); -+ } -+ -+ /** -+ * Encode the object to the output stream. -+ * -+ * @param out the DerOutputStream to encode the object to. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tagged = new DerOutputStream(); -+ -+ if (set != null) { -+ DerOutputStream tmp = new DerOutputStream(); -+ set.encode(tmp); -+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, TAG_SET), tmp); -+ } -+ if (require != -1) { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putInteger(new BigInt(require)); -+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, TAG_REQUIRE), tmp); -+ } -+ if (inhibit != -1) { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putInteger(new BigInt(inhibit)); -+ tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT, -+ true, TAG_INHIBIT), tmp); -+ } -+ out.write(DerValue.tag_Sequence, tagged); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/PolicyConstraintsExtension.java b/org/mozilla/jss/netscape/security/x509/PolicyConstraintsExtension.java -new file mode 100644 -index 00000000..8146e712 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/PolicyConstraintsExtension.java -@@ -0,0 +1,307 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the certificate extension which specifies the -+ * Policy constraints. -+ *

-+ * The policy constraints extension can be used in certificates issued to CAs. The policy constraints extension -+ * constrains path validation in two ways. It can be used to prohibit policy mapping or require that each certificate in -+ * a path contain an acceptable policy identifier. -+ *

-+ * The ASN.1 syntax for this is (IMPLICIT tagging is defined in the module definition): -+ * -+ *

-+ * PolicyConstraints ::= SEQUENCE {
-+ *     requireExplicitPolicy [0] SkipCerts OPTIONAL,
-+ *     inhibitPolicyMapping  [1] SkipCerts OPTIONAL
-+ * }
-+ * SkipCerts ::= INTEGER (0..MAX)
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.9 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class PolicyConstraintsExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -3723759691127622370L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions.PolicyConstraints"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "PolicyConstraints"; -+ public static final String REQUIRE = "require"; -+ public static final String INHIBIT = "inhibit"; -+ -+ private static final byte TAG_REQUIRE = 0; -+ private static final byte TAG_INHIBIT = 1; -+ -+ private int require = -1; -+ private int inhibit = -1; -+ -+ // Encode this extension value. -+ private void encodeThis() throws IOException { -+ try (DerOutputStream seq = new DerOutputStream()) { -+ DerOutputStream tagged = new DerOutputStream(); -+ -+ if (require != -1) { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putInteger(new BigInt(require)); -+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_REQUIRE), tmp); -+ } -+ if (inhibit != -1) { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putInteger(new BigInt(inhibit)); -+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_INHIBIT), tmp); -+ } -+ seq.write(DerValue.tag_Sequence, tagged); -+ extensionValue = seq.toByteArray(); -+ } -+ } -+ -+ /** -+ * Create a PolicyConstraintsExtension object with criticality and -+ * both require explicit policy and inhibit policy mapping. -+ * -+ * @param critical whether this extension should be critical -+ * @param require require explicit policy (-1 for optional). -+ * @param inhibit inhibit policy mapping (-1 for optional). -+ */ -+ public PolicyConstraintsExtension(boolean crit, int require, int inhibit) -+ throws IOException { -+ init(crit, require, inhibit); -+ } -+ -+ /** -+ * Create a PolicyConstraintsExtension object with both -+ * require explicit policy and inhibit policy mapping. -+ * -+ * @param require require explicit policy (-1 for optional). -+ * @param inhibit inhibit policy mapping (-1 for optional). -+ */ -+ public PolicyConstraintsExtension(int require, int inhibit) -+ throws IOException { -+ init(false, require, inhibit); -+ } -+ -+ private void init(boolean crit, int require, int inhibit) -+ throws IOException { -+ this.require = require; -+ this.inhibit = inhibit; -+ this.extensionId = PKIXExtensions.PolicyConstraints_Id; -+ this.critical = crit; -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from its DER encoded value and criticality. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public PolicyConstraintsExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.PolicyConstraints_Id; -+ this.critical = critical.booleanValue(); -+ -+ if (!(value instanceof byte[])) -+ throw new IOException("Illegal argument type"); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ System.arraycopy(value, 0, extValue, 0, len); -+ -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Sequence tag missing for PolicyConstraint."); -+ } -+ DerInputStream in = val.data; -+ while (in != null && in.available() != 0) { -+ DerValue next = in.getDerValue(); -+ -+ if (next.isContextSpecific(TAG_REQUIRE) && !next.isConstructed()) { -+ if (this.require != -1) -+ throw new IOException("Duplicate requireExplicitPolicy" + -+ "found in the PolicyConstraintsExtension"); -+ next.resetTag(DerValue.tag_Integer); -+ this.require = (next.getInteger()).toInt(); -+ -+ } else if (next.isContextSpecific(TAG_INHIBIT) && -+ !next.isConstructed()) { -+ if (this.inhibit != -1) -+ throw new IOException("Duplicate inhibitPolicyMapping" + -+ "found in the PolicyConstraintsExtension"); -+ next.resetTag(DerValue.tag_Integer); -+ this.inhibit = (next.getInteger()).toInt(); -+ } else -+ throw new IOException("Invalid encoding of PolicyConstraint"); -+ } -+ } -+ -+ /** -+ * Return the extension as user readable string. -+ */ -+ public String toString() { -+ String s; -+ s = super.toString() + "PolicyConstraints: [" + " Require: "; -+ if (require == -1) -+ s += "unspecified;"; -+ else -+ s += require + ";"; -+ s += "\tInhibit: "; -+ if (inhibit == -1) -+ s += "unspecified"; -+ else -+ s += inhibit; -+ s += " ]\n"; -+ return s; -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ extensionId = PKIXExtensions.PolicyConstraints_Id; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (!(obj instanceof Integer)) { -+ throw new IOException("Attribute value should be of type Integer."); -+ } -+ if (name.equalsIgnoreCase(REQUIRE)) { -+ require = ((Integer) obj).intValue(); -+ } else if (name.equalsIgnoreCase(INHIBIT)) { -+ inhibit = ((Integer) obj).intValue(); -+ } else { -+ throw new IOException("Attribute name " + "[" + name + "]" + -+ " not recognized by " + -+ "CertAttrSet:PolicyConstraints."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(REQUIRE)) { -+ return Integer.valueOf(require); -+ } else if (name.equalsIgnoreCase(INHIBIT)) { -+ return Integer.valueOf(inhibit); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:PolicyConstraints."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(REQUIRE)) { -+ require = -1; -+ } else if (name.equalsIgnoreCase(INHIBIT)) { -+ inhibit = -1; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:PolicyConstraints."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(REQUIRE); -+ elements.addElement(INHIBIT); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ /** -+ * returns the requireExplicitMapping parameter. -+ */ -+ public int getRequireExplicitMapping() { -+ return require; -+ } -+ -+ /** -+ * returns the inhibitPolicyMapping parameter. -+ */ -+ public int getInhibitPolicyMapping() { -+ return inhibit; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/PolicyMappingsExtension.java b/org/mozilla/jss/netscape/security/x509/PolicyMappingsExtension.java -new file mode 100644 -index 00000000..b15d7c40 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/PolicyMappingsExtension.java -@@ -0,0 +1,259 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the Policy Mappings Extension. -+ * -+ * This extension, if present, identifies the certificate policies considered -+ * identical between the issuing and the subject CA. -+ *

-+ * Extensions are addiitonal attributes which can be inserted in a X509 v3 certificate. For example a -+ * "Driving License Certificate" could have the driving license number as a extension. -+ * -+ *

-+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating -+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding -+ * of the extension value). -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.7 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class PolicyMappingsExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -4023336164621135851L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions.PolicyMappings"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "PolicyMappings"; -+ public static final String MAP = "map"; -+ -+ // Private data members -+ private Vector maps = null; -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ try (DerOutputStream os = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ for (int i = 0; i < maps.size(); i++) { -+ maps.elementAt(i).encode(tmp); -+ } -+ os.write(DerValue.tag_Sequence, tmp); -+ extensionValue = os.toByteArray(); -+ } -+ } -+ -+ /** -+ * Create a PolicyMappings with the Vector of CertificatePolicyMap. -+ * -+ * @param maps the Vector of CertificatePolicyMap. -+ */ -+ public PolicyMappingsExtension(Vector map) throws IOException { -+ init(false, map); -+ } -+ -+ /** -+ * Create a PolicyMappings with the Vector of CertificatePolicyMap. -+ * -+ * @param maps the Vector of CertificatePolicyMap. -+ */ -+ public PolicyMappingsExtension(boolean critical, Vector map) -+ throws IOException { -+ init(critical, map); -+ } -+ -+ /** -+ * init policy with criticality and map. -+ */ -+ private void init(boolean critical, Vector map) throws IOException { -+ this.maps = map; -+ this.extensionId = PKIXExtensions.PolicyMappings_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a default PolicyMappingsExtension. -+ */ -+ public PolicyMappingsExtension() { -+ extensionId = PKIXExtensions.PolicyMappings_Id; -+ critical = false; -+ maps = new Vector(1, 1); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public PolicyMappingsExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.PolicyMappings_Id; -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for " + -+ "PolicyMappingsExtension."); -+ } -+ maps = new Vector(1, 1); -+ while (val.data.available() != 0) { -+ DerValue seq = val.data.getDerValue(); -+ CertificatePolicyMap map = new CertificatePolicyMap(seq); -+ maps.addElement(map); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the policy map. -+ */ -+ public String toString() { -+ if (maps == null) -+ return ""; -+ String s = super.toString() + "PolicyMappings [\n" -+ + maps.toString() + "]\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ extensionId = PKIXExtensions.PolicyMappings_Id; -+ critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ @SuppressWarnings("unchecked") -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (name.equalsIgnoreCase(MAP)) { -+ if (!(obj instanceof Vector)) { -+ throw new IOException("Attribute value should be of" + -+ " type Vector."); -+ } -+ maps = (Vector) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:PolicyMappingsExtension."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(MAP)) { -+ return (maps); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:PolicyMappingsExtension."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(MAP)) { -+ maps = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:PolicyMappingsExtension."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(MAP); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ /** -+ * Returns an enumeration of the mappings in the extension. -+ */ -+ public Enumeration getMappings() { -+ if (maps == null) -+ return null; -+ return maps.elements(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/PolicyQualifierInfo.java b/org/mozilla/jss/netscape/security/x509/PolicyQualifierInfo.java -new file mode 100644 -index 00000000..bb3c30cf ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/PolicyQualifierInfo.java -@@ -0,0 +1,118 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * Represent the PolicyQualifierInfo. -+ * -+ * policyQualifierInfo ::= SEQUENCE { -+ * policyQualifierId PolicyQualifierId -+ * qualifier ANY DEFINED BY policyQualifierId -+ * } -+ * -+ * @author Thomas Kwan -+ */ -+public class PolicyQualifierInfo implements java.io.Serializable { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -2930016944517192379L; -+ public static final int OID_CPS[] = { 1, 3, 6, 1, 5, 5, 7, 2, 1 }; -+ public static final ObjectIdentifier QT_CPS = new -+ ObjectIdentifier(OID_CPS); -+ -+ public static final int OID_UNOTICE[] = { 1, 3, 6, 1, 5, 5, 7, 2, 2 }; -+ public static final ObjectIdentifier QT_UNOTICE = new -+ ObjectIdentifier(OID_UNOTICE); -+ -+ private ObjectIdentifier mId = null; -+ private Qualifier mQualifier = null; -+ -+ /** -+ * Create a PolicyQualifierInfo -+ * -+ * @param id the ObjectIdentifier for the policy id. -+ */ -+ public PolicyQualifierInfo(ObjectIdentifier id, Qualifier qualifier) { -+ mId = id; -+ mQualifier = qualifier; -+ } -+ -+ /** -+ * Create the object from its Der encoded value. -+ * -+ * @param val the DER encoded value for the same. -+ */ -+ public PolicyQualifierInfo(DerValue val) throws IOException { -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for PolicyQualifierInfo."); -+ } -+ DerValue did = val.data.getDerValue(); -+ mId = did.getOID(); -+ if (val.data.available() != 0) { -+ DerValue qualifier = val.data.getDerValue(); -+ if (qualifier.tag == DerValue.tag_IA5String) { -+ mQualifier = new CPSuri(qualifier); -+ } else { -+ mQualifier = new UserNotice(qualifier); -+ } -+ } -+ } -+ -+ public ObjectIdentifier getId() { -+ return mId; -+ } -+ -+ /** -+ * Returns object of type CPSuri or UserNotice. -+ */ -+ public Qualifier getQualifier() { -+ return mQualifier; -+ } -+ -+ /** -+ * Returns a printable representation of the CertificatePolicyId. -+ */ -+ public String toString() { -+ String s = "PolicyQualifierInfo: ["; -+ s = s + getId() + " " + getQualifier(); -+ s = s + "]\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Write the PolicyQualifier to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putOID(mId); -+ mQualifier.encode(tmp); -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/PolicyQualifiers.java b/org/mozilla/jss/netscape/security/x509/PolicyQualifiers.java -new file mode 100644 -index 00000000..3c15a1d3 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/PolicyQualifiers.java -@@ -0,0 +1,107 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the PolicyQualifiers. -+ * -+ * policyQualifiers ::= SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo -+ * -+ * @author Thomas Kwan -+ */ -+public class PolicyQualifiers implements java.io.Serializable { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 6932694408774694516L; -+ private Vector mInfo = new Vector(); -+ -+ /** -+ * Create a PolicyQualifiers with the ObjectIdentifier. -+ * -+ * @param id the ObjectIdentifier for the policy id. -+ */ -+ public PolicyQualifiers() { -+ } -+ -+ /** -+ * Create the object from its Der encoded value. -+ * -+ * @param val the DER encoded value for the same. -+ */ -+ public PolicyQualifiers(DerValue val) throws IOException { -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for " + "PolicyQualifiers."); -+ } -+ while (val.data.available() != 0) { -+ DerValue pq = val.data.getDerValue(); -+ PolicyQualifierInfo info = new PolicyQualifierInfo(pq); -+ add(info); -+ } -+ } -+ -+ public void add(PolicyQualifierInfo info) { -+ mInfo.addElement(info); -+ } -+ -+ public int size() { -+ return mInfo.size(); -+ } -+ -+ public PolicyQualifierInfo getInfoAt(int i) { -+ return mInfo.elementAt(i); -+ } -+ -+ /** -+ * Returns a printable representation of the CertificatePolicyId. -+ */ -+ public String toString() { -+ StringBuffer s = new StringBuffer("PolicyQualifiers: ["); -+ for (int i = 0; i < mInfo.size(); i++) { -+ PolicyQualifierInfo pq = mInfo.elementAt(i); -+ s.append(pq.toString()); -+ } -+ s.append("]\n"); -+ -+ return s.toString(); -+ } -+ -+ /** -+ * Write the PolicyQualifiers to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ for (int i = 0; i < mInfo.size(); i++) { -+ PolicyQualifierInfo pq = mInfo.elementAt(i); -+ pq.encode(tmp); -+ } -+ -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/PrintableConverter.java b/org/mozilla/jss/netscape/security/x509/PrintableConverter.java -new file mode 100644 -index 00000000..4d52df45 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/PrintableConverter.java -@@ -0,0 +1,114 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.nio.ByteBuffer; -+import java.nio.CharBuffer; -+import java.nio.charset.CharacterCodingException; -+import java.nio.charset.CharsetEncoder; -+ -+import org.mozilla.jss.netscape.security.util.ASN1CharStrConvMap; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * A AVAValueConverter that converts a Printable String attribute to a DerValue -+ * and vice versa. An example an attribute that is a printable string is "C". -+ * -+ * @see ASN1CharStrConvMap -+ * @see AVAValueConverter -+ * -+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc. -+ */ -+ -+public class PrintableConverter implements AVAValueConverter { -+ // public constructors. -+ -+ public PrintableConverter() { -+ } -+ -+ /** -+ * Converts a string with ASN.1 Printable characters to a DerValue. -+ * -+ * @param valueString a string with Printable characters. -+ * -+ * @return a DerValue. -+ * -+ * @exception IOException if a Printable encoder is not -+ * available for the conversion. -+ */ -+ public DerValue getValue(String valueString) -+ throws IOException { -+ return getValue(valueString, null); -+ } -+ -+ public DerValue getValue(String valueString, byte[] tags) throws IOException { -+ try { -+ CharsetEncoder encoder = ASN1CharStrConvMap.getDefault().getEncoder(DerValue.tag_PrintableString); -+ if (encoder == null) -+ throw new IOException("No encoder for printable"); -+ -+ CharBuffer charBuffer = CharBuffer.wrap(valueString.toCharArray()); -+ ByteBuffer byteBuffer = encoder.encode(charBuffer); -+ -+ return new DerValue(DerValue.tag_PrintableString, -+ byteBuffer.array(), byteBuffer.arrayOffset(), byteBuffer.limit()); -+ -+ } catch (CharacterCodingException e) { -+ throw new IllegalArgumentException("Invalid Printable String AVA Value", e); -+ } -+ } -+ -+ /** -+ * Converts a BER encoded value of PrintableString to a DER encoded value. -+ * Checks if the BER encoded value is a PrintableString. -+ * NOTE only DER encoded values are currently accepted on input. -+ * -+ * @param berStream A byte array of the BER encoded value. -+ * -+ * @return A DerValue. -+ * -+ * @exception IOException if the BER value cannot be converted to a -+ * PrintableString DER value. -+ */ -+ public DerValue getValue(byte[] berStream) -+ throws IOException { -+ DerValue value = new DerValue(berStream); -+ if (value.tag != DerValue.tag_PrintableString) -+ throw new IOException("Invalid Printable String AVA Value"); -+ return value; -+ } -+ -+ /** -+ * Converts a DerValue of PrintableString to a java string with -+ * PrintableString characters. -+ * -+ * @param avaValue a DerValue. -+ * -+ * @return a string with PrintableString characters. -+ * -+ * @exception IOException if the DerValue is not a PrintableString i.e. -+ * The DerValue cannot be converted to a string -+ * with PrintableString characters. -+ */ -+ public String getAsString(DerValue avaValue) -+ throws IOException { -+ return avaValue.getPrintableString(); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/PrivateKeyUsageExtension.java b/org/mozilla/jss/netscape/security/x509/PrivateKeyUsageExtension.java -new file mode 100644 -index 00000000..a14630c7 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/PrivateKeyUsageExtension.java -@@ -0,0 +1,340 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.security.cert.CertificateException; -+import java.security.cert.CertificateExpiredException; -+import java.security.cert.CertificateNotYetValidException; -+import java.security.cert.CertificateParsingException; -+import java.util.Date; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the Private Key Usage Extension. -+ * -+ *

-+ * The Private Key Usage Period extension allows the certificate issuer to specify a different validity period for the -+ * private key than the certificate. This extension is intended for use with digital signature keys. This extension -+ * consists of two optional components notBefore and notAfter. The private key associated with the certificate should -+ * not be used to sign objects before or after the times specified by the two components, respectively. -+ * -+ *

-+ * PrivateKeyUsagePeriod ::= SEQUENCE {
-+ *     notBefore  [0]  GeneralizedTime OPTIONAL,
-+ *     notAfter   [1]  GeneralizedTime OPTIONAL }
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.12 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class PrivateKeyUsageExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -7623695233957629936L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info.extensions.PrivateKeyUsage"; -+ /** -+ * Sub attributes name for this CertAttrSet. -+ */ -+ public static final String NAME = "PrivateKeyUsage"; -+ public static final String NOT_BEFORE = "not_before"; -+ public static final String NOT_AFTER = "not_after"; -+ -+ // Private data members -+ private static final byte TAG_BEFORE = 0; -+ private static final byte TAG_AFTER = 1; -+ -+ private Date notBefore; -+ private Date notAfter; -+ -+ // Encode this extension value. -+ private void encodeThis() throws IOException { -+ try (DerOutputStream seq = new DerOutputStream()) { -+ -+ DerOutputStream tagged = new DerOutputStream(); -+ if (notBefore != null) { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putGeneralizedTime(notBefore); -+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_BEFORE), tmp); -+ } -+ if (notAfter != null) { -+ DerOutputStream tmp = new DerOutputStream(); -+ tmp.putGeneralizedTime(notAfter); -+ tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, -+ false, TAG_AFTER), tmp); -+ } -+ seq.write(DerValue.tag_Sequence, tagged); -+ extensionValue = seq.toByteArray(); -+ } -+ } -+ -+ /** -+ * The default constructor for PrivateKeyUsageExtension. -+ * -+ * @param notBefore the date/time before which the private key -+ * should not be used. -+ * @param notAfter the date/time after which the private key -+ * should not be used. -+ */ -+ public PrivateKeyUsageExtension(Date notBefore, Date notAfter) -+ throws IOException { -+ this.notBefore = notBefore; -+ this.notAfter = notAfter; -+ -+ this.extensionId = PKIXExtensions.PrivateKeyUsage_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * -+ * @exception CertificateException on certificate parsing errors. -+ * @exception IOException on error. -+ */ -+ public PrivateKeyUsageExtension(Boolean critical, Object value) -+ throws CertificateException, IOException { -+ this.extensionId = PKIXExtensions.PrivateKeyUsage_Id; -+ this.critical = critical.booleanValue(); -+ -+ if (!(value instanceof byte[])) -+ throw new CertificateException("Illegal argument type"); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ System.arraycopy(value, 0, extValue, 0, len); -+ -+ this.extensionValue = extValue; -+ DerInputStream str = new DerInputStream(extValue); -+ DerValue[] seq = str.getSequence(2); -+ -+ // NB. this is always encoded with the IMPLICIT tag -+ // The checks only make sense if we assume implicit tagging, -+ // with explicit tagging the form is always constructed. -+ for (int i = 0; i < seq.length; i++) { -+ DerValue opt = seq[i]; -+ -+ if (opt.isContextSpecific(TAG_BEFORE) && -+ !opt.isConstructed()) { -+ if (notBefore != null) { -+ throw new CertificateParsingException( -+ "Duplicate notBefore in PrivateKeyUsage."); -+ } -+ opt.resetTag(DerValue.tag_GeneralizedTime); -+ str = new DerInputStream(opt.toByteArray()); -+ notBefore = str.getGeneralizedTime(); -+ -+ } else if (opt.isContextSpecific(TAG_AFTER) && -+ !opt.isConstructed()) { -+ if (notAfter != null) { -+ throw new CertificateParsingException( -+ "Duplicate notAfter in PrivateKeyUsage."); -+ } -+ opt.resetTag(DerValue.tag_GeneralizedTime); -+ str = new DerInputStream(opt.toByteArray()); -+ notAfter = str.getGeneralizedTime(); -+ } else -+ throw new IOException("Invalid encoding of " + -+ "PrivateKeyUsageExtension"); -+ } -+ } -+ -+ /** -+ * Return the printable string. -+ */ -+ public String toString() { -+ return (super.toString() + -+ "PrivateKeyUsage: [From: " + -+ ((notBefore == null) ? "" : notBefore.toString()) + -+ ", To: " + -+ ((notAfter == null) ? "" : notAfter.toString()) + "]\n"); -+ } -+ -+ /** -+ * Return notBefore date -+ */ -+ public Date getNotBefore() { -+ return (notBefore); -+ } -+ -+ /** -+ * Return notAfter date -+ */ -+ public Date getNotAfter() { -+ return (notAfter); -+ } -+ -+ /** -+ * Verify that that the current time is within the validity period. -+ * -+ * @exception CertificateExpiredException if the certificate has expired. -+ * @exception CertificateNotYetValidException if the certificate is not -+ * yet valid. -+ */ -+ public void valid() -+ throws CertificateNotYetValidException, CertificateExpiredException { -+ Date now = new Date(); -+ valid(now); -+ } -+ -+ /** -+ * Verify that that the passed time is within the validity period. -+ * -+ * @exception CertificateExpiredException if the certificate has expired -+ * with respect to the Date supplied. -+ * @exception CertificateNotYetValidException if the certificate is not -+ * yet valid with respect to the Date supplied. -+ * -+ */ -+ public void valid(Date now) -+ throws CertificateNotYetValidException, CertificateExpiredException { -+ /* -+ * we use the internal Dates rather than the passed in Date -+ * because someone could override the Date methods after() -+ * and before() to do something entirely different. -+ */ -+ if (notBefore.after(now)) { -+ throw new CertificateNotYetValidException("NotBefore: " + -+ notBefore.toString()); -+ } -+ if (notAfter.before(now)) { -+ throw new CertificateExpiredException("NotAfter: " + -+ notAfter.toString()); -+ } -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ extensionId = PKIXExtensions.PrivateKeyUsage_Id; -+ critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception CertificateException on decoding errors. -+ */ -+ public void decode(InputStream in) throws CertificateException { -+ throw new CertificateException("Method not to be called directly."); -+ } -+ -+ /** -+ * Set the attribute value. -+ * -+ * @exception CertificateException on attribute handling errors. -+ */ -+ public void set(String name, Object obj) -+ throws CertificateException { -+ clearValue(); -+ if (!(obj instanceof Date)) { -+ throw new CertificateException("Attribute must be of type Date."); -+ } -+ if (name.equalsIgnoreCase(NOT_BEFORE)) { -+ notBefore = (Date) obj; -+ } else if (name.equalsIgnoreCase(NOT_AFTER)) { -+ notAfter = (Date) obj; -+ } else { -+ throw new CertificateException("Attribute name not recognized by" -+ + " CertAttrSet:PrivateKeyUsage."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ * -+ * @exception CertificateException on attribute handling errors. -+ */ -+ public Object get(String name) throws CertificateException { -+ if (name.equalsIgnoreCase(NOT_BEFORE)) { -+ return (new Date(notBefore.getTime())); -+ } else if (name.equalsIgnoreCase(NOT_AFTER)) { -+ return (new Date(notAfter.getTime())); -+ } else { -+ throw new CertificateException("Attribute name not recognized by" -+ + " CertAttrSet:PrivateKeyUsage."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ * -+ * @exception CertificateException on attribute handling errors. -+ */ -+ public void delete(String name) throws CertificateException { -+ if (name.equalsIgnoreCase(NOT_BEFORE)) { -+ notBefore = null; -+ } else if (name.equalsIgnoreCase(NOT_AFTER)) { -+ notAfter = null; -+ } else { -+ throw new CertificateException("Attribute name not recognized by" -+ + " CertAttrSet:PrivateKeyUsage."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(NOT_BEFORE); -+ elements.addElement(NOT_AFTER); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/Qualifier.java b/org/mozilla/jss/netscape/security/x509/Qualifier.java -new file mode 100644 -index 00000000..353983ea ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/Qualifier.java -@@ -0,0 +1,63 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the Qualifier. -+ * -+ * Qualifier ::= CHOICE { -+ * cPRuri CPSuri, -+ * userNotice UserNotice -+ * } -+ * -+ * @author Thomas Kwan -+ */ -+public class Qualifier implements java.io.Serializable { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 2214531407387992974L; -+ -+ /** -+ * Create a PolicyQualifierInfo -+ * -+ * @param id the ObjectIdentifier for the policy id. -+ */ -+ public Qualifier() { -+ } -+ -+ public Qualifier(DerValue val) throws IOException { -+ // needs to override this -+ } -+ -+ /** -+ * Write the PolicyQualifier to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ // needs to override this -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/RDN.java b/org/mozilla/jss/netscape/security/x509/RDN.java -new file mode 100644 -index 00000000..ceb8872a ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/RDN.java -@@ -0,0 +1,304 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.util.Arrays; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * RDNs are a set of {attribute = value} assertions. Some of those -+ * attributes are "distinguished" (unique w/in context). Order is -+ * never relevant. -+ * -+ * Some X.500 names include only a single distinguished attribute -+ * per RDN. This style is currently common. -+ * -+ * Note that DER-encoded RDNs sort AVAs by assertion OID ... so that -+ * when we parse this data we don't have to worry about canonicalizing -+ * it, but we'll need to sort them when we expose the RDN class more. -+ * -+ * @see X500Name -+ * @see AVA -+ * @see LdapDNStrConverter -+ */ -+ -+public class RDN { -+ // public constructors -+ -+ /** -+ * Constructs a RDN from a Ldap DN String with one RDN component -+ * using the global default LdapDNStrConverter. -+ * -+ * @see LdapDNStrConverter -+ * @param rdnString a Ldap DN string with one RDN component, e.g. as -+ * defined in RFC1779. -+ * @exception IOException if error occurs while parsing the string. -+ */ -+ public RDN(String rdnString) -+ throws IOException { -+ RDN rdn = LdapDNStrConverter.getDefault().parseRDN(rdnString); -+ assertion = rdn.getAssertion(); -+ } -+ -+ /** -+ * Like RDN(String) with a DER encoding order given as argument for -+ * Directory Strings. -+ */ -+ public RDN(String rdnString, byte[] tags) -+ throws IOException { -+ RDN rdn = LdapDNStrConverter.getDefault().parseRDN(rdnString, tags); -+ assertion = rdn.getAssertion(); -+ } -+ -+ /** -+ * Constructs a RDN from a Ldap DN string with one RDN component -+ * using the specified Ldap DN Str converter. -+ * For example, RFC1779StrConverter can be passed to parse a Ldap -+ * DN string in RFC1779 format. -+ * -+ * @see LdapDNStrConverter -+ * @param rdnString Ldap DN string. -+ * @param ldapDNStrConverter a LdapDNStrConverter. -+ */ -+ public RDN(String rdnString, LdapDNStrConverter ldapDNStrConverter) -+ throws IOException { -+ RDN rdn = ldapDNStrConverter.parseRDN(rdnString); -+ assertion = rdn.getAssertion(); -+ } -+ -+ /** -+ * Constructs a RDN from a DerValue. -+ * -+ * @param set Der value of a set of AVAs. -+ */ -+ public RDN(DerValue set) throws IOException { -+ if (set.tag != DerValue.tag_Set) -+ throw new CertParseError("X500 RDN"); -+ -+ int j_max = 50; // XXX j_max = f(data)!! -+ int j; -+ int i; -+ -+ AVA[] avas = new AVA[j_max]; -+ -+ // create a temporary array big enough for a huge set of AVA's -+ for (j = 0; j < j_max; j++) { -+ avas[j] = new AVA(set.data); -+ if (set.data.available() == 0) -+ break; -+ } -+ -+ // copy the elements into it -+ if (j >= j_max - 1) { -+ assertion = new AVA[j + 1]; -+ } else { -+ assertion = new AVA[j + 1]; -+ for (i = 0; i < (j + 1); i++) { -+ assertion[i] = avas[i]; -+ } -+ } -+ -+ /* -+ if (set.data.available () != 0) -+ // throw new CertParseError ("X500 RDN 2"); -+ System.out.println (" ... RDN parse, ignored bytes = " -+ + set.data.available ()); -+ */ -+ } -+ -+ /** -+ * Constructs a RDN from a Der Input Stream. -+ * -+ * @param in a Der Input Stream. -+ */ -+ public RDN(DerInputStream in) throws IOException { -+ /* an RDN is a SET of avas */ -+ DerValue avaset[] = in.getSet(1); -+ int i; -+ assertion = new AVA[avaset.length]; -+ for (i = 0; i < assertion.length; i++) -+ assertion[i] = new AVA(avaset[i].data); -+ } -+ -+ /** -+ * Constructs a RDN from an array of AVA. -+ * -+ * @param avas a AVA Array. -+ */ -+ public RDN(AVA avas[]) { -+ assertion = avas.clone(); -+ } -+ -+ /** -+ * convenience method. -+ */ -+ public RDN(Vector avaVector) { -+ int size = avaVector.size(); -+ assertion = new AVA[size]; -+ for (int i = 0; i < size; i++) { -+ assertion[i] = avaVector.elementAt(i); -+ } -+ } -+ -+ /** -+ * returns an array of AVA in the RDN. -+ * -+ * @return array of AVA in this RDN. -+ */ -+ public AVA[] getAssertion() { -+ return assertion.clone(); -+ } -+ -+ /** -+ * returns the number of AVAs in the RDN. -+ * -+ * @return number of AVAs in this RDN. -+ */ -+ public int getAssertionLength() { -+ return assertion.length; -+ } -+ -+ private AVA assertion[]; -+ -+ private class AVAEnumerator implements Enumeration { -+ private int index; -+ -+ public AVAEnumerator() { -+ index = 0; -+ } -+ -+ public boolean hasMoreElements() { -+ return (index < assertion.length); -+ } -+ -+ public AVA nextElement() { -+ if (index >= assertion.length) -+ return null; -+ return assertion[index++]; -+ } -+ } -+ -+ // other public methods. -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + Arrays.hashCode(assertion); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (obj == null) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ RDN other = (RDN) obj; -+ if (!Arrays.equals(assertion, other.assertion)) -+ return false; -+ return true; -+ } -+ -+ DerValue findAttribute(ObjectIdentifier oid) { -+ int i; -+ -+ for (i = 0; i < assertion.length; i++) -+ if (assertion[i].oid.equals(oid)) -+ return assertion[i].value; -+ return null; -+ } -+ -+ /** -+ * Encodes this RDN to a Der output stream. -+ * -+ * @param out the Der Output Stream. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ int i; -+ -+ for (i = 0; i < assertion.length; i++) -+ assertion[i].encode(tmp); -+ out.write(DerValue.tag_Set, tmp); -+ } -+ -+ /** -+ * returns an enumeration of AVAs that make up this RDN. -+ * -+ * @return an enumeration of AVAs that make up this RDN. -+ */ -+ public Enumeration getAVAs() { -+ return new AVAEnumerator(); -+ } -+ -+ /** -+ * Returns a Ldap DN string with one RDN component using the -+ * global default LdapDNStrConverter. -+ * -+ * @see LdapDNStrConverter -+ * @return the Ldap DN String of this RDN. -+ * @exception IOException if an error occurs during the conversion. -+ */ -+ public String toLdapDNString() -+ throws IOException { -+ return LdapDNStrConverter.getDefault().encodeRDN(this); -+ } -+ -+ /** -+ * Returns a Ldap DN String with this RDN component using the specified -+ * LdapDNStrConverter. -+ * -+ * @see LdapDNStrConverter -+ * @param ldapDNStrConverter a LdapDNStrConverter. -+ * @return a Ldap DN String. -+ * @exception IOException if an error occurs in the conversion. -+ */ -+ public String toLdapDNString(LdapDNStrConverter ldapDNStrConverter) -+ throws IOException { -+ return ldapDNStrConverter.encodeRDN(this); -+ } -+ -+ /** -+ * Returns a Ldap DN string with this RDN component using the global -+ * default LdapDNStrConverter. -+ * -+ * @see LdapDNStrConverter -+ * @return the Ldap DN String with this RDN component, null if an error -+ * occurs in the conversion. -+ */ -+ public String toString() { -+ String s; -+ try { -+ s = toLdapDNString(); -+ } catch (IOException e) { -+ return null; -+ } -+ return s; -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/RFC1779StrConverter.java b/org/mozilla/jss/netscape/security/x509/RFC1779StrConverter.java -new file mode 100644 -index 00000000..1919270e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/RFC1779StrConverter.java -@@ -0,0 +1,102 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * Converts a RFC 1779 string to a X500Name, RDN or AVA object and vice versa. -+ * -+ * @see LdapDNStrConverter -+ * @see LdapV3DNStrConverter -+ * -+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc. -+ */ -+ -+public class RFC1779StrConverter extends LdapV3DNStrConverter { -+ // -+ // Constructors. -+ // -+ -+ /** -+ * Constructs a RFC1779StrConverter using the global default -+ * X500NameAttrMap and accepts OIDs not listed in the attribute map. -+ */ -+ public RFC1779StrConverter() { -+ super(); -+ } -+ -+ /** -+ * Constructs a RFC1779StrConverter using the specified X500NameAttrMap -+ * and boolean for whether to accept OIDs not in the X500NameAttrMap. -+ * -+ * @param attributeMap A X500NameAttrMap to use for this converter. -+ * @param doAcceptUnknownOids Accept unregistered attributes, i.e. OIDs -+ * not in the map). -+ */ -+ public RFC1779StrConverter(X500NameAttrMap attributeMap, -+ boolean doAcceptUnknownOids) { -+ super(attributeMap, doAcceptUnknownOids); -+ } -+ -+ // -+ // overriding methods. -+ // -+ -+ /** -+ * Converts a OID to a attribute keyword in a Ldap DN string or -+ * to a "OID.1.2.3.4" string syntax as defined in RFC1779. -+ * -+ * @param oid an ObjectIdentifier. -+ * -+ * @return a attribute keyword or "OID.1.2.3.4" string. -+ * -+ * @exception IOException if an error occurs during the conversion. -+ */ -+ public String encodeOID(ObjectIdentifier oid) -+ throws IOException { -+ String keyword = attrMap.getName(oid); -+ if (keyword == null) -+ if (!acceptUnknownOids) -+ throw new IllegalArgumentException("Unrecognized OID"); -+ else -+ keyword = "OID" + "." + oid.toString(); -+ return keyword; -+ } -+ -+ /** -+ * Converts a attribute value as a DerValue to a string in a -+ * RFC1779 Ldap DN string. -+ * -+ * @param attrValue an attribute value. -+ * @param oid ObjectIdentifier for the attribute. -+ * @return a string in RFC1779 syntax. -+ * @exception IOException if an error occurs during the conversion. -+ */ -+ public String encodeValue(DerValue attrValue, ObjectIdentifier oid) -+ throws IOException { -+ String s = super.encodeValue(attrValue, oid); -+ if (s.indexOf('\n') != -1) -+ return "\"" + s + "\""; -+ else -+ return s; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/RFC822Name.java b/org/mozilla/jss/netscape/security/x509/RFC822Name.java -new file mode 100644 -index 00000000..e33ff330 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/RFC822Name.java -@@ -0,0 +1,85 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class implements the RFC822Name as required by the GeneralNames -+ * ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.3 -+ * @see GeneralName -+ * @see GeneralNames -+ * @see GeneralNameInterface -+ */ -+public class RFC822Name implements GeneralNameInterface { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -1453025303548809007L; -+ private String name; -+ -+ /** -+ * Create the RFC822Name object from the passed encoded Der value. -+ * -+ * @param derValue the encoded DER RFC822Name. -+ * @exception IOException on error. -+ */ -+ public RFC822Name(DerValue derValue) throws IOException { -+ name = derValue.getIA5String(); -+ } -+ -+ /** -+ * Create the RFC822Name object with the specified name. -+ * -+ * @param name the RFC822Name. -+ */ -+ public RFC822Name(String name) { -+ this.name = name; -+ } -+ -+ /** -+ * Return the type of the GeneralName. -+ */ -+ public int getType() { -+ return (GeneralNameInterface.NAME_RFC822); -+ } -+ -+ /** -+ * Encode the RFC822 name into the DerOutputStream. -+ * -+ * @param out the DER stream to encode the RFC822Name to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putIA5String(name); -+ } -+ -+ /** -+ * Convert the name into user readable string. -+ */ -+ public String toString() { -+ return ("RFC822Name: " + name); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/ReasonFlags.java b/org/mozilla/jss/netscape/security/x509/ReasonFlags.java -new file mode 100755 -index 00000000..d1e93e84 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/ReasonFlags.java -@@ -0,0 +1,283 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.BitArray; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the CRL Reason Flags. -+ * -+ *

-+ * This extension, if present, defines the identifies the reason for the certificate revocation. -+ * -+ * @author Hemma Prafullchandra -+ * @version 1.3 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class ReasonFlags { -+ -+ /** -+ * Reasons -+ */ -+ public static final String UNUSED = "unused"; -+ public static final String KEY_COMPROMISE = "key_compromise"; -+ public static final String CA_COMPROMISE = "ca_compromise"; -+ public static final String AFFLIATION_CHANGED = "affliation_changed"; -+ public static final String SUPERSEDED = "superseded"; -+ public static final String CESSATION_OF_OPERATION = "cessation_of_operation"; -+ public static final String CERTIFICATION_HOLD = "certification_hold"; -+ public static final String PRIVILEGE_WITHDRAWN = "privilege_withdrawn"; -+ public static final String AA_COMPROMISE = "aa_compromise"; -+ -+ // Private data members -+ private boolean[] bitString; -+ -+ /** -+ * Check if bit is set. -+ * -+ * @param position the position in the bit string to check. -+ */ -+ private boolean isSet(int position) { -+ return bitString[position]; -+ } -+ -+ /** -+ * Set the bit at the specified position. -+ */ -+ private void set(int position, boolean val) { -+ // enlarge bitString if necessary -+ if (position >= bitString.length) { -+ boolean[] tmp = new boolean[position + 1]; -+ System.arraycopy(bitString, 0, tmp, 0, bitString.length); -+ bitString = tmp; -+ } -+ bitString[position] = val; -+ } -+ -+ /** -+ * Create a ReasonFlags with the passed bit settings. -+ * -+ * @param reasons the bits to be set for the ReasonFlags. -+ */ -+ public ReasonFlags(byte[] reasons) { -+ bitString = new BitArray(reasons.length * 8, reasons).toBooleanArray(); -+ } -+ -+ /** -+ * Create a ReasonFlags with the passed bit settings. -+ * -+ * @param reasons the bits to be set for the ReasonFlags. -+ */ -+ public ReasonFlags(boolean[] reasons) { -+ this.bitString = reasons; -+ } -+ -+ /** -+ * Create a ReasonFlags with the passed bit settings. -+ * -+ * @param reasons the bits to be set for the ReasonFlags. -+ */ -+ public ReasonFlags(BitArray reasons) { -+ this.bitString = reasons.toBooleanArray(); -+ } -+ -+ /** -+ * Create the object from the passed DER encoded value. -+ * -+ * @param in the DerInputStream to read the ReasonFlags from. -+ * @exception IOException on decoding errors. -+ */ -+ public ReasonFlags(DerInputStream in) throws IOException { -+ DerValue derVal = in.getDerValue(); -+ this.bitString = derVal.getUnalignedBitString(true).toBooleanArray(); -+ } -+ -+ /** -+ * Create the object from the passed DER encoded value. -+ * -+ * @param derVal the DerValue decoded from the stream. -+ * @exception IOException on decoding errors. -+ */ -+ public ReasonFlags(DerValue derVal) throws IOException { -+ this.bitString = derVal.getUnalignedBitString(true).toBooleanArray(); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ if (!(obj instanceof Boolean)) { -+ throw new IOException("Attribute must be of type Boolean."); -+ } -+ boolean val = ((Boolean) obj).booleanValue(); -+ if (name.equalsIgnoreCase(UNUSED)) { -+ set(0, val); -+ } else if (name.equalsIgnoreCase(KEY_COMPROMISE)) { -+ set(1, val); -+ } else if (name.equalsIgnoreCase(CA_COMPROMISE)) { -+ set(2, val); -+ } else if (name.equalsIgnoreCase(AFFLIATION_CHANGED)) { -+ set(3, val); -+ } else if (name.equalsIgnoreCase(SUPERSEDED)) { -+ set(4, val); -+ } else if (name.equalsIgnoreCase(CESSATION_OF_OPERATION)) { -+ set(5, val); -+ } else if (name.equalsIgnoreCase(CERTIFICATION_HOLD)) { -+ set(6, val); -+ } else if (name.equalsIgnoreCase(PRIVILEGE_WITHDRAWN)) { -+ set(7, val); -+ } else if (name.equalsIgnoreCase(AA_COMPROMISE)) { -+ set(8, val); -+ } else { -+ throw new IOException("Name not recognized by ReasonFlags"); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(UNUSED)) { -+ return Boolean.valueOf(isSet(0)); -+ } else if (name.equalsIgnoreCase(KEY_COMPROMISE)) { -+ return Boolean.valueOf(isSet(1)); -+ } else if (name.equalsIgnoreCase(CA_COMPROMISE)) { -+ return Boolean.valueOf(isSet(2)); -+ } else if (name.equalsIgnoreCase(AFFLIATION_CHANGED)) { -+ return Boolean.valueOf(isSet(3)); -+ } else if (name.equalsIgnoreCase(SUPERSEDED)) { -+ return Boolean.valueOf(isSet(4)); -+ } else if (name.equalsIgnoreCase(CESSATION_OF_OPERATION)) { -+ return Boolean.valueOf(isSet(5)); -+ } else if (name.equalsIgnoreCase(CERTIFICATION_HOLD)) { -+ return Boolean.valueOf(isSet(6)); -+ } else if (name.equalsIgnoreCase(PRIVILEGE_WITHDRAWN)) { -+ return Boolean.valueOf(isSet(7)); -+ } else if (name.equalsIgnoreCase(AA_COMPROMISE)) { -+ return Boolean.valueOf(isSet(8)); -+ } else { -+ throw new IOException("Name not recognized by ReasonFlags"); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(UNUSED)) { -+ set(0, false); -+ } else if (name.equalsIgnoreCase(KEY_COMPROMISE)) { -+ set(1, false); -+ } else if (name.equalsIgnoreCase(CA_COMPROMISE)) { -+ set(2, false); -+ } else if (name.equalsIgnoreCase(AFFLIATION_CHANGED)) { -+ set(3, false); -+ } else if (name.equalsIgnoreCase(SUPERSEDED)) { -+ set(4, false); -+ } else if (name.equalsIgnoreCase(CESSATION_OF_OPERATION)) { -+ set(5, false); -+ } else if (name.equalsIgnoreCase(CERTIFICATION_HOLD)) { -+ set(6, false); -+ } else if (name.equalsIgnoreCase(PRIVILEGE_WITHDRAWN)) { -+ set(7, false); -+ } else if (name.equalsIgnoreCase(AA_COMPROMISE)) { -+ set(8, false); -+ } else { -+ throw new IOException("Name not recognized by ReasonFlags"); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the ReasonFlags. -+ */ -+ public String toString() { -+ String s = super.toString() + "Reason Flags [\n"; -+ -+ try { -+ if (isSet(0)) { -+ s += " Unused\n"; -+ } -+ if (isSet(1)) { -+ s += " Key Compromise\n"; -+ } -+ if (isSet(2)) { -+ s += " CA_Compromise\n"; -+ } -+ if (isSet(3)) { -+ s += " Affiliation_Changed\n"; -+ } -+ if (isSet(4)) { -+ s += " Superseded\n"; -+ } -+ if (isSet(5)) { -+ s += " Cessation Of Operation\n"; -+ } -+ if (isSet(6)) { -+ s += " Certificate Hold\n"; -+ } -+ if (isSet(7)) { -+ s += " Privilege Withdrawn\n"; -+ } -+ if (isSet(8)) { -+ s += " AA Compromise\n"; -+ } -+ } catch (ArrayIndexOutOfBoundsException ex) { -+ } -+ -+ s += "]\n"; -+ -+ return (s); -+ } -+ -+ /** -+ * Write the extension to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putUnalignedBitString(new BitArray(this.bitString)); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getElements() { -+ Vector elements = new Vector(); -+ elements.addElement(UNUSED); -+ elements.addElement(KEY_COMPROMISE); -+ elements.addElement(CA_COMPROMISE); -+ elements.addElement(AFFLIATION_CHANGED); -+ elements.addElement(SUPERSEDED); -+ elements.addElement(CESSATION_OF_OPERATION); -+ elements.addElement(CERTIFICATION_HOLD); -+ elements.addElement(PRIVILEGE_WITHDRAWN); -+ elements.addElement(AA_COMPROMISE); -+ -+ return (elements.elements()); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/RevocationReason.java b/org/mozilla/jss/netscape/security/x509/RevocationReason.java -new file mode 100644 -index 00000000..32eb3600 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/RevocationReason.java -@@ -0,0 +1,129 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.Serializable; -+import java.util.ArrayList; -+import java.util.Collection; -+import java.util.LinkedHashMap; -+import java.util.Map; -+ -+/** -+ * Represent the enumerated type used in CRLReason Extension of CRL entry. -+ * -+ * -+ * @author galperin -+ * @version $Revision$, $Date$ -+ */ -+ -+public final class RevocationReason implements Serializable { -+ private static final long serialVersionUID = -2582403666913588806L; -+ -+ public static final Collection INSTANCES = new ArrayList(); -+ public static final Map CODES = new LinkedHashMap(); -+ public static final Map LABELS = new LinkedHashMap(); -+ -+ /** -+ * Reasons -+ */ -+ public static final RevocationReason UNSPECIFIED = new RevocationReason(0, "Unspecified"); -+ public static final RevocationReason KEY_COMPROMISE = new RevocationReason(1, "Key_Compromise"); -+ public static final RevocationReason CA_COMPROMISE = new RevocationReason(2, "CA_Compromise"); -+ public static final RevocationReason AFFILIATION_CHANGED = new RevocationReason(3, "Affiliation_Changed"); -+ public static final RevocationReason SUPERSEDED = new RevocationReason(4, "Superseded"); -+ public static final RevocationReason CESSATION_OF_OPERATION = new RevocationReason(5, "Cessation_of_Operation"); -+ public static final RevocationReason CERTIFICATE_HOLD = new RevocationReason(6, "Certificate_Hold"); -+ public static final RevocationReason REMOVE_FROM_CRL = new RevocationReason(8, "Remove_from_CRL"); -+ public static final RevocationReason PRIVILEGE_WITHDRAWN = new RevocationReason(9, "Privilege_Withdrawn"); -+ public static final RevocationReason AA_COMPROMISE = new RevocationReason(10, "AA_Compromise"); -+ -+ // Private data members -+ private int code; -+ private String label; -+ -+ /** -+ * Create a RevocationReason with the passed integer value and string label. -+ * -+ * @param reason integer value of the enumeration alternative. -+ * @param label string value of the enumeration alternative. -+ */ -+ private RevocationReason(int reason, String label) { -+ this.code = reason; -+ this.label = label; -+ -+ INSTANCES.add(this); -+ CODES.put(reason, this); -+ LABELS.put(label.toLowerCase(), this); -+ } -+ -+ public int getCode() { -+ return code; -+ } -+ -+ public String getLabel() { -+ return label; -+ } -+ -+ public static RevocationReason fromInt(int reason) { -+ return valueOf(reason); -+ } -+ -+ public static RevocationReason valueOf(int reason) { -+ return CODES.get(reason); -+ } -+ -+ public static RevocationReason valueOf(String string) { -+ return LABELS.get(string.toLowerCase()); -+ } -+ -+ public int toInt() { -+ return code; -+ } -+ -+ public String toString() { -+ return label; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (obj == null) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ RevocationReason other = (RevocationReason) obj; -+ if (code != other.code) -+ return false; -+ if (label == null) { -+ if (other.label != null) -+ return false; -+ } else if (!label.equals(other.label)) -+ return false; -+ return true; -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + code; -+ result = prime * result + ((label == null) ? 0 : label.hashCode()); -+ return result; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/RevocationReasonAdapter.java b/org/mozilla/jss/netscape/security/x509/RevocationReasonAdapter.java -new file mode 100644 -index 00000000..b3d7d49c ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/RevocationReasonAdapter.java -@@ -0,0 +1,38 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import javax.xml.bind.annotation.adapters.XmlAdapter; -+ -+import org.apache.commons.lang.StringUtils; -+ -+/** -+ * The RevocationReasonAdapter class provides custom marshaling for RevocationReason. -+ * -+ * @author Endi S. Dewata -+ */ -+public class RevocationReasonAdapter extends XmlAdapter { -+ -+ public RevocationReason unmarshal(String value) throws Exception { -+ return StringUtils.isEmpty(value) ? null : RevocationReason.valueOf(value); -+ } -+ -+ public String marshal(RevocationReason value) throws Exception { -+ return value == null ? null : value.toString(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/RevokedCertImpl.java b/org/mozilla/jss/netscape/security/x509/RevokedCertImpl.java -new file mode 100755 -index 00000000..40bd630e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/RevokedCertImpl.java -@@ -0,0 +1,447 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.Serializable; -+import java.math.BigInteger; -+import java.security.cert.CRLException; -+import java.util.Date; -+import java.util.Enumeration; -+import java.util.LinkedHashSet; -+import java.util.Set; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ *

-+ * Abstract class for a revoked certificate in a CRL. This class is for each entry in the -+ * revokedCertificates, so it deals with the inner SEQUENCE. The ASN.1 definition for this is: -+ * -+ *

-+ * revokedCertificates    SEQUENCE OF SEQUENCE  {
-+ *     userCertificate    CertificateSerialNumber,
-+ *     revocationDate     ChoiceOfTime,
-+ *     crlEntryExtensions Extensions OPTIONAL
-+ *                        -- if present, must be v2
-+ * }  OPTIONAL
-+ *
-+ * CertificateSerialNumber  ::=  INTEGER
-+ *
-+ * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
-+ *
-+ * Extension  ::=  SEQUENCE  {
-+ *     extnId        OBJECT IDENTIFIER,
-+ *     critical      BOOLEAN DEFAULT FALSE,
-+ *     extnValue     OCTET STRING
-+ *                   -- contains a DER encoding of a value
-+ *                   -- of the type registered for use with
-+ *                   -- the extnId object identifier value
-+ * }
-+ * 
-+ * -+ * @author Hemma Prafullchandra -+ * @version 1.6 97/12/10 -+ */ -+ -+public class RevokedCertImpl extends RevokedCertificate implements Serializable { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -3449642360223397701L; -+ -+ private SerialNumber serialNumber; -+ private Date revocationDate; -+ private CRLExtensions extensions = null; -+ private byte[] revokedCert; -+ private final static boolean isExplicit = false; -+ -+ /** -+ * Default constructor. -+ */ -+ public RevokedCertImpl() { -+ } -+ -+ /** -+ * Constructs a revoked certificate entry using the serial number and -+ * revocation date. -+ * -+ * @param num -+ * the serial number of the revoked certificate. -+ * @param date -+ * the Date on which revocation took place. -+ */ -+ public RevokedCertImpl(BigInteger num, Date date) { -+ this.serialNumber = new SerialNumber(num); -+ this.revocationDate = date; -+ } -+ -+ /** -+ * Constructs a revoked certificate entry using the serial number, -+ * revocation date and the entry extensions. -+ * -+ * @param num -+ * the serial number of the revoked certificate. -+ * @param date -+ * the Date on which revocation took place. -+ * @param crlEntryExts -+ * the extensions for this entry. -+ */ -+ public RevokedCertImpl(BigInteger num, Date date, CRLExtensions crlEntryExts) { -+ this.serialNumber = new SerialNumber(num); -+ this.revocationDate = date; -+ this.extensions = crlEntryExts; -+ } -+ -+ public byte[] getEncoded() throws CRLException { -+ // XXX NOT IMPLEMENTED -+ if (revokedCert == null) { -+ DerOutputStream os = new DerOutputStream(); -+ try { -+ encode(os); -+ } catch (Exception e) { -+ // revokedCert = null; -+ } -+ revokedCert = os.toByteArray(); -+ } -+ return revokedCert; -+ } -+ -+ public boolean hasUnsupportedCriticalExtension() { -+ // XXX NOT IMPLEMENTED -+ return true; -+ } -+ -+ /** -+ * Sets extensions for this impl. -+ * -+ * @param crlEntryExts -+ * CRLExtensions -+ */ -+ public void setExtensions(CRLExtensions crlEntryExts) { -+ this.extensions = crlEntryExts; -+ } -+ -+ /** -+ * Unmarshals a revoked certificate from its encoded form. -+ * -+ * @param revokedCert -+ * the encoded bytes. -+ * @exception CRLException -+ * on parsing errors. -+ * @exception X509ExtensionException -+ * on extension handling errors. -+ */ -+ public RevokedCertImpl(byte[] revokedCert) throws CRLException, -+ X509ExtensionException { -+ try { -+ DerValue derValue = new DerValue(revokedCert); -+ parse(derValue); -+ } catch (IOException e) { -+ throw new CRLException("Parsing error: " + e.toString()); -+ } -+ } -+ -+ /** -+ * Unmarshals a revoked certificate from its encoded form. -+ * -+ * @param derValue -+ * the DER value containing the revoked certificate. -+ * @exception CRLException -+ * on parsing errors. -+ * @exception X509ExtensionException -+ * on extension handling errors. -+ */ -+ public RevokedCertImpl(DerValue derValue) throws CRLException, -+ X509ExtensionException { -+ parse(derValue); -+ } -+ -+ /** -+ * Returns true if this revoked certificate entry has extensions, otherwise -+ * false. -+ * -+ * @return true if this CRL entry has extensions, otherwise false. -+ */ -+ public boolean hasExtensions() { -+ if (extensions == null) -+ return false; -+ else -+ return true; -+ } -+ -+ /** -+ * Decode a revoked certificate from an input stream. -+ * -+ * @param inStrm -+ * an input stream holding at least one revoked certificate -+ * @exception CRLException -+ * on parsing errors. -+ * @exception X509ExtensionException -+ * on extension handling errors. -+ */ -+ public void decode(InputStream inStrm) throws CRLException, -+ X509ExtensionException { -+ try { -+ DerValue derValue = new DerValue(inStrm); -+ parse(derValue); -+ } catch (IOException e) { -+ throw new CRLException("Parsing error: " + e.toString()); -+ } -+ } -+ -+ /** -+ * Encodes the revoked certificate to an output stream. -+ * -+ * @param outStrm -+ * an output stream to which the encoded revoked certificate is -+ * written. -+ * @exception CRLException -+ * on encoding errors. -+ * @exception X509ExtensionException -+ * on extension handling errors. -+ */ -+ public void encode(DerOutputStream outStrm) throws CRLException, -+ X509ExtensionException { -+ try (DerOutputStream seq = new DerOutputStream()) { -+ if (revokedCert == null) { -+ DerOutputStream tmp = new DerOutputStream(); -+ // sequence { serialNumber, revocationDate, extensions } -+ serialNumber.encode(tmp); -+ -+ // from 2050 should encode GeneralizedTime -+ tmp.putUTCTime(revocationDate); -+ -+ if (extensions != null) -+ extensions.encode(tmp, isExplicit); -+ -+ seq.write(DerValue.tag_Sequence, tmp); -+ -+ revokedCert = seq.toByteArray(); -+ } -+ outStrm.write(revokedCert); -+ } catch (IOException e) { -+ throw new CRLException("Encoding error: " + e.toString()); -+ } -+ } -+ -+ /** -+ * Gets the serial number for this RevokedCertificate, the userCertificate. -+ * -+ * @return the serial number. -+ */ -+ public BigInteger getSerialNumber() { -+ return serialNumber.getNumber().toBigInteger(); -+ } -+ -+ /** -+ * Gets the revocation date for this RevokedCertificate, the revocationDate. -+ * -+ * @return the revocation date. -+ */ -+ public Date getRevocationDate() { -+ return (new Date(revocationDate.getTime())); -+ } -+ -+ /** -+ * Returns extensions for this impl. -+ * -+ * @return the CRLExtensions -+ */ -+ public CRLExtensions getExtensions() { -+ return extensions; -+ } -+ -+ /** -+ * Returns a printable string of this revoked certificate. -+ * -+ * @return value of this revoked certificate in a printable form. -+ */ -+ public String toString() { -+ StringBuffer sb = new StringBuffer(serialNumber.toString() + " On: " + revocationDate.toString()); -+ -+ if (extensions != null) { -+ sb.append("\n"); -+ for (int i = 0; i < extensions.size(); i++) -+ sb.append("Entry Extension[" + i + "]: " -+ + (extensions.elementAt(i)).toString()); -+ } -+ sb.append("\n"); -+ return (sb.toString()); -+ } -+ -+ /** -+ * Gets a Set of the extension(s) marked CRITICAL in the -+ * RevokedCertificate by OID strings. -+ * -+ * @return a set of the extension oid strings in the -+ * Object that are marked critical. -+ */ -+ public Set getCriticalExtensionOIDs() { -+ if (extensions == null) -+ return null; -+ Set extSet = new LinkedHashSet(); -+ Extension ex; -+ for (Enumeration e = extensions.getElements(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ if (ex.isCritical()) -+ extSet.add(ex.getExtensionId().toString()); -+ } -+ return extSet; -+ } -+ -+ /** -+ * Gets a Set of the extension(s) marked NON-CRITICAL in the -+ * RevokedCertificate by OID strings. -+ * -+ * @return a set of the extension oid strings in the -+ * Object that are marked critical. -+ */ -+ public Set getNonCriticalExtensionOIDs() { -+ if (extensions == null) -+ return null; -+ Set extSet = new LinkedHashSet(); -+ Extension ex; -+ for (Enumeration e = extensions.getElements(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ if (!ex.isCritical()) -+ extSet.add(ex.getExtensionId().toString()); -+ } -+ return extSet; -+ } -+ -+ /** -+ * Gets the DER encoded OCTET string for the extension value -+ * (extnValue) identified by the passed in oid String. -+ * The oid string is -+ * represented by a set of positive whole number separated -+ * by ".", that means,
-+ * <positive whole number>.<positive whole number>.<positive -+ * whole number>.<...> -+ * -+ * @param oid the Object Identifier value for the extension. -+ * @return the DER encoded octet string of the extension value. -+ */ -+ public byte[] getExtensionValue(String oid) { -+ if (extensions == null) -+ return null; -+ try (DerOutputStream out = new DerOutputStream()) { -+ String extAlias = OIDMap.getName(new ObjectIdentifier(oid)); -+ Extension crlExt = null; -+ -+ if (extAlias == null) { // may be unknown -+ ObjectIdentifier findOID = new ObjectIdentifier(oid); -+ Extension ex = null; -+ ObjectIdentifier inCertOID; -+ for (Enumeration e = extensions.getElements(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ inCertOID = ex.getExtensionId(); -+ if (inCertOID.equals(findOID)) { -+ crlExt = ex; -+ break; -+ } -+ } -+ } else -+ crlExt = extensions.get(extAlias); -+ if (crlExt == null) -+ return null; -+ byte[] extData = crlExt.getExtensionValue(); -+ if (extData == null) -+ return null; -+ -+ out.putOctetString(extData); -+ return out.toByteArray(); -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ private void parse(DerValue derVal) -+ throws CRLException, X509ExtensionException { -+ -+ if (derVal.tag != DerValue.tag_Sequence) { -+ throw new CRLException("Invalid encoded RevokedCertificate, " + -+ "starting sequence tag missing."); -+ } -+ if (derVal.data.available() == 0) -+ throw new CRLException("No data encoded for RevokedCertificates"); -+ -+ // serial number -+ try { -+ DerInputStream in = derVal.toDerInputStream(); -+ DerValue val = in.getDerValue(); -+ this.serialNumber = new SerialNumber(val); -+ } catch (IOException e) { -+ throw new CRLException("Parsing Serial Number error: " -+ + e.toString()); -+ } -+ -+ // revocationDate -+ try { -+ int nextByte = derVal.data.peekByte(); -+ if ((byte) nextByte == DerValue.tag_UtcTime) { -+ this.revocationDate = derVal.data.getUTCTime(); -+ } else if ((byte) nextByte == DerValue.tag_GeneralizedTime) { -+ this.revocationDate = derVal.data.getGeneralizedTime(); -+ } else { -+ throw new CRLException("Invalid encoding for RevokedCertificates"); -+ } -+ } catch (IOException e) { -+ throw new CRLException("Parsing Revocation Date error: " -+ + e.toString()); -+ } -+ -+ if (derVal.data.available() == 0) -+ return; // no extensions -+ -+ // crlEntryExtensions -+ try { -+ this.extensions = new CRLExtensions(derVal.toDerInputStream()); -+ } catch (IOException e) { -+ throw new CRLException("Parsing CRL Entry Extensions error: " -+ + e.toString()); -+ } -+ } -+ -+ /** -+ * Serialization write ... X.509 certificates serialize as themselves, and -+ * they're parsed when they get read back. (Actually they serialize as some -+ * type data from the serialization subsystem, then the cert data.) -+ */ -+ private void writeObject(ObjectOutputStream stream) throws CRLException, X509ExtensionException, IOException { -+ DerOutputStream dos = new DerOutputStream(); -+ encode(dos); -+ dos.derEncode(stream); -+ } -+ -+ /** -+ * Serialization read ... X.509 certificates serialize as themselves, and -+ * they're parsed when they get read back. -+ */ -+ private void readObject(ObjectInputStream stream) throws CRLException, X509ExtensionException, IOException { -+ decode(stream); -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/RevokedCertificate.java b/org/mozilla/jss/netscape/security/x509/RevokedCertificate.java -new file mode 100644 -index 00000000..a08ee3c6 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/RevokedCertificate.java -@@ -0,0 +1,95 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.math.BigInteger; -+import java.security.cert.X509CRL; -+import java.security.cert.X509CRLEntry; -+import java.util.Date; -+ -+/** -+ *

-+ * Abstract class for a revoked certificate in a CRL (Certificate Revocation List). -+ * -+ * The ASN.1 definition for revokedCertificates is: -+ * -+ *

-+ *  revokedCertificates    SEQUENCE OF SEQUENCE  {
-+ *      userCertificate    CertificateSerialNumber,
-+ *      revocationDate     ChoiceOfTime,
-+ *      crlEntryExtensions Extensions OPTIONAL
-+ *                         -- if present, must be v2
-+ *  }  OPTIONAL
-+ * 

-+ * CertificateSerialNumber ::= INTEGER -+ *

-+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension -+ *

-+ * Extension ::= SEQUENCE { -+ * extnId OBJECT IDENTIFIER, -+ * critical BOOLEAN DEFAULT FALSE, -+ * extnValue OCTET STRING -+ * -- contains a DER encoding of a value -+ * -- of the type registered for use with -+ * -- the extnId object identifier value -+ * } -+ *

-+ * -+ * @see X509CRL -+ * -+ * @author Hemma Prafullchandra -+ * @version 1.4 97/12/10 -+ */ -+ -+public abstract class RevokedCertificate extends X509CRLEntry { -+ /* implements X509Extension { */ -+ -+ /** -+ * Gets the serial number for this RevokedCertificate, -+ * the userCertificate. -+ * -+ * @return the serial number. -+ */ -+ public abstract BigInteger getSerialNumber(); -+ -+ /** -+ * Gets the revocation date for this RevokedCertificate, -+ * the revocationDate. -+ * -+ * @return the revocation date. -+ */ -+ public abstract Date getRevocationDate(); -+ -+ /** -+ * Returns true if this revoked certificate entry has -+ * extensions. -+ * -+ * @return true if this entry has extensions, false otherwise. -+ */ -+ public abstract boolean hasExtensions(); -+ -+ /** -+ * Returns a string representation of this revoked certificate. -+ * -+ * @return a string representation of this revoked certificate. -+ */ -+ public abstract String toString(); -+ -+ public abstract CRLExtensions getExtensions(); -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/SerialNumber.java b/org/mozilla/jss/netscape/security/x509/SerialNumber.java -new file mode 100644 -index 00000000..368b510a ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/SerialNumber.java -@@ -0,0 +1,127 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.Serializable; -+import java.math.BigInteger; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the SerialNumber class used by certificates. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.5 -+ */ -+public class SerialNumber implements Serializable { -+ -+ private static final long serialVersionUID = 1600956411497203535L; -+ private BigInt serialNum; -+ -+ // Construct the class from the DerValue -+ private void construct(DerValue derVal) throws IOException { -+ serialNum = derVal.getInteger(); -+ if (derVal.data.available() != 0) { -+ throw new IOException("Excess SerialNumber data"); -+ } -+ } -+ -+ /** -+ * The default constructor for this class using BigInteger. -+ * -+ * @param num the BigInteger number used to create the serial number. -+ */ -+ public SerialNumber(BigInteger num) { -+ serialNum = new BigInt(num); -+ } -+ -+ public SerialNumber(BigInt num) { -+ serialNum = num; -+ } -+ -+ /** -+ * The default constructor for this class using int. -+ * -+ * @param num the BigInteger number used to create the serial number. -+ */ -+ public SerialNumber(int num) { -+ serialNum = new BigInt(num); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the SerialNumber from. -+ * @exception IOException on decoding errors. -+ */ -+ public SerialNumber(DerInputStream in) throws IOException { -+ DerValue derVal = in.getDerValue(); -+ construct(derVal); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DerValue. -+ * -+ * @param val the DerValue to read the SerialNumber from. -+ * @exception IOException on decoding errors. -+ */ -+ public SerialNumber(DerValue val) throws IOException { -+ construct(val); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed stream. -+ * -+ * @param in the InputStream to read the SerialNumber from. -+ * @exception IOException on decoding errors. -+ */ -+ public SerialNumber(InputStream in) throws IOException { -+ DerValue derVal = new DerValue(in); -+ construct(derVal); -+ } -+ -+ /** -+ * Return the SerialNumber as user readable string. -+ */ -+ public String toString() { -+ return ("SerialNumber: [" + serialNum.toString() + "]"); -+ } -+ -+ /** -+ * Encode the SerialNumber in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putInteger(serialNum); -+ } -+ -+ /** -+ * Return the serial number. -+ */ -+ public BigInt getNumber() { -+ return (serialNum); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/SubjectAlternativeNameExtension.java b/org/mozilla/jss/netscape/security/x509/SubjectAlternativeNameExtension.java -new file mode 100644 -index 00000000..37ee3492 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/SubjectAlternativeNameExtension.java -@@ -0,0 +1,257 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This represents the Subject Alternative Name Extension. -+ * -+ * This extension, if present, allows the subject to specify multiple -+ * alternative names. -+ * -+ *

-+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating -+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding -+ * of the extension value). -+ *

-+ * The ASN.1 syntax for this is: -+ * -+ *

-+ * SubjectAltName ::= GeneralNames
-+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-+ * 
-+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.9 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class SubjectAlternativeNameExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -4022446008355607196L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = -+ "x509.info.extensions.SubjectAlternativeName"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "SubjectAlternativeName"; -+ public static final String SUBJECT_NAME = "subject_name"; -+ -+ // private data members -+ GeneralNames names; -+ -+ // Encode this extension -+ private void encodeThis() throws IOException { -+ DerOutputStream os = new DerOutputStream(); -+ try { -+ names.encode(os); -+ } catch (GeneralNamesException e) { -+ throw new IOException("SubjectAlternativeName: " + e); -+ } -+ extensionValue = os.toByteArray(); -+ } -+ -+ /** -+ * Create a SubjectAlternativeNameExtension with the passed GeneralNames. -+ * -+ * @param names the GeneralNames for the subject. -+ * @exception IOException on error. -+ */ -+ public SubjectAlternativeNameExtension(boolean critical, GeneralNames names) -+ throws IOException { -+ this.names = names; -+ this.extensionId = PKIXExtensions.SubjectAlternativeName_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ public SubjectAlternativeNameExtension(GeneralNames names) -+ throws IOException { -+ this.names = names; -+ this.extensionId = PKIXExtensions.SubjectAlternativeName_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create a default SubjectAlternativeNameExtension. -+ */ -+ public SubjectAlternativeNameExtension() { -+ extensionId = PKIXExtensions.SubjectAlternativeName_Id; -+ critical = false; -+ names = new GeneralNames(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public SubjectAlternativeNameExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.SubjectAlternativeName_Id; -+ this.critical = critical.booleanValue(); -+ -+ if (!(value instanceof byte[])) -+ throw new IOException("SubjectAlternativeName: " -+ + "Illegal argument type"); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ System.arraycopy(value, 0, extValue, 0, len); -+ -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ try { -+ names = new GeneralNames(val); -+ } catch (GeneralNamesException e) { -+ throw new IOException("SubjectAlternativeName: " + e, e); -+ } -+ } -+ -+ /** -+ * Returns a printable representation of the SubjectAlternativeName. -+ */ -+ public String toString() { -+ if (names == null) -+ return ""; -+ String s = super.toString() + "SubjectAlternativeName [\n" -+ + names.toString() + "]\n"; -+ return (s); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ extensionId = PKIXExtensions.SubjectAlternativeName_Id; -+ //critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (name.equalsIgnoreCase(SUBJECT_NAME)) { -+ if (!(obj instanceof GeneralNames)) { -+ throw new IOException("Attribute value should be of " + -+ "type GeneralNames."); -+ } -+ names = (GeneralNames) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:SubjectAlternativeName."); -+ } -+ } -+ -+ /** -+ * Set the GeneralNames of this extension. -+ */ -+ public void setGeneralNames(GeneralNames names) { -+ clearValue(); -+ this.names = names; -+ } -+ -+ /** -+ * Get the GeneralNames of this extension. -+ */ -+ public GeneralNames getGeneralNames() { -+ return names; -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(SUBJECT_NAME)) { -+ return (names); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:SubjectAlternativeName."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(SUBJECT_NAME)) { -+ names = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:SubjectAlternativeName."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(SUBJECT_NAME); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/SubjectDirAttributesExtension.java b/org/mozilla/jss/netscape/security/x509/SubjectDirAttributesExtension.java -new file mode 100644 -index 00000000..fda86f87 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/SubjectDirAttributesExtension.java -@@ -0,0 +1,289 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class represents the Subject Directory Attributes Extension. -+ * -+ *

-+ * The subject directory attributes extension is not recommended as an essential part of this profile, but it may be -+ * used in local environments. This extension MUST be non-critical. -+ * -+ *

-+ * The ASN.1 syntax for this extension is:
-+ *
-+ *    SubjectDirectoryAttributes ::= SEQUENCE (1..MAX) OF Attribute
-+ *
-+ *    Attribute	::= SEQUENCE {
-+ * type		AttributeType,
-+ * 	value		SET OF AttributeValue
-+ *              	-- at least one value is required --}
-+ *
-+ *    AttributeType	::= OBJECT IDENTIFIER
-+ *
-+ *    AttributeValue	::= ANY
-+ *
-+ * 
-+ * -+ * @author Christine Ho -+ * @version 1.7 -+ * -+ * @see CertAttrSet -+ * @see Extension -+ */ -+public class SubjectDirAttributesExtension extends Extension -+ implements CertAttrSet { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -1215458115428197688L; -+ -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ //public static final String IDENT = "x509.info.extensions.SubjectDirectoryAttributes"; -+ public static final String IDENT = "Subject Directory Attributes"; -+ -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "SubjectDirectoryAttributes"; -+ -+ // Private data members -+ private Vector attrList = new Vector(); -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ try (DerOutputStream out = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ //encoding the attributes -+ Enumeration attrs = attrList.elements(); -+ while (attrs.hasMoreElements()) { -+ Attribute attr = attrs.nextElement(); -+ attr.encode(tmp); -+ } -+ -+ out.write(DerValue.tag_SequenceOf, tmp); -+ this.extensionValue = out.toByteArray(); -+ } -+ } -+ -+ // Decode this extension value -+ private void decodeThis(DerValue derVal) throws IOException { -+ -+ if (derVal.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for " + -+ "Subject Directory Attribute extension."); -+ } -+ -+ if (derVal.data.available() == 0) { -+ throw new IOException(NAME + " No data available in " -+ + "passed DER encoded value."); -+ } -+ -+ // Decode all the Attributes -+ while (derVal.data.available() != 0) { -+ DerValue encAttr = derVal.data.getDerValue(); -+ Attribute attr = new Attribute(encAttr); -+ attrList.addElement(attr); -+ } -+ } -+ -+ /** -+ * Default constructor for this object. -+ * -+ * @param derVal Der encoded value of this extension -+ */ -+ public SubjectDirAttributesExtension(DerValue derVal) throws IOException { -+ -+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id; -+ this.critical = false; -+ decodeThis(derVal); -+ } -+ -+ /** -+ * Default constructor for this object. -+ * -+ * @param list Attribute object list -+ */ -+ public SubjectDirAttributesExtension(Attribute[] list) throws IOException { -+ -+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id; -+ this.critical = false; -+ -+ if ((list == null) || (list.length == 0)) { -+ throw new IOException("No data available in " -+ + "passed Attribute List."); -+ } -+ -+ // add the Attributes -+ for (int i = 0; i < list.length; i++) { -+ attrList.addElement(list[i]); -+ } -+ } -+ -+ /** -+ * Constructor from parsing extension -+ * -+ * @param list Attribute object list -+ */ -+ public SubjectDirAttributesExtension(Boolean crit, Object value) -+ throws IOException { -+ -+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id; -+ this.critical = crit.booleanValue(); -+ -+ if (!(value instanceof byte[])) -+ throw new IOException(NAME + "Illegal argument type"); -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ System.arraycopy(value, 0, extValue, 0, len); -+ -+ this.extensionValue = extValue; -+ decodeThis(new DerValue(extValue)); -+ } -+ -+ /** -+ * Constructor for this object. -+ * -+ * @param list Attribute object list -+ * @param critical The criticality -+ */ -+ public SubjectDirAttributesExtension(Attribute[] list, boolean critical) -+ throws IOException { -+ -+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id; -+ this.critical = critical; -+ -+ if ((list == null) || (list.length == 0)) { -+ throw new IOException("No data available in " -+ + "passed Attribute List."); -+ } -+ -+ // add the Attributes -+ for (int i = 0; i < list.length; i++) { -+ attrList.addElement(list[i]); -+ } -+ } -+ -+ /** -+ * Return user readable form of extension. -+ */ -+ public String toString() { -+ -+ String s = super.toString() + "SubjectDirectoryAttributes:[\n"; -+ -+ Enumeration attrs = attrList.elements(); -+ StringBuffer tempBuffer = new StringBuffer(); -+ while (attrs.hasMoreElements()) { -+ Attribute attr = attrs.nextElement(); -+ tempBuffer.append(attr.toString()); -+ } -+ s += tempBuffer.toString(); -+ return (s + "]\n"); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ decodeThis(val); -+ } -+ -+ /** -+ * Encode this extension value to the output stream. -+ * -+ * @param out the DerOutputStream to encode the extension to. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ this.extensionId = PKIXExtensions.SubjectDirectoryAttributes_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:SubjectDirectoryAttributes."); -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:SubjectDirectoryAttributes."); -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:SubjectDirectoryAttributes."); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ /** -+ * Returns an enumeration of attributes in the extension. -+ */ -+ public Enumeration getAttributesList() { -+ if (attrList == null) -+ return null; -+ return attrList.elements(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/SubjectKeyIdentifierExtension.java b/org/mozilla/jss/netscape/security/x509/SubjectKeyIdentifierExtension.java -new file mode 100644 -index 00000000..6c367dbe ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/SubjectKeyIdentifierExtension.java -@@ -0,0 +1,222 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.lang.reflect.Array; -+import java.util.Enumeration; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the Subject Key Identifier Extension. -+ * -+ * This extension, if present, provides a means of identifying the particular -+ * public key used in an application. This extension by default is marked -+ * non-critical. -+ * -+ *

-+ * Extensions are addiitonal attributes which can be inserted in a X509 v3 certificate. For example a -+ * "Driving License Certificate" could have the driving license number as a extension. -+ * -+ *

-+ * Extensions are represented as a sequence of the extension identifier (Object Identifier), a boolean flag stating -+ * whether the extension is to be treated as being critical and the extension value itself (this is again a DER encoding -+ * of the extension value). -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.7 -+ * @see Extension -+ * @see CertAttrSet -+ */ -+public class SubjectKeyIdentifierExtension extends Extension -+ implements CertAttrSet { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 2457721262590880939L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = -+ "x509.info.extensions.SubjectKeyIdentifier"; -+ /** -+ * Attribute names. -+ */ -+ public static final String NAME = "SubjectKeyIdentifier"; -+ public static final String KEY_ID = "key_id"; -+ -+ // Private data member -+ private KeyIdentifier id; -+ -+ // Encode this extension value -+ private void encodeThis() throws IOException { -+ DerOutputStream os = new DerOutputStream(); -+ id.encode(os); -+ extensionValue = os.toByteArray(); -+ } -+ -+ /** -+ * Create a SubjectKeyIdentifierExtension with the passed octet string. -+ * The criticality is set to False. -+ * -+ * @param octetString the octet string identifying the key identifier. -+ */ -+ public SubjectKeyIdentifierExtension(boolean critical, byte[] octetString) -+ throws IOException { -+ id = new KeyIdentifier(octetString); -+ -+ this.extensionId = PKIXExtensions.SubjectKey_Id; -+ this.critical = critical; -+ encodeThis(); -+ } -+ -+ public SubjectKeyIdentifierExtension(byte[] octetString) -+ throws IOException { -+ id = new KeyIdentifier(octetString); -+ -+ this.extensionId = PKIXExtensions.SubjectKey_Id; -+ this.critical = false; -+ encodeThis(); -+ } -+ -+ /** -+ * Create the extension from the passed DER encoded value. -+ * -+ * @param critical true if the extension is to be treated as critical. -+ * @param value Array of DER encoded bytes of the actual value. -+ * @exception IOException on error. -+ */ -+ public SubjectKeyIdentifierExtension(Boolean critical, Object value) -+ throws IOException { -+ this.extensionId = PKIXExtensions.SubjectKey_Id; -+ this.critical = critical.booleanValue(); -+ -+ int len = Array.getLength(value); -+ byte[] extValue = new byte[len]; -+ for (int i = 0; i < len; i++) { -+ extValue[i] = Array.getByte(value, i); -+ } -+ this.extensionValue = extValue; -+ DerValue val = new DerValue(extValue); -+ this.id = new KeyIdentifier(val); -+ } -+ -+ /** -+ * Returns a printable representation. -+ */ -+ public String toString() { -+ if (id == null) -+ return ""; -+ String s = super.toString() + "SubjectKeyIdentifier [\n" -+ + id.toString() + "]\n"; -+ return (s); -+ } -+ -+ /** -+ * Write the extension to the OutputStream. -+ * -+ * @param out the OutputStream to write the extension to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ if (extensionValue == null) { -+ extensionId = PKIXExtensions.SubjectKey_Id; -+ critical = false; -+ encodeThis(); -+ } -+ super.encode(tmp); -+ out.write(tmp.toByteArray()); -+ } -+ -+ /** -+ * Decode the extension from the InputStream. -+ * -+ * @param in the InputStream to unmarshal the contents from. -+ * @exception IOException on decoding or validity errors. -+ */ -+ public void decode(InputStream in) throws IOException { -+ throw new IOException("Method not to be called directly."); -+ } -+ -+ /** -+ * Set the attribute value. -+ */ -+ public void set(String name, Object obj) throws IOException { -+ clearValue(); -+ if (name.equalsIgnoreCase(KEY_ID)) { -+ if (!(obj instanceof KeyIdentifier)) { -+ throw new IOException("Attribute value should be of" + -+ " type KeyIdentifier."); -+ } -+ id = (KeyIdentifier) obj; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:SubjectKeyIdentifierExtension."); -+ } -+ } -+ -+ /** -+ * Get the attribute value. -+ */ -+ public Object get(String name) throws IOException { -+ if (name.equalsIgnoreCase(KEY_ID)) { -+ return (id); -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:SubjectKeyIdentifierExtension."); -+ } -+ } -+ -+ /** -+ * Delete the attribute value. -+ */ -+ public void delete(String name) throws IOException { -+ if (name.equalsIgnoreCase(KEY_ID)) { -+ id = null; -+ } else { -+ throw new IOException("Attribute name not recognized by " + -+ "CertAttrSet:SubjectKeyIdentifierExtension."); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(KEY_ID); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/URIName.java b/org/mozilla/jss/netscape/security/x509/URIName.java -new file mode 100644 -index 00000000..5143c587 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/URIName.java -@@ -0,0 +1,85 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class implements the URIName as required by the GeneralNames -+ * ASN.1 object. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.3 -+ * @see GeneralName -+ * @see GeneralNames -+ * @see GeneralNameInterface -+ */ -+public class URIName implements GeneralNameInterface { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 8340049830612859508L; -+ private String name; -+ -+ /** -+ * Create the URIName object from the passed encoded Der value. -+ * -+ * @param derValue the encoded DER URIName. -+ * @exception IOException on error. -+ */ -+ public URIName(DerValue derValue) throws IOException { -+ name = derValue.getIA5String(); -+ } -+ -+ /** -+ * Create the URIName object with the specified name. -+ * -+ * @param name the URIName. -+ */ -+ public URIName(String name) { -+ this.name = name; -+ } -+ -+ /** -+ * Return the type of the GeneralName. -+ */ -+ public int getType() { -+ return (GeneralNameInterface.NAME_URI); -+ } -+ -+ /** -+ * Encode the URI name into the DerOutputStream. -+ * -+ * @param out the DER stream to encode the URIName to. -+ * @exception IOException on encoding errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ out.putIA5String(name); -+ } -+ -+ /** -+ * Convert the name into user readable string. -+ */ -+ public String toString() { -+ return ("URIName: " + name); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/UniqueIdentity.java b/org/mozilla/jss/netscape/security/x509/UniqueIdentity.java -new file mode 100644 -index 00000000..24a8b11e ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/UniqueIdentity.java -@@ -0,0 +1,112 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.BitArray; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * This class defines the UniqueIdentity class used by certificates. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.6 -+ */ -+public class UniqueIdentity { -+ // Private data members -+ private BitArray id; -+ -+ /** -+ * The default constructor for this class. -+ * -+ * @param id the byte array containing the unique identifier. -+ */ -+ public UniqueIdentity(BitArray id) { -+ this.id = id; -+ } -+ -+ /** -+ * The default constructor for this class. -+ * -+ * @param id the byte array containing the unique identifier. -+ */ -+ public UniqueIdentity(byte[] id) { -+ this.id = new BitArray(id.length * 8, id); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param in the DerInputStream to read the UniqueIdentity from. -+ * @exception IOException on decoding errors. -+ */ -+ public UniqueIdentity(DerInputStream in) throws IOException { -+ DerValue derVal = in.getDerValue(); -+ id = derVal.getUnalignedBitString(true); -+ } -+ -+ /** -+ * Create the object, decoding the values from the passed DER stream. -+ * -+ * @param derVal the DerValue decoded from the stream. -+ * @param tag the tag the value is encoded under. -+ * @exception IOException on decoding errors. -+ */ -+ public UniqueIdentity(DerValue derVal) throws IOException { -+ id = derVal.getUnalignedBitString(true); -+ } -+ -+ /** -+ * Return the UniqueIdentity as a printable string. -+ */ -+ public String toString() { -+ return ("UniqueIdentity:" + id.toString() + "\n"); -+ } -+ -+ /** -+ * Encode the UniqueIdentity in DER form to the stream. -+ * -+ * @param out the DerOutputStream to marshal the contents to. -+ * @param tag enocode it under the following tag. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out, byte tag) throws IOException { -+ byte[] bytes = id.toByteArray(); -+ int excessBits = bytes.length * 8 - id.length(); -+ -+ out.write(tag); -+ out.putLength(bytes.length + 1); -+ -+ out.write(excessBits); -+ out.write(bytes); -+ } -+ -+ /** -+ * Return the unique id. -+ */ -+ public boolean[] getId() { -+ if (id == null) -+ return null; -+ -+ return id.toBooleanArray(); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/UserNotice.java b/org/mozilla/jss/netscape/security/x509/UserNotice.java -new file mode 100644 -index 00000000..4b19b6dd ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/UserNotice.java -@@ -0,0 +1,96 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Represent the UserNotice Qualifier. -+ * -+ * UserNotice ::= SEQUENCE { -+ * noticeRef NoticeReference OPTIONAL, -+ * explicitText DisplayText OPTIONAL -+ * } -+ * -+ * @author Thomas Kwan -+ */ -+public class UserNotice extends Qualifier { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 5770869942793748051L; -+ private NoticeReference mNoticeReference = null; -+ private DisplayText mDisplayText = null; -+ -+ public UserNotice(NoticeReference ref, DisplayText text) { -+ mNoticeReference = ref; -+ mDisplayText = text; -+ } -+ -+ public UserNotice(DerValue val) throws IOException { -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new IOException("Invalid encoding for UserNotice"); -+ } -+ // case 0: no element -+ if (val.data.available() == 0) -+ return; -+ // case 1: 1 element -+ DerValue inSeq = val.data.getDerValue(); -+ if (inSeq.tag == DerValue.tag_Sequence) { -+ mNoticeReference = new NoticeReference(inSeq); -+ } else { -+ mDisplayText = new DisplayText(inSeq); -+ } -+ if (val.data.available() == 0) -+ return; -+ // case 2: 2 elements -+ mDisplayText = new DisplayText(val.data.getDerValue()); -+ } -+ -+ public NoticeReference getNoticeReference() { -+ return mNoticeReference; -+ } -+ -+ public DisplayText getDisplayText() { -+ return mDisplayText; -+ } -+ -+ /** -+ * Write the UserNotice to the DerOutputStream. -+ * -+ * @param out the DerOutputStream to write the object to. -+ * @exception IOException on errors. -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ // OPTIONAL -+ if (mNoticeReference != null) { -+ mNoticeReference.encode(tmp); -+ } -+ // OPTIONAL -+ if (mDisplayText != null) { -+ mDisplayText.encode(tmp); -+ } -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X500Name.java b/org/mozilla/jss/netscape/security/x509/X500Name.java -new file mode 100644 -index 00000000..b19f8f37 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X500Name.java -@@ -0,0 +1,723 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.security.Principal; -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Enumeration; -+import java.util.List; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * X.500 names are used to identify entities, such as those which are -+ * identified by X.509 certificates. They are world-wide, hierarchical, -+ * and descriptive. Entities can be identified by attributes, and in -+ * some systems can be searched for according to those attributes. -+ * -+ *

-+ * This class exposes only partial X.500 name functionality. Most -+ * notably, it works best if Relative Distinguished Names only have one -+ * (unique) attribute each, and if only the most common attributes need -+ * to be visible to applications. This limitation, and others, will -+ * be lifted over time. -+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.35 -+ * @see GeneralName -+ * @see GeneralNames -+ * @see GeneralNameInterface -+ * @see RDN -+ * @see AVA -+ * @see LdapDNStrConverter -+ */ -+ -+public class X500Name implements Principal, GeneralNameInterface { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -730790062013191108L; -+ -+ /** -+ * Constructs a name from a Ldap DN string, such -+ * as &lb;CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US&rb;. The -+ * older "/C=US/O=Sun Microsystems, Inc/OU=JavaSoft/CN=Dave" syntax -+ * is not currently supported. (The former is RFC 1779 style.) -+ * -+ * @param ldapDNString a Ldap DN String e.g. as defined in RFC1779 -+ */ -+ public X500Name(String ldapDNString) -+ throws IOException { -+ X500Name x500name; -+ -+ if (ldapDNString == null || ldapDNString.equals("")) { -+ clear(); -+ return; -+ } -+ x500name = LdapDNStrConverter.getDefault().parseDN(ldapDNString); -+ names = x500name.getNames(); -+ } -+ -+ /** -+ * Constructs a X500Name from a Ldap DN String using the specified -+ * LdapDNStrConverter. Also use the input tags. -+ * -+ * @see LdapDNStrConverter -+ * -+ * @param ldapDNString a Ldap DN String e.g. as defined in RFC1779. -+ * @param ldapDNStrConverter A LdapDNStrConverter -+ */ -+ public X500Name(String ldapDNString, LdapDNStrConverter ldapDNStrConverter, byte[] tags) -+ throws IOException { -+ -+ if (ldapDNString == null || ldapDNString.equals("")) { -+ clear(); -+ return; -+ } -+ X500Name x500name; -+ x500name = ldapDNStrConverter.parseDN(ldapDNString, tags); -+ names = x500name.getNames(); -+ -+ } -+ -+ public X500Name(String ldapDNString, byte[] tags) -+ throws IOException { -+ if (ldapDNString == null || ldapDNString.equals("")) { -+ clear(); -+ return; -+ } -+ X500Name x500name; -+ x500name = LdapDNStrConverter.getDefault().parseDN(ldapDNString, tags); -+ names = x500name.getNames(); -+ } -+ -+ /** -+ * Constructs a X500Name from a Ldap DN String using the specified -+ * LdapDNStrConverter. -+ * -+ * @see LdapDNStrConverter -+ * -+ * @param ldapDNString a Ldap DN String e.g. as defined in RFC1779. -+ * @param ldapDNStrConverter A LdapDNStrConverter -+ */ -+ public X500Name(String ldapDNString, -+ LdapDNStrConverter ldapDNStrConverter) -+ throws IOException { -+ if (ldapDNString == null || ldapDNString.equals("")) { -+ clear(); -+ return; -+ } -+ X500Name x500name; -+ x500name = ldapDNStrConverter.parseDN(ldapDNString); -+ names = x500name.getNames(); -+ } -+ -+ /** -+ * Constructs a X500Name from fields common in enterprise application -+ * environments. -+ * -+ * @param commonName common name of a person, e.g. "Vivette Davis" -+ * @param organizationUnit small organization name, e.g. "Purchasing" -+ * @param organizationName large organization name, e.g. "Onizuka, Inc." -+ * @param country two letter country code, e.g. "CH" -+ */ -+ public X500Name( -+ String commonName, -+ String organizationUnit, -+ String organizationName, -+ String country) throws IOException { -+ DirStrConverter dirStrConverter = new DirStrConverter(); -+ PrintableConverter printableConverter = new PrintableConverter(); -+ AVA[] assertion = new AVA[1]; // array is cloned in constructors. -+ int i = 4; -+ -+ names = new RDN[i]; -+ /* -+ * NOTE: it's only on output that little-endian -+ * ordering is used. -+ */ -+ assertion[0] = new AVA(commonName_oid, -+ dirStrConverter.getValue(commonName)); -+ names[--i] = new RDN(assertion); -+ -+ assertion[0] = new AVA(orgUnitName_oid, -+ dirStrConverter.getValue(organizationUnit)); -+ names[--i] = new RDN(assertion); -+ -+ assertion[0] = new AVA(orgName_oid, -+ dirStrConverter.getValue(organizationName)); -+ names[--i] = new RDN(assertion); -+ -+ assertion[0] = new AVA(countryName_oid, -+ printableConverter.getValue(country)); -+ names[--i] = new RDN(assertion); -+ } -+ -+ /** -+ * Constructs a X500Name from fields common in Internet application -+ * environments. -+ * -+ * @param commonName common name of a person, e.g. "Vivette Davis" -+ * @param organizationUnit small organization name, e.g. "Purchasing" -+ * @param organizationName large organization name, e.g. "Onizuka, Inc." -+ * @param localityName locality (city) name, e.g. "Palo Alto" -+ * @param stateName state name, e.g. "California" -+ * @param country two letter country code, e.g. "CH" -+ */ -+ public X500Name( -+ String commonName, -+ String organizationUnit, -+ String organizationName, -+ String localityName, -+ String stateName, -+ String country) throws IOException { -+ DirStrConverter dirStrConverter = new DirStrConverter(); -+ PrintableConverter printableConverter = new PrintableConverter(); -+ AVA[] assertion = new AVA[1]; // array is cloned in constructors. -+ int i = 6; -+ -+ names = new RDN[i]; -+ /* -+ * NOTE: it's only on output that little-endian -+ * ordering is used. -+ */ -+ assertion[0] = new AVA(commonName_oid, -+ dirStrConverter.getValue(commonName)); -+ names[--i] = new RDN(assertion); -+ -+ assertion[0] = new AVA(orgUnitName_oid, -+ dirStrConverter.getValue(organizationUnit)); -+ names[--i] = new RDN(assertion); -+ -+ assertion[0] = new AVA(orgName_oid, -+ dirStrConverter.getValue(organizationName)); -+ names[--i] = new RDN(assertion); -+ -+ assertion[0] = new AVA(localityName_oid, -+ dirStrConverter.getValue(localityName)); -+ names[--i] = new RDN(assertion); -+ -+ assertion[0] = new AVA(stateName_oid, -+ dirStrConverter.getValue(stateName)); -+ names[--i] = new RDN(assertion); -+ -+ assertion[0] = new AVA(countryName_oid, -+ printableConverter.getValue(country)); -+ names[--i] = new RDN(assertion); -+ } -+ -+ /** -+ * Constructs a name from an ASN.1 encoded value. The encoding -+ * of the name in the stream uses DER (a BER/1 subset). -+ * -+ * @param value a DER-encoded value holding an X.500 name. -+ */ -+ public X500Name(DerValue value) throws IOException { -+ -+ this(value.toDerInputStream()); -+ } -+ -+ /** -+ * Constructs a name from an ASN.1 encoded input stream. The encoding -+ * of the name in the stream uses DER (a BER/1 subset). -+ * -+ * @param in DER-encoded data holding an X.500 name. -+ */ -+ public X500Name(DerInputStream in) -+ throws IOException { -+ parseDER(in); -+ } -+ -+ /** -+ * Constructs a name from an ASN.1 encoded byte array. -+ * -+ * @param name DER-encoded byte array holding an X.500 name. -+ */ -+ public X500Name(byte[] name) -+ throws IOException { -+ DerInputStream in = new DerInputStream(name); -+ parseDER(in); -+ -+ } -+ -+ /** -+ * Constructs a X500Name from array of RDN. The RDNs are expected to -+ * be in big endian order i.e. most significant first. -+ * -+ * @param rdns an array of RDN. -+ */ -+ public X500Name(RDN[] rdns) -+ throws IOException { -+ names = rdns.clone(); -+ } -+ -+ /** -+ * convenience method. -+ * -+ * @param rdns a vector of rdns. -+ */ -+ public X500Name(Vector rdnVector) -+ throws IOException { -+ int size = rdnVector.size(); -+ names = new RDN[size]; -+ for (int i = 0; i < size; i++) { -+ names[i] = rdnVector.elementAt(i); -+ } -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + Arrays.hashCode(names); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) -+ return true; -+ if (obj == null) -+ return false; -+ if (getClass() != obj.getClass()) -+ return false; -+ X500Name other = (X500Name) obj; -+ if (!Arrays.equals(names, other.names)) -+ return false; -+ return true; -+ } -+ -+ /** -+ * Sets private data to a null state -+ */ -+ -+ private void clear() { -+ dn = ""; -+ names = null; -+ -+ } -+ -+ /** -+ * Returns the name component as a Java string, regardless of its -+ * encoding restrictions. -+ */ -+ private String getString(DerValue attribute) throws IOException { -+ String value = attribute.getAsString(); -+ -+ if (value == null) -+ throw new IOException("not a DER string encoding, " -+ + attribute.tag); -+ else -+ return value; -+ } -+ -+ /** -+ * Return type of GeneralName. -+ */ -+ public int getType() { -+ return (GeneralNameInterface.NAME_DIRECTORY); -+ } -+ -+ /** -+ * Returns a "Country" name component. If more than one -+ * such attribute exists, the topmost one is returned. -+ * -+ * @return "C=" component of the name, if any. -+ */ -+ public String getCountry() throws IOException { -+ DerValue attr = findAttribute(countryName_oid); -+ -+ return getString(attr); -+ } -+ -+ /** -+ * Returns an "Organization" name component. If more than -+ * one such attribute exists, the topmost one is returned. -+ * -+ * @return "O=" component of the name, if any. -+ */ -+ public String getOrganization() throws IOException { -+ DerValue attr = findAttribute(orgName_oid); -+ -+ return getString(attr); -+ } -+ -+ /** -+ * Returns an "Organizational Unit" name component. If more -+ * than one such attribute exists, the topmost one is returned. -+ * -+ * @return "OU=" component of the name, if any. -+ */ -+ public String getOrganizationalUnit() throws IOException { -+ DerValue attr = findAttribute(orgUnitName_oid); -+ -+ return getString(attr); -+ } -+ -+ /** -+ * Returns a "Common Name" component. If more than one such -+ * attribute exists, the topmost one is returned. -+ * -+ * @return "CN=" component of the name, if any. -+ */ -+ public String getCommonName() throws IOException { -+ DerValue attr = findAttribute(commonName_oid); -+ -+ return getString(attr); -+ } -+ -+ /** -+ * Returns a "UID" component. If more than one such -+ * attribute exists, the topmost one is returned. -+ * -+ * @return "UID=" component of the name, if any. -+ */ -+ public String getUserID() throws IOException { -+ DerValue attr = findAttribute(uidName_oid); -+ -+ return getString(attr); -+ } -+ -+ /** -+ * Returns a "Locality" name component. If more than one -+ * such component exists, the topmost one is returned. -+ * -+ * @return "L=" component of the name, if any. -+ */ -+ public String getLocality() throws IOException { -+ DerValue attr = findAttribute(localityName_oid); -+ -+ return getString(attr); -+ } -+ -+ /** -+ * Returns a "State" name component. If more than one -+ * such component exists, the topmost one is returned. -+ * -+ * @return "S=" component of the name, if any. -+ */ -+ public String getState() throws IOException { -+ DerValue attr = findAttribute(stateName_oid); -+ -+ return getString(attr); -+ } -+ -+ /** -+ * Returns a "Email" name component. If more than one -+ * such component exists, the topmost one is returned. -+ * -+ * @return "E=" component of the name, if any. -+ */ -+ public String getEmail() throws IOException { -+ DerValue attr = findAttribute(email_oid); -+ if (attr == null) -+ return null; -+ return getString(attr); -+ } -+ -+ /** -+ * Returns a Ldap DN String from the X500Name using the global default -+ * LdapDNStrConverter -+ * -+ * @see LdapDNStrConverter -+ * @return Ldap DN string of this X500Name using the default converter. -+ */ -+ public String toLdapDNString() -+ throws IOException { -+ if (dn == null) -+ generateDN(LdapDNStrConverter.getDefault()); -+ return dn; -+ } -+ -+ /** -+ * Return a list of attributes of the given type. -+ * -+ * The "most specific" value comes last. -+ * -+ * If there are no name attributes of the given type, an empty -+ * list is returned. -+ */ -+ public List getAttributesForOid(ObjectIdentifier oid) -+ throws IOException { -+ List xs = new ArrayList<>(); -+ for (int i = 0; i < names.length; i++) { -+ DerValue v = names[i].findAttribute(oid); -+ if (v != null) -+ xs.add(getString(v)); -+ } -+ return xs; -+ } -+ -+ /** -+ * Returns a Ldap DN String from the X500Name -+ * using the specified LdapDNStrconverter. -+ * For example, RFC1779String converter can be passed to convert the -+ * DN to RFC1779 string syntax. -+ * -+ * @see LdapDNStrConverter -+ * @param ldapDNStrConverter a LdapDNStrConverter -+ * @return Ldap DN string of the X500Name -+ */ -+ public String toLdapDNString(LdapDNStrConverter ldapDNStrConverter) -+ throws IOException { -+ -+ if (dn == null) -+ generateDN(ldapDNStrConverter); -+ return dn; -+ } -+ -+ /** -+ * Returns a Ldap DN string, using the global default LdapDNStrConverter -+ * or null if an error occurs in the conversion. -+ */ -+ public String toString() { -+ String s; -+ if (names == null) { -+ s = ""; -+ return s; -+ } -+ try { -+ s = toLdapDNString(); -+ } catch (IOException e) { -+ return null; -+ } -+ return s; -+ } -+ -+ /** -+ * Returns the value of toString(). This call is needed to -+ * implement the java.security.Principal interface. -+ */ -+ public String getName() { -+ return toString(); -+ } -+ -+ private String dn; // RFC 1779 style DN, or null -+ private RDN names[]; // RDNs -+ -+ /** -+ * Find the first instance of this attribute in a "top down" -+ * search of all the attributes in the name. -+ */ -+ private DerValue findAttribute(ObjectIdentifier attribute) { -+ int i; -+ DerValue retval = null; -+ -+ for (i = 0; i < names.length; i++) { -+ retval = names[i].findAttribute(attribute); -+ if (retval != null) -+ break; -+ } -+ return retval; -+ } -+ -+ /** -+ * Returns an enumerator of RDNs in the X500Name. -+ * -+ * @return enumeration of rdns in this X500Name. -+ */ -+ public Enumeration getRDNs() { -+ return new RDNEnumerator(); -+ } -+ -+ /** -+ * Returns an array of RDN in the X500Name. -+ * -+ * @return array of RDN in this X500name. -+ */ -+ public RDN[] getNames() { -+ return names.clone(); -+ } -+ -+ /** -+ * Returns the number of RDNs in the X500Name. -+ * -+ * @return number of RDNs in this X500Name. -+ */ -+ public int getNamesLength() { -+ return names.length; -+ } -+ -+ /****************************************************************/ -+ -+ private void parseDER(DerInputStream in) throws IOException { -+ // -+ // X.500 names are a "SEQUENCE OF" RDNs, which means one or -+ // more and order matters. We scan them in order, which -+ // conventionally is big-endian. -+ // -+ DerValue nameseq[] = in.getSequence(5); -+ int i; -+ -+ if (nameseq.length != 0) { -+ names = new RDN[nameseq.length]; -+ } else { -+ clear(); -+ } -+ -+ for (i = 0; i < nameseq.length; i++) -+ names[i] = new RDN(nameseq[i]); -+ } -+ -+ /** -+ * Encodes the name in DER-encoded form. -+ * -+ * @param out where to put the DER-encoded X.500 name -+ */ -+ public void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ int i; -+ -+ int len = 0; -+ if (names == null) { -+ len = 0; -+ } else { -+ len = names.length; -+ -+ } -+ -+ for (i = 0; i < len; i++) -+ names[i].encode(tmp); -+ -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+ -+ /** -+ * Gets the name in DER-encoded form. -+ * -+ * @return the DER encoded byte array of this name, -+ * null if no names are present. -+ */ -+ public byte[] getEncoded() throws IOException { -+ try (DerOutputStream out = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ int len = 0; -+ -+ if (names == null) { -+ len = 0; -+ } else { -+ len = names.length; -+ } -+ -+ for (int i = 0; i < len; i++) -+ names[i].encode(tmp); -+ -+ out.write(DerValue.tag_Sequence, tmp); -+ return out.toByteArray(); -+ } -+ } -+ -+ /* -+ * Dump the printable form of a distinguished name. Each relative -+ * name is separated from the next by a ",", and assertions in the -+ * relative names have "label=value" syntax. -+ * -+ * Uses RFC 1779 syntax (i.e. little-endian, comma separators) -+ * -+ */ -+ private void generateDN(LdapDNStrConverter ldapDNStrConverter) -+ throws IOException { -+ if (names == null) -+ return; -+ -+ dn = ldapDNStrConverter.encodeDN(this); -+ } -+ -+ private class RDNEnumerator implements Enumeration { -+ private int index; -+ -+ public RDNEnumerator() { -+ index = 0; -+ } -+ -+ public boolean hasMoreElements() { -+ return (index < names.length); -+ } -+ -+ public RDN nextElement() { -+ if (index >= names.length) -+ return null; -+ return names[index++]; -+ } -+ } -+ -+ /****************************************************************/ -+ -+ /* -+ * Maybe return a preallocated OID, to reduce storage costs -+ * and speed recognition of common X.500 attributes. -+ */ -+ static ObjectIdentifier intern(ObjectIdentifier oid) -+ throws IOException { -+ return X500NameAttrMap.getDefault().getOid(oid); -+ } -+ -+ /* -+ * Selected OIDs from X.520 -+ */ -+ -+ /** OID for the "CN=" attribute, denoting a person's common name. */ -+ public static final ObjectIdentifier commonName_oid = X500NameAttrMap.getDefault().getOid("CN"); -+ -+ /** OID for the "UID=" attribute, denoting a person's ID. */ -+ public static final ObjectIdentifier uidName_oid = X500NameAttrMap.getDefault().getOid("UID"); -+ -+ /** OID for the "C=" attribute, denoting a country. */ -+ public static final ObjectIdentifier countryName_oid = X500NameAttrMap.getDefault().getOid("C"); -+ -+ /** OID for the "L=" attribute, denoting a locality (such as a city) */ -+ public static final ObjectIdentifier localityName_oid = X500NameAttrMap.getDefault().getOid("L"); -+ -+ /** OID for the "O=" attribute, denoting an organization name */ -+ public static final ObjectIdentifier orgName_oid = X500NameAttrMap.getDefault().getOid("O"); -+ -+ /** OID for the "OU=" attribute, denoting an organizational unit name */ -+ public static final ObjectIdentifier orgUnitName_oid = X500NameAttrMap.getDefault().getOid("OU"); -+ -+ /** OID for the "S=" attribute, denoting a state (such as Delaware) */ -+ public static final ObjectIdentifier stateName_oid = X500NameAttrMap.getDefault().getOid("ST"); -+ -+ /** OID for the "STREET=" attribute, denoting a street address. */ -+ public static final ObjectIdentifier streetAddress_oid = X500NameAttrMap.getDefault().getOid("STREET"); -+ -+ /** OID for the "T=" attribute, denoting a person's title. */ -+ public static final ObjectIdentifier title_oid = X500NameAttrMap.getDefault().getOid("TITLE"); -+ -+ /** OID for the "E=" attribute, denoting a person's email address. */ -+ public static final ObjectIdentifier email_oid = X500NameAttrMap.getDefault().getOid("E"); -+ -+ /* -+ * OIDs from other sources which show up in X.500 names we -+ * expect to deal with often -+ */ -+ -+ private static final int ipAddress_data[] = // SKIP -+ { 1, 3, 6, 1, 4, 1, 42, 2, 11, 2, 1 }; -+ -+ /** OID for "IP=" IP address attributes, used with SKIP. */ -+ public static final ObjectIdentifier ipAddress_oid = new ObjectIdentifier(ipAddress_data); -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X500NameAttrMap.java b/org/mozilla/jss/netscape/security/x509/X500NameAttrMap.java -new file mode 100644 -index 00000000..28673bf4 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X500NameAttrMap.java -@@ -0,0 +1,376 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.util.Enumeration; -+import java.util.Hashtable; -+ -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * Maps an attribute name in an X500 AVA to its OID and a -+ * converter for the attribute type. The converter converts from a string to -+ * its DER encoded attribute value. * For example, "CN" maps to its OID of -+ * 2.5.4.3 and the Directory String Converter. The Directory String -+ * Converter converts from a string to a DerValue with tag Printable, T.61 or -+ * UniversalString. -+ * -+ * @author Lily Hsiao, Slava Galperin at Netscape Communications, Inc. -+ * -+ */ -+ -+public class X500NameAttrMap { -+ // -+ // public constructors. -+ // -+ -+ /** -+ * Construct a X500NameAttrMap. -+ */ -+ public X500NameAttrMap() { -+ } -+ -+ // -+ // public get methods. -+ // -+ -+ /** -+ * Get the attribute name (keyword) of the specified OID. -+ * -+ * @param oid An ObjectIdentifier -+ * -+ * @return An attribute name (keyword string) for the OID. -+ */ -+ public String getName(ObjectIdentifier oid) { -+ // XXX assert oid != null -+ return oid2Name.get(oid); -+ } -+ -+ /** -+ * Get the ObjectIdentifier of the attribute name. -+ * -+ * @param name An attribute name (string of ascii characters) -+ * -+ * @return An ObjectIdentifier for the attribute. -+ */ -+ public ObjectIdentifier getOid(String name) { -+ // XXX assert name != null -+ return name2OID.get(name.toUpperCase()); -+ } -+ -+ /** -+ * Get the Attribute Value Converter for the specified attribute name. -+ * -+ * @param name An attribute name -+ * -+ * @return An attribute value converter for the attribute name -+ */ -+ public AVAValueConverter getValueConverter(String name) { -+ ObjectIdentifier oid = -+ name2OID.get(name.toUpperCase()); -+ if (oid == null) -+ return null; -+ return oid2ValueConverter.get(oid); -+ } -+ -+ /** -+ * Get the Attribute Value Converter for the specified ObjectIdentifier. -+ * -+ * @param oid An ObjectIdentifier -+ * -+ * @return An AVAValueConverter for the OID. -+ */ -+ public AVAValueConverter getValueConverter(ObjectIdentifier oid) { -+ return oid2ValueConverter.get(oid); -+ } -+ -+ /** -+ * Get an Enumeration of all attribute names in this map. -+ * -+ * @return An Enumeration of all attribute names. -+ */ -+ public Enumeration getAllNames() { -+ return name2OID.keys(); -+ } -+ -+ /** -+ * Get an Enumeration of all ObjectIdentifiers in this map. -+ * -+ * @return An Enumeration of all OIDs in this map. -+ */ -+ public Enumeration getAllOIDs() { -+ return oid2Name.keys(); -+ } -+ -+ /** -+ * Get the ObjectIdentifier object in the map for the specified OID. -+ * -+ * @param oid An ObjectIdentifier. -+ * @return The ObjectIdentifier object in this map for the OID. -+ */ -+ public ObjectIdentifier getOid(ObjectIdentifier oid) { -+ String name = oid2Name.get(oid); -+ if (name == null) -+ return null; -+ return name2OID.get(name); -+ } -+ -+ // -+ // public add methods. -+ // -+ -+ /** -+ * Adds a attribute name, ObjectIdentifier, AVAValueConverter entry -+ * to the map. -+ * -+ * @param name An attribute name (string of ascii chars) -+ * @param oid The ObjectIdentifier for the attribute. -+ * @param valueConverter An AVAValueConverter object for converting -+ * an value for this attribute from a string to -+ * a DerValue and vice versa. -+ */ -+ public void addNameOID(String name, ObjectIdentifier oid, -+ AVAValueConverter valueConverter) { -+ // normalize name for case insensitive compare. -+ ObjectIdentifier theOid; -+ Class expValueConverter; -+ -+ theOid = name2OID.get(name); -+ if (theOid != null) { -+ expValueConverter = oid2ValueConverter.get(theOid).getClass(); -+ if (!theOid.equals(oid) || -+ expValueConverter != valueConverter.getClass()) { -+ throw new IllegalArgumentException( -+ "Another keyword-oid-valueConverter triple already " + -+ "exists in the X500NameAttrMap "); -+ } -+ return; -+ } -+ name2OID.put(name.toUpperCase(), oid); -+ oid2Name.put(oid, name.toUpperCase()); -+ oid2ValueConverter.put(oid, valueConverter); -+ } -+ -+ // -+ // public static methods. -+ // -+ -+ /** -+ * Get the global default X500NameAttrMap. -+ * -+ * @return The global default X500NameAttrMap. -+ */ -+ public static X500NameAttrMap getDefault() { -+ return defMap; -+ } -+ -+ /** -+ * Get the global default X500NamAttrMap using the DirStrConverter. -+ * -+ * @return The global default X500NameAttrMap using the DirStrConverter. -+ */ -+ -+ public static X500NameAttrMap getDirDefault() { -+ return defDirMap; -+ -+ } -+ -+ /** -+ * Set the global default X500NameAttrMap. -+ * -+ * @param newDefault The new default X500NameAttrMap. -+ */ -+ public static void setDefault(X500NameAttrMap newDefault) { -+ // XXX assert newDef != null -+ defMap = newDefault; -+ } -+ -+ // -+ // private variables -+ // -+ -+ Hashtable name2OID = new Hashtable(); -+ Hashtable oid2Name = new Hashtable(); -+ Hashtable oid2ValueConverter = -+ new Hashtable(); -+ -+ // -+ // global defaults. -+ // -+ -+ private static X500NameAttrMap defMap; -+ -+ private static X500NameAttrMap defDirMap; -+ -+ /* -+ * Create the default maps on initialization. -+ */ -+ static { -+ defMap = new X500NameAttrMap(); -+ AVAValueConverter directoryStr = new DirStrConverter(), ia5Str = new IA5StringConverter(); -+ defMap.addNameOID("CN", -+ new ObjectIdentifier("2.5.4.3"), -+ directoryStr); -+ defMap.addNameOID("OU", -+ new ObjectIdentifier("2.5.4.11"), -+ directoryStr); -+ defMap.addNameOID("O", -+ new ObjectIdentifier("2.5.4.10"), -+ directoryStr); -+ // serialNumber added for CEP support -+ defMap.addNameOID("SERIALNUMBER", -+ new ObjectIdentifier("2.5.4.5"), -+ new PrintableConverter()); -+ defMap.addNameOID("C", -+ new ObjectIdentifier("2.5.4.6"), -+ new PrintableConverter()); -+ defMap.addNameOID("L", -+ new ObjectIdentifier("2.5.4.7"), -+ directoryStr); -+ defMap.addNameOID("ST", -+ new ObjectIdentifier("2.5.4.8"), -+ directoryStr); -+ defMap.addNameOID("STREET", -+ new ObjectIdentifier("2.5.4.9"), -+ directoryStr); -+ defMap.addNameOID("TITLE", -+ new ObjectIdentifier("2.5.4.12"), -+ directoryStr); -+ // RFC 1274 UserId, rfc822MailBox -+ defMap.addNameOID("UID", -+ new ObjectIdentifier("0.9.2342.19200300.100.1.1"), -+ directoryStr); -+ defMap.addNameOID("MAIL", -+ new ObjectIdentifier("0.9.2342.19200300.100.1.3"), -+ ia5Str); -+ // PKCS9 e-mail address -+ defMap.addNameOID("E", -+ new ObjectIdentifier("1.2.840.113549.1.9.1"), -+ ia5Str); -+ -+ // DC definition from draft-ietf-asid-ldap-domains-02.txt -+ defMap.addNameOID("DC", -+ new ObjectIdentifier("0.9.2342.19200300.100.1.25"), -+ ia5Str); -+ -+ // more defined in RFC2459 used in Subject Directory Attr extension -+ defMap.addNameOID("SN", // surname -+ new ObjectIdentifier("2.5.4.4"), -+ directoryStr); -+ defMap.addNameOID("GIVENNAME", -+ new ObjectIdentifier("2.5.4.42"), -+ directoryStr); -+ defMap.addNameOID("INITIALS", -+ new ObjectIdentifier("2.5.4.43"), -+ directoryStr); -+ defMap.addNameOID("GENERATIONQUALIFIER", -+ new ObjectIdentifier("2.5.4.44"), -+ directoryStr); -+ defMap.addNameOID("DNQUALIFIER", -+ new ObjectIdentifier("2.5.4.46"), -+ directoryStr); -+ -+ // these two added mainly for CEP support -+ // PKCS9 unstructured name -+ defMap.addNameOID("UNSTRUCTUREDNAME", -+ new ObjectIdentifier("1.2.840.113549.1.9.2"), -+ ia5Str); -+ // PKCS9 unstructured address -+ defMap.addNameOID("UNSTRUCTUREDADDRESS", -+ new ObjectIdentifier("1.2.840.113549.1.9.8"), -+ new PrintableConverter()); -+ }; -+ -+ static { -+ defDirMap = new X500NameAttrMap(); -+ AVAValueConverter directoryStr = new DirStrConverter(); -+ -+ defDirMap.addNameOID("CN", -+ new ObjectIdentifier("2.5.4.3"), -+ directoryStr); -+ defDirMap.addNameOID("OU", -+ new ObjectIdentifier("2.5.4.11"), -+ directoryStr); -+ defDirMap.addNameOID("O", -+ new ObjectIdentifier("2.5.4.10"), -+ directoryStr); -+ // serialNumber added for CEP support -+ defDirMap.addNameOID("SERIALNUMBER", -+ new ObjectIdentifier("2.5.4.5"), -+ directoryStr); -+ defDirMap.addNameOID("C", -+ new ObjectIdentifier("2.5.4.6"), -+ directoryStr); -+ defDirMap.addNameOID("L", -+ new ObjectIdentifier("2.5.4.7"), -+ directoryStr); -+ defDirMap.addNameOID("ST", -+ new ObjectIdentifier("2.5.4.8"), -+ directoryStr); -+ defDirMap.addNameOID("STREET", -+ new ObjectIdentifier("2.5.4.9"), -+ directoryStr); -+ defDirMap.addNameOID("TITLE", -+ new ObjectIdentifier("2.5.4.12"), -+ directoryStr); -+ // RFC 1274 UserId, rfc822MailBox -+ defDirMap.addNameOID("UID", -+ new ObjectIdentifier("0.9.2342.19200300.100.1.1"), -+ directoryStr); -+ defDirMap.addNameOID("MAIL", -+ new ObjectIdentifier("0.9.2342.19200300.100.1.3"), -+ directoryStr); -+ // PKCS9 e-mail address -+ defDirMap.addNameOID("E", -+ new ObjectIdentifier("1.2.840.113549.1.9.1"), -+ directoryStr); -+ -+ // DC definition from draft-ietf-asid-ldap-domains-02.txt -+ defDirMap.addNameOID("DC", -+ new ObjectIdentifier("0.9.2342.19200300.100.1.25"), -+ directoryStr); -+ -+ // more defined in RFC2459 used in Subject Directory Attr extension -+ defDirMap.addNameOID("SN", // surname -+ new ObjectIdentifier("2.5.4.4"), -+ directoryStr); -+ defDirMap.addNameOID("GIVENNAME", -+ new ObjectIdentifier("2.5.4.42"), -+ directoryStr); -+ defDirMap.addNameOID("INITIALS", -+ new ObjectIdentifier("2.5.4.43"), -+ directoryStr); -+ defDirMap.addNameOID("GENERATIONQUALIFIER", -+ new ObjectIdentifier("2.5.4.44"), -+ directoryStr); -+ defDirMap.addNameOID("DNQUALIFIER", -+ new ObjectIdentifier("2.5.4.46"), -+ directoryStr); -+ -+ // these two added mainly for CEP support -+ // PKCS9 unstructured name -+ defDirMap.addNameOID("UNSTRUCTUREDNAME", -+ new ObjectIdentifier("1.2.840.113549.1.9.2"), -+ directoryStr); -+ // PKCS9 unstructured address -+ defDirMap.addNameOID("UNSTRUCTUREDADDRESS", -+ new ObjectIdentifier("1.2.840.113549.1.9.8"), -+ directoryStr); -+ }; -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X500Signer.java b/org/mozilla/jss/netscape/security/x509/X500Signer.java -new file mode 100644 -index 00000000..41959443 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X500Signer.java -@@ -0,0 +1,110 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.security.NoSuchAlgorithmException; -+import java.security.Signature; -+import java.security.SignatureException; -+ -+/** -+ * This class provides a binding between a Signature object and an -+ * authenticated X.500 name (from an X.509 certificate chain), which -+ * is needed in many public key signing applications. -+ * -+ *

-+ * The name of the signer is important, both because knowing it is the whole point of the signature, and because the -+ * associated X.509 certificate is always used to verify the signature. -+ * -+ *

-+ * The X.509 certificate chain is temporarily not associated with -+ * the signer, but this omission will be resolved. -+ * -+ * @version 1.18 -+ * -+ * @author David Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ */ -+public final class X500Signer { -+ -+ private Signature sig; -+ private X500Name agent; // XXX should be X509CertChain -+ private AlgorithmId algid; -+ -+ /** -+ * Called for each chunk of the data being signed. That -+ * is, you can present the data in many chunks, so that -+ * it doesn't need to be in a single sequential buffer. -+ * -+ * @param buf buffer holding the next chunk of the data to be signed -+ * @param offset starting point of to-be-signed data -+ * @param len how many bytes of data are to be signed -+ * @exception SignatureException on errors. -+ */ -+ public void update(byte buf[], int offset, int len) -+ throws SignatureException { -+ sig.update(buf, offset, len); -+ } -+ -+ /** -+ * Produces the signature for the data processed by update(). -+ * -+ * @exception SignatureException on errors. -+ */ -+ public byte[] sign() throws SignatureException { -+ return sig.sign(); -+ } -+ -+ /** -+ * Returns the algorithm used to sign. -+ */ -+ public AlgorithmId getAlgorithmId() { -+ return algid; -+ } -+ -+ /** -+ * Returns the name of the signing agent. -+ */ -+ public X500Name getSigner() { -+ return agent; -+ } -+ -+ /* -+ * Constructs a binding between a signature and an X500 name -+ * from an X.509 certificate. -+ */ -+ // package private ----hmmmmm ????? -+ public X500Signer(Signature sig, X500Name agent) { -+ if (sig == null || agent == null) -+ throw new IllegalArgumentException("null parameter"); -+ -+ this.sig = sig; -+ this.agent = agent; -+ -+ try { -+ String alg = sig.getAlgorithm(); -+ if (alg.equals("DSA")) { -+ alg = "SHA1withDSA"; -+ } -+ this.algid = AlgorithmId.get(alg); -+ -+ } catch (NoSuchAlgorithmException e) { -+ throw new RuntimeException("internal error! " + e.getMessage()); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X509AttributeName.java b/org/mozilla/jss/netscape/security/x509/X509AttributeName.java -new file mode 100644 -index 00000000..e0591ba6 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X509AttributeName.java -@@ -0,0 +1,64 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+/** -+ * This class is used to parse attribute names like "x509.info.extensions". -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.4 -+ */ -+public class X509AttributeName { -+ // Public members -+ private static final char SEPARATOR = '.'; -+ -+ // Private data members -+ private String prefix = null; -+ private String suffix = null; -+ -+ /** -+ * Default constructor for the class. Name is of the form -+ * "x509.info.extensions". -+ * -+ * @param name the attribute name. -+ */ -+ public X509AttributeName(String name) { -+ int i = name.indexOf(SEPARATOR); -+ if (i == (-1)) { -+ prefix = name; -+ } else { -+ prefix = name.substring(0, i); -+ suffix = name.substring(i + 1); -+ } -+ } -+ -+ /** -+ * Return the prefix of the name. -+ */ -+ public String getPrefix() { -+ return (prefix); -+ } -+ -+ /** -+ * Return the suffix of the name. -+ */ -+ public String getSuffix() { -+ return (suffix); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X509CRLImpl.java b/org/mozilla/jss/netscape/security/x509/X509CRLImpl.java -new file mode 100755 -index 00000000..b88033d6 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X509CRLImpl.java -@@ -0,0 +1,1078 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.OutputStream; -+import java.math.BigInteger; -+import java.security.InvalidKeyException; -+import java.security.NoSuchAlgorithmException; -+import java.security.NoSuchProviderException; -+import java.security.Principal; -+import java.security.PrivateKey; -+import java.security.PublicKey; -+import java.security.Signature; -+import java.security.SignatureException; -+import java.security.cert.CRLException; -+import java.security.cert.Certificate; -+import java.security.cert.X509CRL; -+import java.security.cert.X509CRLEntry; -+import java.security.cert.X509Certificate; -+import java.util.Date; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.LinkedHashSet; -+import java.util.Set; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ *

-+ * An implmentation for X509 CRL (Certificate Revocation List). -+ *

-+ * The X.509 v2 CRL format is described below in ASN.1: -+ * -+ *

-+ * 
-+ *

-+ * CertificateList ::= SEQUENCE { tbsCertList TBSCertList, signatureAlgorithm AlgorithmIdentifier, signature BIT STRING -+ * } -+ *

-+ * A good description and profiling is provided in the IETF PKIX WG draft, Part I: X.509 Certificate and CRL Profile, -+ * <draft-ietf-pkix-ipki-part1-06.txt>. -+ *

-+ * The ASN.1 definition of tbsCertList is: -+ * -+ *

-+ * TBSCertList  ::=  SEQUENCE  {
-+ *     version                 Version OPTIONAL,
-+ *                             -- if present, must be v2
-+ *     signature               AlgorithmIdentifier,
-+ *     issuer                  Name,
-+ *     thisUpdate              ChoiceOfTime,
-+ *     nextUpdate              ChoiceOfTime OPTIONAL,
-+ *     revokedCertificates     SEQUENCE OF SEQUENCE  {
-+ *         userCertificate         CertificateSerialNumber,
-+ *         revocationDate          ChoiceOfTime,
-+ *         crlEntryExtensions      Extensions OPTIONAL
-+ *                                 -- if present, must be v2
-+ *         }  OPTIONAL,
-+ *     crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
-+ *                                  -- if present, must be v2
-+ *     }
-+ * 
-+ * -+ * @author Hemma Prafullchandra -+ * @version 1.8 -+ * @see X509CRL -+ */ -+public class X509CRLImpl extends X509CRL { -+ -+ // CRL data, and its envelope -+ private byte[] signedCRL = null; // DER encoded crl -+ private byte[] signature = null; // raw signature bits -+ private byte[] tbsCertList = null; // DER encoded "to-be-signed" CRL -+ private AlgorithmId sigAlgId; // sig alg in CRL -+ -+ // crl information -+ private int version; -+ private AlgorithmId infoSigAlgId; // sig alg in "to-be-signed" crl -+ private X500Name issuer; -+ private Date thisUpdate = null; -+ private Date nextUpdate = null; -+ // private static final Hashtable revokedCerts = new Hashtable(); -+ private Hashtable revokedCerts = new Hashtable(); -+ // private static CRLExtensions extensions = null; -+ private CRLExtensions extensions = null; -+ private boolean entriesIncluded = true; -+ private final static boolean isExplicit = true; -+ -+ private boolean readOnly = false; -+ -+ /** -+ * Unmarshals an X.509 CRL from its encoded form, parsing the encoded -+ * bytes. This form of constructor is used by agents which -+ * need to examine and use CRL contents. Note that the buffer -+ * must include only one CRL, and no "garbage" may be left at -+ * the end. -+ * -+ * @param crlData the encoded bytes, with no trailing padding. -+ * @exception CRLException on parsing errors. -+ * @exception X509ExtensionException on extension handling errors. -+ */ -+ public X509CRLImpl(byte[] crlData) -+ throws CRLException, X509ExtensionException { -+ try { -+ DerValue in = new DerValue(crlData); -+ -+ parse(in); -+ signedCRL = crlData; -+ } catch (IOException e) { -+ throw new CRLException("Parsing error: " + e.getMessage()); -+ } -+ } -+ -+ public X509CRLImpl(byte[] crlData, boolean includeEntries) -+ throws CRLException, X509ExtensionException { -+ try { -+ entriesIncluded = includeEntries; -+ DerValue in = new DerValue(crlData); -+ -+ parse(in, includeEntries); -+ signedCRL = crlData; -+ } catch (IOException e) { -+ throw new CRLException("Parsing error: " + e.getMessage()); -+ } -+ } -+ -+ /** -+ * Unmarshals an X.509 CRL from an input stream. Only one CRL -+ * is expected at the end of the input stream. -+ * -+ * @param inStrm an input stream holding at least one CRL -+ * @exception CRLException on parsing errors. -+ * @exception X509ExtensionException on extension handling errors. -+ */ -+ public X509CRLImpl(InputStream inStrm) -+ throws CRLException, X509ExtensionException { -+ try { -+ DerValue val = new DerValue(inStrm); -+ -+ parse(val); -+ signedCRL = val.toByteArray(); -+ } catch (IOException e) { -+ throw new CRLException("Parsing error: " + e.getMessage()); -+ } -+ } -+ -+ /** -+ * Initial CRL constructor, no revoked certs, and no extensions. -+ * -+ * @param issuer the name of the CA issuing this CRL. -+ * @param thisUpdate the Date of this issue. -+ * @param nextUpdate the Date of the next CRL. -+ */ -+ public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate) { -+ this.issuer = issuer; -+ this.thisUpdate = thisDate; -+ this.nextUpdate = nextDate; -+ } -+ -+ /** -+ * CRL constructor, revoked certs, no extensions. -+ * -+ * @param issuer the name of the CA issuing this CRL. -+ * @param thisUpdate the Date of this issue. -+ * @param nextUpdate the Date of the next CRL. -+ * @param badCerts the array of revoked certificates. -+ * -+ * @exception CRLException on parsing/construction errors. -+ * @exception X509ExtensionException on extension handling errors. -+ */ -+ public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate, -+ RevokedCertificate[] badCerts) -+ throws CRLException, X509ExtensionException { -+ this.issuer = issuer; -+ this.thisUpdate = thisDate; -+ this.nextUpdate = nextDate; -+ if (badCerts != null) { -+ for (int i = 0; i < badCerts.length; i++) -+ this.revokedCerts.put(badCerts[i].getSerialNumber(), -+ badCerts[i]); -+ } -+ } -+ -+ /** -+ * CRL constructor, revoked certs and extensions. -+ * -+ * @param issuer the name of the CA issuing this CRL. -+ * @param thisUpdate the Date of this issue. -+ * @param nextUpdate the Date of the next CRL. -+ * @param badCerts the array of revoked certificates. -+ * @param crlExts the CRL extensions. -+ * -+ * @exception CRLException on parsing/construction errors. -+ * @exception X509ExtensionException on extension handling errors. -+ */ -+ public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate, -+ RevokedCertificate[] badCerts, CRLExtensions crlExts) -+ throws CRLException, X509ExtensionException { -+ this.issuer = issuer; -+ this.thisUpdate = thisDate; -+ this.nextUpdate = nextDate; -+ if (badCerts != null) { -+ for (int i = 0; i < badCerts.length; i++) { -+ if (badCerts[i] != null) { -+ this.revokedCerts.put(badCerts[i].getSerialNumber(), -+ badCerts[i]); -+ if (badCerts[i].hasExtensions()) -+ this.version = 1; -+ } -+ } -+ } -+ if (crlExts != null) { -+ this.extensions = crlExts; -+ this.version = 1; -+ } -+ } -+ -+ /** -+ * CRL constructor, revoked certs and extensions. -+ * This will be used by code that constructs CRL and uses -+ * encodeInfo() in order to sign it using external means -+ * (other than sign() method) -+ * -+ * @param issuer the name of the CA issuing this CRL. -+ * @param sigAlg signing algorithm id -+ * @param thisUpdate the Date of this issue. -+ * @param nextUpdate the Date of the next CRL. -+ * @param badCerts the array of revoked certificates. -+ * @param crlExts the CRL extensions. -+ */ -+ public X509CRLImpl(X500Name issuer, AlgorithmId algId, Date thisDate, Date nextDate, -+ RevokedCertificate[] badCerts, CRLExtensions crlExts) -+ throws CRLException, X509ExtensionException { -+ this(issuer, thisDate, nextDate, badCerts, crlExts); -+ infoSigAlgId = algId; -+ } -+ -+ /** -+ * CRL constructor, revoked certs and extensions. -+ * -+ * @param issuer the name of the CA issuing this CRL. -+ * @param sigAlg signing algorithm id -+ * @param thisUpdate the Date of this issue. -+ * @param nextUpdate the Date of the next CRL. -+ * @param badCerts the hashtable of revoked certificates. -+ * @param crlExts the CRL extensions. -+ * -+ * @exception CRLException on parsing/construction errors. -+ * @exception X509ExtensionException on extension handling errors. -+ */ -+ public X509CRLImpl(X500Name issuer, AlgorithmId algId, -+ Date thisDate, Date nextDate, -+ Hashtable badCerts, CRLExtensions crlExts) -+ throws CRLException, X509ExtensionException { -+ this.issuer = issuer; -+ this.thisUpdate = thisDate; -+ this.nextUpdate = nextDate; -+ this.revokedCerts = badCerts; -+ if (crlExts != null) { -+ this.extensions = crlExts; -+ this.version = 1; -+ } -+ infoSigAlgId = algId; -+ } -+ -+ /** -+ * Returns the ASN.1 DER encoded form of this CRL. -+ * -+ * @exception CRLException if an encoding error occurs. -+ */ -+ public byte[] getEncoded() throws CRLException { -+ if (signedCRL == null) -+ throw new CRLException("Null CRL to encode"); -+ byte[] dup = new byte[signedCRL.length]; -+ System.arraycopy(signedCRL, 0, dup, 0, dup.length); -+ return dup; -+ } -+ -+ /** -+ * Returns true if signedCRL was set. -+ * -+ * @param byte array of containing signed CRL. -+ */ -+ public boolean setSignedCRL(byte[] crl) { -+ boolean done = false; -+ if (tbsCertList != null && signedCRL == null) { -+ signedCRL = new byte[crl.length]; -+ System.arraycopy(crl, 0, signedCRL, 0, signedCRL.length); -+ done = true; -+ } -+ return done; -+ } -+ -+ public boolean hasUnsupportedCriticalExtension() { -+ // XXX NOT IMPLEMENTED -+ return true; -+ } -+ -+ /** -+ * Encodes the "to-be-signed" CRL to the OutputStream. -+ * -+ * @param out the OutputStream to write to. -+ * @exception CRLException on encoding errors. -+ * @exception X509ExtensionException on extension encoding errors. -+ */ -+ public void encodeInfo(OutputStream out) -+ throws CRLException, X509ExtensionException { -+ try (DerOutputStream seq = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ DerOutputStream rCerts = new DerOutputStream(); -+ -+ if (version != 0) // v2 crl encode version -+ tmp.putInteger(new BigInt(version)); -+ infoSigAlgId.encode(tmp); -+ issuer.encode(tmp); -+ -+ // from 2050 should encode GeneralizedTime -+ tmp.putUTCTime(thisUpdate); -+ -+ if (nextUpdate != null) -+ tmp.putUTCTime(nextUpdate); -+ -+ if (!revokedCerts.isEmpty()) { -+ for (Enumeration e = revokedCerts.elements(); e.hasMoreElements();) -+ ((RevokedCertImpl) e.nextElement()).encode(rCerts); -+ tmp.write(DerValue.tag_Sequence, rCerts); -+ } -+ -+ if (extensions != null) -+ extensions.encode(tmp, isExplicit); -+ -+ seq.write(DerValue.tag_Sequence, tmp); -+ -+ tbsCertList = seq.toByteArray(); -+ out.write(tbsCertList); -+ } catch (IOException e) { -+ throw new CRLException("Encoding error: " + e.getMessage()); -+ } -+ } -+ -+ /** -+ * Verifies that this CRL was signed using the -+ * private key that corresponds to the specified public key. -+ * -+ * @param key the PublicKey used to carry out the verification. -+ * -+ * @exception NoSuchAlgorithmException on unsupported signature -+ * algorithms. -+ * @exception InvalidKeyException on incorrect key. -+ * @exception NoSuchProviderException if there's no default provider. -+ * @exception SignatureException on signature errors. -+ * @exception CRLException on encoding errors. -+ */ -+ public void verify(PublicKey key) -+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException, -+ NoSuchProviderException, SignatureException { -+ String sigProvider = null; -+ verify(key, sigProvider); -+ } -+ -+ /** -+ * Verifies that this CRL was signed using the -+ * private key that corresponds to the specified public key, -+ * and that the signature verification was computed by -+ * the given provider. -+ * -+ * @param key the PublicKey used to carry out the verification. -+ * @param sigProvider the name of the signature provider. -+ * -+ * @exception NoSuchAlgorithmException on unsupported signature -+ * algorithms. -+ * @exception InvalidKeyException on incorrect key. -+ * @exception NoSuchProviderException on incorrect provider. -+ * @exception SignatureException on signature errors. -+ * @exception CRLException on encoding errors. -+ */ -+ public void verify(PublicKey key, String sigProvider) -+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException, -+ NoSuchProviderException, SignatureException { -+ if (signedCRL == null) { -+ throw new CRLException("Uninitialized CRL"); -+ } -+ Signature sigVerf = null; -+ -+ String sigAlg = sigAlgId.getName(); -+ if (sigProvider != null && sigProvider.equals("Mozilla-JSS")) { -+ if (sigAlg.equals("MD5withRSA")) { -+ sigAlg = "MD5/RSA"; -+ } else if (sigAlg.equals("MD2withRSA")) { -+ sigAlg = "MD2/RSA"; -+ } else if (sigAlg.equals("SHA1withRSA")) { -+ sigAlg = "SHA1/RSA"; -+ } else if (sigAlg.equals("SHA1withDSA")) { -+ sigAlg = "SHA1/DSA"; -+ } else if (sigAlg.equals("SHA1withEC")) { -+ sigAlg = "SHA1/EC"; -+ } else if (sigAlg.equals("SHA256withRSA")) { -+ sigAlg = "SHA256/RSA"; -+ } else if (sigAlg.equals("SHA384withRSA")) { -+ sigAlg = "SHA384/RSA"; -+ } else if (sigAlg.equals("SHA512withRSA")) { -+ sigAlg = "SHA512/RSA"; -+ } else if (sigAlg.equals("SHA256withEC")) { -+ sigAlg = "SHA256/EC"; -+ } else if (sigAlg.equals("SHA384withEC")) { -+ sigAlg = "SHA384/EC"; -+ } else if (sigAlg.equals("SHA512withEC")) { -+ sigAlg = "SHA512/EC"; -+ } -+ } -+ sigVerf = Signature.getInstance(sigAlg, sigProvider); -+ sigVerf.initVerify(key); -+ -+ if (tbsCertList == null) -+ throw new CRLException("Uninitialized CRL"); -+ -+ sigVerf.update(tbsCertList, 0, tbsCertList.length); -+ -+ if (!sigVerf.verify(signature)) { -+ throw new CRLException("Signature does not match."); -+ } -+ } -+ -+ /** -+ * Encodes an X.509 CRL, and signs it using the key -+ * passed. -+ * -+ * @param key the private key used for signing. -+ * @param algorithm the name of the signature algorithm used. -+ * -+ * @exception NoSuchAlgorithmException on unsupported signature -+ * algorithms. -+ * @exception InvalidKeyException on incorrect key. -+ * @exception NoSuchProviderException on incorrect provider. -+ * @exception SignatureException on signature errors. -+ * @exception CRLException if any mandatory data was omitted. -+ * @exception X509ExtensionException on any extension errors. -+ */ -+ public void sign(PrivateKey key, String algorithm) -+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException, -+ NoSuchProviderException, SignatureException, X509ExtensionException { -+ sign(key, algorithm, null); -+ } -+ -+ /** -+ * Encodes an X.509 CRL, and signs it using the key -+ * passed. -+ * -+ * @param key the private key used for signing. -+ * @param algorithm the name of the signature algorithm used. -+ * @param provider the name of the provider. -+ * -+ * @exception NoSuchAlgorithmException on unsupported signature -+ * algorithms. -+ * @exception InvalidKeyException on incorrect key. -+ * @exception NoSuchProviderException on incorrect provider. -+ * @exception SignatureException on signature errors. -+ * @exception CRLException if any mandatory data was omitted. -+ * @exception X509ExtensionException on any extension errors. -+ */ -+ public void sign(PrivateKey key, String algorithm, String provider) -+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException, -+ NoSuchProviderException, SignatureException, X509ExtensionException { -+ try (DerOutputStream out = new DerOutputStream()){ -+ if (readOnly) -+ throw new CRLException("cannot over-write existing CRL"); -+ Signature sigEngine = null; -+ if (provider == null) -+ sigEngine = Signature.getInstance(algorithm); -+ else -+ sigEngine = Signature.getInstance(algorithm, provider); -+ -+ sigEngine.initSign(key); -+ -+ // in case the name is reset -+ sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm()); -+ infoSigAlgId = sigAlgId; -+ -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ // encode crl info -+ encodeInfo(tmp); -+ -+ // encode algorithm identifier -+ sigAlgId.encode(tmp); -+ -+ // Create and encode the signature itself. -+ sigEngine.update(tbsCertList, 0, tbsCertList.length); -+ signature = sigEngine.sign(); -+ tmp.putBitString(signature); -+ -+ // Wrap the signed data in a SEQUENCE { data, algorithm, sig } -+ out.write(DerValue.tag_Sequence, tmp); -+ signedCRL = out.toByteArray(); -+ readOnly = true; -+ -+ } catch (IOException e) { -+ throw new CRLException("Error while encoding data: " + -+ e.getMessage()); -+ } -+ } -+ -+ /** -+ * Returns a printable string of this CRL. -+ * -+ * @return value of this CRL in a printable form. -+ */ -+ public String toString() { -+ StringBuffer sb = new StringBuffer("X.509 CRL v" + (version + 1) + "\n" + "Signature Algorithm: " + sigAlgId + -+ ", OID=" + sigAlgId.getOID() + "\n" + "Issuer: " + issuer + "\n" + "\nThis Update: " + thisUpdate -+ + "\n"); -+ if (nextUpdate != null) -+ sb.append("Next Update: " + nextUpdate + "\n"); -+ if (revokedCerts.isEmpty()) -+ sb.append("\nNO certificates have been revoked\n"); -+ else { -+ sb.append("\nRevoked Certificates:\n"); -+ for (Enumeration e = revokedCerts.elements(); e.hasMoreElements();) -+ sb.append(e.nextElement()); -+ } -+ if (extensions != null) { -+ for (int i = 0; i < extensions.size(); i++) { -+ sb.append("\nCRL Extension[" + i + "]: " + extensions.elementAt(i)); -+ } -+ } -+ org.mozilla.jss.netscape.security.util.PrettyPrintFormat pp = -+ new org.mozilla.jss.netscape.security.util.PrettyPrintFormat(" ", 20); -+ String signaturebits = pp.toHexString(signature); -+ sb.append("\nSignature:\n" + signaturebits); -+ -+ return sb.toString(); -+ } -+ -+ /** -+ * Checks whether the given serial number is on this CRL. -+ * -+ * @param serialNumber the number to check for. -+ * @return true if the given serial number is on this CRL, -+ * false otherwise. -+ */ -+ public boolean isRevoked(BigInteger serialNumber) { -+ if (revokedCerts == null || revokedCerts.isEmpty()) -+ return false; -+ return revokedCerts.containsKey(serialNumber); -+ } -+ -+ public boolean isRevoked(Certificate cert) { -+ if (cert == null) -+ return false; -+ if (cert instanceof X509Certificate) { -+ return isRevoked(((X509Certificate) cert).getSerialNumber()); -+ } else { -+ return false; -+ } -+ } -+ -+ /** -+ * Gets the version number from the CRL. -+ * The ASN.1 definition for this is: -+ * -+ *
-+     * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
-+     *             -- v3 does not apply to CRLs but appears for consistency
-+     *             -- with definition of Version for certs
-+     * 
-+ * -+ * @return the version number. -+ */ -+ public int getVersion() { -+ return version; -+ } -+ -+ /** -+ * Gets the issuer distinguished name from this CRL. -+ * The issuer name identifies the entity who has signed (and -+ * issued the CRL). The issuer name field contains an -+ * X.500 distinguished name (DN). -+ * The ASN.1 definition for this is: -+ * -+ *
-+     * issuer    Name
-+     *
-+     * Name ::= CHOICE { RDNSequence }
-+     * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
-+     * RelativeDistinguishedName ::=
-+     *     SET OF AttributeValueAssertion
-+     *
-+     * AttributeValueAssertion ::= SEQUENCE {
-+     *                               AttributeType,
-+     *                               AttributeValue }
-+     * AttributeType ::= OBJECT IDENTIFIER
-+     * AttributeValue ::= ANY
-+     * 
-+ * -+ * The Name describes a hierarchical name composed of attributes, -+ * such as country name, and corresponding values, such as US. -+ * The type of the component AttributeValue is determined by the -+ * AttributeType; in general it will be a directoryString. -+ * A directoryString is usually one of PrintableString, -+ * TeletexString or UniversalString. -+ * -+ * @return the issuer name. -+ */ -+ public Principal getIssuerDN() { -+ return issuer; -+ } -+ -+ /** -+ * Gets the thisUpdate date from the CRL. -+ * The ASN.1 definition for this is: -+ * -+ * @return the thisUpdate date from the CRL. -+ */ -+ public Date getThisUpdate() { -+ return (new Date(thisUpdate.getTime())); -+ } -+ -+ /** -+ * Gets the nextUpdate date from the CRL. -+ * -+ * @return the nextUpdate date from the CRL, or null if -+ * not present. -+ */ -+ public Date getNextUpdate() { -+ if (nextUpdate == null) -+ return null; -+ return (new Date(nextUpdate.getTime())); -+ } -+ -+ /** -+ * Get the revoked certificate from the CRL by the serial -+ * number provided. -+ * -+ * @return the revoked certificate or null if there is -+ * no entry in the CRL marked with the provided serial number. -+ * @see RevokedCertificate -+ */ -+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) { -+ if (revokedCerts == null || revokedCerts.isEmpty()) -+ return null; -+ return revokedCerts.get(serialNumber); -+ } -+ -+ /** -+ * Gets all the revoked certificates from the CRL. -+ * A Set of RevokedCertificate. -+ * -+ * @return all the revoked certificates or null if there are -+ * none. -+ * @see RevokedCertificate -+ */ -+ public Set getRevokedCertificates() { -+ if (revokedCerts == null || revokedCerts.isEmpty()) -+ return null; -+ else { -+ Set certSet = new LinkedHashSet(revokedCerts.values()); -+ return certSet; -+ } -+ } -+ -+ @SuppressWarnings("unchecked") -+ public Hashtable getListOfRevokedCertificates() { -+ if (revokedCerts == null) { -+ return null; -+ } else { -+ return (Hashtable) revokedCerts.clone(); -+ } -+ } -+ -+ public int getNumberOfRevokedCertificates() { -+ if (revokedCerts == null) -+ return -1; -+ else -+ return revokedCerts.size(); -+ } -+ -+ /** -+ * Gets the DER encoded CRL information, the tbsCertList from this CRL. -+ * This can be used to verify the signature independently. -+ * -+ * @return the DER encoded CRL information. -+ * @exception CRLException on parsing errors. -+ * @exception X509ExtensionException on extension parsing errors. -+ */ -+ public byte[] getTBSCertList() -+ throws CRLException { -+ if (tbsCertList == null) -+ throw new CRLException("Uninitialized CRL"); -+ byte[] dup = new byte[tbsCertList.length]; -+ System.arraycopy(tbsCertList, 0, dup, 0, dup.length); -+ return dup; -+ } -+ -+ /** -+ * Gets the raw Signature bits from the CRL. -+ * -+ * @return the signature. -+ */ -+ public byte[] getSignature() { -+ if (signature == null) -+ return null; -+ byte[] dup = new byte[signature.length]; -+ System.arraycopy(signature, 0, dup, 0, dup.length); -+ return dup; -+ } -+ -+ /** -+ * Returns true if signature was set. -+ * -+ * @param byte array of containing CRL signature. -+ */ -+ public boolean setSignature(byte[] crlSignature) { -+ boolean done = false; -+ if (tbsCertList != null && signature == null) { -+ signature = new byte[crlSignature.length]; -+ System.arraycopy(crlSignature, 0, signature, 0, signature.length); -+ done = true; -+ } -+ return done; -+ } -+ -+ /** -+ * Gets the signature algorithm name for the CRL -+ * signature algorithm. For example, the string "SHA1withDSA". -+ * The ASN.1 definition for this is: -+ * -+ *
-+     * AlgorithmIdentifier  ::=  SEQUENCE  {
-+     *     algorithm               OBJECT IDENTIFIER,
-+     *     parameters              ANY DEFINED BY algorithm OPTIONAL  }
-+     *                             -- contains a value of the type
-+     *                             -- registered for use with the
-+     *                             -- algorithm object identifier value
-+     * 
-+ * -+ * @return the signature algorithm name. -+ */ -+ public String getSigAlgName() { -+ if (sigAlgId == null) -+ return null; -+ return sigAlgId.getName(); -+ } -+ -+ /** -+ * Gets the signature algorithm OID string from the CRL. -+ * An OID is represented by a set of positive whole number separated -+ * by ".", that means,
-+ * <positive whole number>.<positive whole number>.<...> -+ * For example, the string "1.2.840.10040.4.3" identifies the SHA-1 -+ * with DSA signature algorithm, as per the PKIX part I. -+ * -+ * @return the signature algorithm oid string. -+ */ -+ public String getSigAlgOID() { -+ if (sigAlgId == null) -+ return null; -+ ObjectIdentifier oid = sigAlgId.getOID(); -+ return oid.toString(); -+ } -+ -+ /** -+ * Gets the DER encoded signature algorithm parameters from this -+ * CRL's signature algorithm. In most cases, the signature -+ * algorithm parameters are null, the parameters are usually -+ * supplied with the Public Key. -+ * -+ * @return the DER encoded signature algorithm parameters, or -+ * null if no parameters are present. -+ */ -+ public byte[] getSigAlgParams() { -+ if (sigAlgId == null) -+ return null; -+ try { -+ return sigAlgId.getEncodedParams(); -+ } catch (IOException e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Gets a Set of the extension(s) marked CRITICAL in the -+ * CRL by OID strings. -+ * -+ * @return a set of the extension oid strings in the -+ * CRL that are marked critical. -+ */ -+ public Set getCriticalExtensionOIDs() { -+ if (extensions == null) -+ return null; -+ Set extSet = new LinkedHashSet(); -+ Extension ex; -+ for (Enumeration e = extensions.getElements(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ if (ex.isCritical()) { -+ extSet.add(ex.getExtensionId().toString()); -+ } -+ } -+ return extSet; -+ } -+ -+ /** -+ * Gets a Set of the extension(s) marked NON-CRITICAL in the -+ * CRL by OID strings. -+ * -+ * @return a set of the extension oid strings in the -+ * CRL that are NOT marked critical. -+ */ -+ public Set getNonCriticalExtensionOIDs() { -+ if (extensions == null) -+ return null; -+ Set extSet = new LinkedHashSet(); -+ Extension ex; -+ for (Enumeration e = extensions.getElements(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ if (!ex.isCritical()) -+ extSet.add(ex.getExtensionId().toString()); -+ } -+ return extSet; -+ } -+ -+ /** -+ * Gets the DER encoded OCTET string for the extension value -+ * (extnValue) identified by the passed in oid String. -+ * The oid string is -+ * represented by a set of positive whole number separated -+ * by ".", that means,
-+ * <positive whole number>.<positive whole number>.<...> -+ * -+ * @param oid the Object Identifier value for the extension. -+ * @return the der encoded octet string of the extension value. -+ */ -+ public byte[] getExtensionValue(String oid) { -+ if (extensions == null) -+ return null; -+ try (DerOutputStream out = new DerOutputStream()) { -+ String extAlias = OIDMap.getName(new ObjectIdentifier(oid)); -+ Extension crlExt = null; -+ -+ if (extAlias == null) { // may be unknown -+ ObjectIdentifier findOID = new ObjectIdentifier(oid); -+ Extension ex = null; -+ ObjectIdentifier inCertOID; -+ for (Enumeration e = extensions.getElements(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ inCertOID = ex.getExtensionId(); -+ if (inCertOID.equals(findOID)) { -+ crlExt = ex; -+ break; -+ } -+ } -+ } else -+ crlExt = extensions.get(extAlias); -+ if (crlExt == null) -+ return null; -+ byte[] extData = crlExt.getExtensionValue(); -+ if (extData == null) -+ return null; -+ -+ out.putOctetString(extData); -+ return out.toByteArray(); -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ public BigInteger getCRLNumber() { -+ try { -+ CRLExtensions exts = getExtensions(); -+ if (exts == null) -+ return null; -+ Enumeration e = exts.getElements(); -+ while (e.hasMoreElements()) { -+ Extension ext = e.nextElement(); -+ if (ext instanceof CRLNumberExtension) { -+ CRLNumberExtension numExt = (CRLNumberExtension) ext; -+ return (BigInteger) numExt.get(CRLNumberExtension.NUMBER); -+ } -+ } -+ } catch (Exception e) { -+ } -+ return null; -+ } -+ -+ public BigInteger getDeltaBaseCRLNumber() { -+ try { -+ CRLExtensions exts = getExtensions(); -+ if (exts == null) -+ return null; -+ Enumeration e = exts.getElements(); -+ while (e.hasMoreElements()) { -+ Extension ext = e.nextElement(); -+ if (ext instanceof DeltaCRLIndicatorExtension) { -+ DeltaCRLIndicatorExtension numExt = (DeltaCRLIndicatorExtension) ext; -+ return (BigInteger) numExt.get(DeltaCRLIndicatorExtension.NUMBER); -+ } -+ } -+ } catch (Exception e) { -+ } -+ return null; -+ } -+ -+ public boolean isDeltaCRL() { -+ try { -+ CRLExtensions exts = getExtensions(); -+ if (exts == null) -+ return false; -+ Enumeration e = exts.getElements(); -+ while (e.hasMoreElements()) { -+ Extension ext = e.nextElement(); -+ if (ext instanceof DeltaCRLIndicatorExtension) { -+ return true; -+ } -+ } -+ } catch (Exception e) { -+ } -+ return false; -+ } -+ -+ /** -+ * Returns extensions for this impl. -+ * -+ * @param extn CRLExtensions -+ */ -+ public CRLExtensions getExtensions() { -+ return extensions; -+ } -+ -+ public boolean areEntriesIncluded() { -+ return entriesIncluded; -+ } -+ -+ /*********************************************************************/ -+ /* -+ * Parses an X.509 CRL, should be used only by constructors. -+ */ -+ private void parse(DerValue val) -+ throws CRLException, IOException, X509ExtensionException { -+ parse(val, true); -+ } -+ -+ private void parse(DerValue val, boolean includeEntries) -+ throws CRLException, IOException, X509ExtensionException { -+ // check if can over write the certificate -+ if (readOnly) -+ throw new CRLException("cannot over-write existing CRL"); -+ -+ readOnly = true; -+ DerValue seq[] = new DerValue[3]; -+ -+ seq[0] = val.data.getDerValue(); -+ seq[1] = val.data.getDerValue(); -+ seq[2] = val.data.getDerValue(); -+ -+ if (val.data.available() != 0) -+ throw new CRLException("signed overrun, bytes = " -+ + val.data.available()); -+ -+ if (seq[0].tag != DerValue.tag_Sequence) -+ throw new CRLException("signed CRL fields invalid"); -+ -+ sigAlgId = AlgorithmId.parse(seq[1]); -+ signature = seq[2].getBitString(); -+ -+ if (seq[1].data.available() != 0) -+ throw new CRLException("AlgorithmId field overrun"); -+ -+ if (seq[2].data.available() != 0) -+ throw new CRLException("Signature field overrun"); -+ -+ // the tbsCertsList -+ tbsCertList = seq[0].toByteArray(); -+ -+ // parse the information -+ DerInputStream derStrm = seq[0].data; -+ DerValue tmp; -+ byte nextByte; -+ -+ // version (optional if v1) -+ version = 0; // by default, version = v1 == 0 -+ nextByte = (byte) derStrm.peekByte(); -+ if (nextByte == DerValue.tag_Integer) { -+ version = derStrm.getInteger().toInt(); -+ if (version != 1) // i.e. v2 -+ throw new CRLException("Invalid version"); -+ } -+ tmp = derStrm.getDerValue(); -+ // signature -+ { -+ AlgorithmId tmpId = AlgorithmId.parse(tmp); -+ if (!tmpId.equals(sigAlgId)) -+ throw new CRLException("Signature algorithm mismatch"); -+ -+ infoSigAlgId = tmpId; -+ } -+ // issuer -+ issuer = new X500Name(derStrm); -+ -+ // thisUpdate -+ // check if UTCTime encoded or GeneralizedTime -+ -+ nextByte = (byte) derStrm.peekByte(); -+ if (nextByte == DerValue.tag_UtcTime) { -+ thisUpdate = derStrm.getUTCTime(); -+ } else if (nextByte == DerValue.tag_GeneralizedTime) { -+ thisUpdate = derStrm.getGeneralizedTime(); -+ } else { -+ throw new CRLException("Invalid encoding for thisUpdate" -+ + " (tag=" + nextByte + ")"); -+ } -+ -+ if (derStrm.available() == 0) -+ return; // done parsing no more optional fields present -+ -+ // nextUpdate (optional) -+ nextByte = (byte) derStrm.peekByte(); -+ if (nextByte == DerValue.tag_UtcTime) { -+ nextUpdate = derStrm.getUTCTime(); -+ } else if (nextByte == DerValue.tag_GeneralizedTime) { -+ nextUpdate = derStrm.getGeneralizedTime(); -+ } // else it is not present -+ -+ if (derStrm.available() == 0) -+ return; // done parsing no more optional fields present -+ -+ // revokedCertificates (optional) -+ nextByte = (byte) derStrm.peekByte(); -+ if ((nextByte == DerValue.tag_SequenceOf) -+ && (!((nextByte & 0x0c0) == 0x080))) { -+ if (includeEntries) { -+ DerValue[] badCerts = derStrm.getSequence(4); -+ for (int i = 0; i < badCerts.length; i++) { -+ RevokedCertImpl entry = new RevokedCertImpl(badCerts[i]); -+ if (entry.hasExtensions() && (version == 0)) -+ throw new CRLException("Invalid encoding, extensions" + -+ " not supported in CRL v1 entries."); -+ -+ revokedCerts.put(entry.getSerialNumber(), -+ entry); -+ } -+ } else { -+ derStrm.skipSequence(4); -+ } -+ } -+ -+ if (derStrm.available() == 0) -+ return; // done parsing no extensions -+ -+ // crlExtensions (optional) -+ tmp = derStrm.getDerValue(); -+ if (tmp.isConstructed() && tmp.isContextSpecific((byte) 0)) { -+ if (version == 0) -+ throw new CRLException("Invalid encoding, extensions not" + -+ " supported in CRL v1."); -+ extensions = new CRLExtensions(tmp.data); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X509Cert.java b/org/mozilla/jss/netscape/security/x509/X509Cert.java -new file mode 100644 -index 00000000..c3f51492 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X509Cert.java -@@ -0,0 +1,846 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.security.Certificate; -+import java.security.InvalidKeyException; -+import java.security.Key; -+import java.security.NoSuchAlgorithmException; -+import java.security.Principal; -+import java.security.PrivateKey; -+import java.security.PublicKey; -+import java.security.Signature; -+import java.security.SignatureException; -+import java.util.Date; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * @author David Brownell -+ * @version 1.5 -+ * -+ * @see CertAndKeyGen -+ * @deprecated Use the new X509Certificate class. -+ * This class is only restored for backwards compatibility. -+ */ -+public class X509Cert implements Certificate, Serializable { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -6968141532738786900L; -+ /* The algorithm id */ -+ protected AlgorithmId algid; -+ -+ /** -+ * Construct a uninitialized X509 Cert on which -+ * decode must later be called (or which may be deserialized). -+ */ -+ // XXX deprecated, delete this -+ public X509Cert() { -+ } -+ -+ /** -+ * Unmarshals a certificate from its encoded form, parsing the -+ * encoded bytes. This form of constructor is used by agents which -+ * need to examine and use certificate contents. That is, this is -+ * one of the more commonly used constructors. Note that the buffer -+ * must include only a certificate, and no "garbage" may be left at -+ * the end. If you need to ignore data at the end of a certificate, -+ * use another constructor. -+ * -+ * @param cert the encoded bytes, with no terminatu (CONSUMED) -+ * @exception IOException when the certificate is improperly encoded. -+ */ -+ public X509Cert( -+ byte cert[]) throws IOException { -+ DerValue in = new DerValue(cert); -+ -+ parse(in); -+ if (in.data.available() != 0) -+ throw new CertParseError("garbage at end"); -+ signedCert = cert; -+ } -+ -+ /** -+ * Unmarshals a certificate from its encoded form, parsing the -+ * encoded bytes. This form of constructor is used by agents which -+ * need to examine and use certificate contents. That is, this is -+ * one of the most commonly used constructors. -+ * -+ * @param buf the buffer holding the encoded bytes -+ * @param offset the offset in the buffer where the bytes begin -+ * @param len how many bytes of certificate exist -+ * -+ * @exception IOException when the certificate is improperly encoded. -+ */ -+ public X509Cert( -+ byte buf[], -+ int offset, -+ int len) throws IOException { -+ DerValue in = new DerValue(buf, offset, len); -+ -+ parse(in); -+ if (in.data.available() != 0) -+ throw new CertParseError("garbage at end"); -+ signedCert = new byte[len]; -+ System.arraycopy(buf, offset, signedCert, 0, len); -+ } -+ -+ /** -+ * Unmarshal a certificate from its encoded form, parsing a DER value. -+ * This form of constructor is used by agents which need to examine -+ * and use certificate contents. -+ * -+ * @param derVal the der value containing the encoded cert. -+ * @exception IOException when the certificate is improperly encoded. -+ */ -+ public X509Cert(DerValue derVal) throws IOException { -+ parse(derVal); -+ if (derVal.data.available() != 0) -+ throw new CertParseError("garbage at end"); -+ signedCert = derVal.toByteArray(); -+ } -+ -+ /** -+ * Partially constructs a certificate from descriptive parameters. -+ * This constructor may be used by Certificate Authority (CA) code, -+ * which later signs and encodes the -+ * certificate. Also, self-signed certificates serve as CA certificates, -+ * and are sometimes used as certificate requests. -+ * -+ *

-+ * Until the certificate has been signed and encoded, some of the mandatory fields in the certificate will not be -+ * available via accessor functions: the serial number, issuer name and signing algorithm, and of course the signed -+ * certificate. The fields passed to this constructor are available, and must be non-null. -+ * -+ *

-+ * Note that the public key being signed is generally independent of the signature algorithm being used. So for -+ * example Diffie-Hellman keys (which do not support signatures) can be placed in X.509 certificates when some other -+ * signature algorithm (e.g. DSS/DSA, or one of the RSA based algorithms) is used. -+ * -+ * @see CertAndKeyGen -+ * -+ * @param subjectName the X.500 distinguished name being certified -+ * @param subjectPublicKey the public key being certified. This -+ * must be an "X509Key" implementing the "PublicKey" interface. -+ * @param notBefore the first time the certificate is valid -+ * @param notAfter the last time the certificate is valid -+ * -+ * @exception CertException if the public key is inappropriate -+ */ -+ public X509Cert( -+ X500Name subjectName, -+ X509Key subjectPublicKey, -+ Date notBefore, -+ Date notAfter) throws CertException { -+ subject = subjectName; -+ -+ if (subjectPublicKey == null) -+ throw new CertException(CertException.err_INVALID_PUBLIC_KEY, -+ "Public Key is NULL"); -+ -+ /* -+ * The X509 cert API requires X509 keys, else things break. -+ */ -+ pubkey = subjectPublicKey; -+ notbefore = notBefore; -+ notafter = notAfter; -+ version = 0; -+ } -+ -+ /** -+ * Decode an X.509 certificate from an input stream. -+ * -+ * @param in an input stream holding at least one certificate -+ * @exception IOException when the certificate is improperly encoded. -+ */ -+ public void decode(InputStream in) throws IOException { -+ DerValue val = new DerValue(in); -+ -+ parse(val); -+ if (val.data.available() != 0) -+ throw new CertParseError("garbage at end"); -+ signedCert = val.toByteArray(); -+ } -+ -+ /** -+ * Appends the certificate to an output stream. -+ * -+ * @param out an input stream to which the certificate is appended. -+ * @exception IOException when appending fails. -+ */ -+ public void encode(OutputStream out) throws IOException { -+ out.write(getSignedCert()); -+ } -+ -+ /** -+ * Compares two certificates. This is false if the -+ * certificates are not both X.509 certs, otherwise it -+ * compares them as binary data. -+ * -+ * @param other the object being compared with this one -+ * @return true iff the certificates are equivalent -+ */ -+ public boolean equals(Object other) { -+ if (other instanceof X509Cert) -+ return equals((X509Cert) other); -+ else -+ return false; -+ } -+ -+ /** -+ * Compares two certificates, returning false if any data -+ * differs between the two. -+ * -+ * @param other the object being compared with this one -+ * @return true iff the certificates are equivalent -+ */ -+ public boolean equals(X509Cert src) { -+ if (this == src) -+ return true; -+ if (signedCert == null || src.signedCert == null) -+ return false; -+ if (signedCert.length != src.signedCert.length) -+ return false; -+ for (int i = 0; i < signedCert.length; i++) -+ if (signedCert[i] != src.signedCert[i]) -+ return false; -+ return true; -+ } -+ -+ /** Returns the "X.509" format identifier. */ -+ public String getFormat() // for Certificate -+ { -+ return "X.509"; -+ } -+ -+ /** Returns getIssuerName */ -+ public Principal getGuarantor() // for Certificate -+ { -+ return getIssuerName(); -+ } -+ -+ /** Returns getSubjectName */ -+ public Principal getPrincipal() { -+ return getSubjectName(); -+ } -+ -+ /** -+ * Throws an exception if the certificate is invalid because it is -+ * now outside of the certificate's validity period, or because it -+ * was not signed using the verification key provided. Successfully -+ * verifying a certificate does not indicate that one should -+ * trust the entity which it represents. -+ * -+ *

-+ * Note that since this class represents only a single X.509 -+ * certificate, it cannot know anything about the certificate chain -+ * which is used to provide the verification key and to establish trust. -+ * Other code must manage and use those cert chains. -+ * -+ *

For now, you must walk the cert chain being used to verify any -+ * given cert. Start at the root, which is a self-signed certificate; -+ * verify it using the key inside the certificate. Then use that to -+ * verify the next certificate in the chain, issued by that CA. In -+ * this manner, verify each certificate until you reach the particular -+ * certificate you wish to verify. You should not use a certificate -+ * if any of the verification operations for its certificate chain -+ * were unsuccessful. -+ * -+ * -+ * @param issuerPublicKey the public key of the issuing CA -+ * @exception CertException when the certificate is not valid. -+ */ -+ public void verify(PublicKey issuerPublicKey) -+ throws CertException { -+ Date now = new Date(); -+ -+ if (now.before(notbefore)) -+ throw new CertException(CertException.verf_INVALID_NOTBEFORE); -+ if (now.after(notafter)) -+ throw new CertException(CertException.verf_INVALID_EXPIRED); -+ if (signedCert == null) -+ throw new CertException(CertException.verf_INVALID_SIG, -+ "?? certificate is not signed yet ??"); -+ -+ // -+ // Verify the signature ... -+ // -+ String algName = null; -+ -+ try { -+ Signature sigVerf = null; -+ -+ algName = issuerSigAlg.getName(); -+ sigVerf = Signature.getInstance(algName); -+ sigVerf.initVerify(issuerPublicKey); -+ sigVerf.update(rawCert, 0, rawCert.length); -+ -+ if (!sigVerf.verify(signature)) { -+ throw new CertException(CertException.verf_INVALID_SIG, -+ "Signature ... by <" + issuer + "> for <" + subject + ">"); -+ } -+ -+ // Gag -- too many catch clauses, let most through. -+ -+ } catch (NoSuchAlgorithmException e) { -+ throw new CertException(CertException.verf_INVALID_SIG, -+ "Unsupported signature algorithm (" + algName + ")"); -+ -+ } catch (InvalidKeyException e) { -+ // e.printStackTrace(); -+ throw new CertException(CertException.err_INVALID_PUBLIC_KEY, -+ "Algorithm (" + algName + ") rejected public key"); -+ -+ } catch (SignatureException e) { -+ throw new CertException(CertException.verf_INVALID_SIG, -+ "Signature by <" + issuer + "> for <" + subject + ">"); -+ } -+ } -+ -+ /** -+ * Creates an X.509 certificate, and signs it using the issuer -+ * passed (associating a signature algorithm and an X.500 name). -+ * This operation is used to implement the certificate generation -+ * functionality of a certificate authority. -+ * -+ * @see #getSignedCert -+ * @see #getSigner -+ * @see CertAndKeyGen -+ * -+ * @param serial the serial number of the certificate (non-null) -+ * @param issuer the certificate issuer (CA) (non-null) -+ * @return the signed certificate, as returned by getSignedCert -+ * -+ * @exception IOException if any of the data could not be encoded, -+ * or when any mandatory data was omitted -+ * @exception SignatureException on signing failures -+ */ -+ public byte[] -+ encodeAndSign( -+ BigInt serial, -+ X500Signer issuer -+ ) throws IOException, SignatureException { -+ rawCert = null; -+ -+ /* -+ * Get the remaining cert parameters, and make sure we have enough. -+ * -+ * We deduce version based on what attribute data are available -+ * For now, we have no attributes, so we always deduce X.509v1 ! -+ */ -+ version = 0; -+ serialnum = serial; -+ this.issuer = issuer.getSigner(); -+ issuerSigAlg = issuer.getAlgorithmId(); -+ -+ if (subject == null || pubkey == null -+ || notbefore == null || notafter == null) -+ throw new IOException("not enough cert parameters"); -+ -+ /* -+ * Encode the raw cert, create its signature and put it -+ * into the envelope. -+ */ -+ rawCert = DERencode(); -+ signedCert = sign(issuer, rawCert); -+ return signedCert; -+ } -+ -+ /** -+ * Returns an X500Signer that may be used to create signatures. Those -+ * signature may in turn be verified using this certificate (or a -+ * copy of it). -+ * -+ *

-+ * NOTE: If the private key is by itself capable of -+ * creating signatures, this fact may not be recognized at this time. -+ * Specifically, the case of DSS/DSA keys which get their algorithm -+ * parameters from higher in the certificate chain is not supportable -+ * without using an X509CertChain API, and there is no current support -+ * for other sources of algorithm parameters. -+ * -+ * @param algorithm the signature algorithm to be used. Note that a -+ * given public/private key pair may support several such algorithms. -+ * @param privateKey the private key used to create the signature, -+ * which must correspond to the public key in this certificate -+ * @return the Signer object -+ * -+ * @exception NoSuchAlgorithmException if the signature -+ * algorithm is not supported -+ * @exception InvalidKeyException if either the key in the certificate, -+ * or the private key parameter, does not support the requested -+ * signature algorithm -+ */ -+ public X500Signer getSigner(AlgorithmId algorithmId, -+ PrivateKey privateKey) -+ throws NoSuchAlgorithmException, InvalidKeyException { -+ String algorithm; -+ Signature sig; -+ -+ if (privateKey != null) { -+ Key key = privateKey; -+ algorithm = key.getAlgorithm(); -+ } else { -+ throw new InvalidKeyException("Private Key is NULL"); -+ } -+ -+ sig = Signature.getInstance(algorithmId.getName()); -+ -+ if (!pubkey.getAlgorithm().equals(algorithm)) { -+ -+ throw new InvalidKeyException("Private key algorithm " + -+ algorithm + -+ " incompatible with certificate " + -+ pubkey.getAlgorithm()); -+ } -+ sig.initSign(privateKey); -+ return new X500Signer(sig, subject); -+ } -+ -+ /** -+ * Returns a signature object that may be used to verify signatures -+ * created using a specified signature algorithm and the public key -+ * contained in this certificate. -+ * -+ *

-+ * NOTE: If the public key in this certificate is not by -+ * itself capable of verifying signatures, this may not be recognized -+ * at this time. Specifically, the case of DSS/DSA keys which get -+ * their algorithm parameters from higher in the certificate chain -+ * is not supportable without using an X509CertChain API, and there -+ * is no current support for other sources of algorithm parameters. -+ * -+ * @param algorithm the algorithm of the signature to be verified -+ * @return the Signature object -+ * @exception NoSuchAlgorithmException if the signature -+ * algorithm is not supported -+ * @exception InvalidKeyException if the key in the certificate -+ * does not support the requested signature algorithm -+ */ -+ public Signature getVerifier(String algorithm) -+ throws NoSuchAlgorithmException, InvalidKeyException { -+ Signature sig; -+ -+ sig = Signature.getInstance(algorithm); -+ sig.initVerify(pubkey); -+ return sig; -+ } -+ -+ /** -+ * Return the signed X.509 certificate as a byte array. -+ * The bytes are in standard DER marshaled form. -+ * Null is returned in the case of a partially constructed cert. -+ */ -+ public byte[] getSignedCert() { -+ return signedCert; -+ } -+ -+ /** -+ * Returns the certificate's serial number. -+ * Null is returned in the case of a partially constructed cert. -+ */ -+ public BigInt getSerialNumber() { -+ return serialnum; -+ } -+ -+ /** -+ * Returns the subject's X.500 distinguished name. -+ */ -+ public X500Name getSubjectName() { -+ return subject; -+ } -+ -+ /** -+ * Returns the certificate issuer's X.500 distinguished name. -+ * Null is returned in the case of a partially constructed cert. -+ */ -+ public X500Name getIssuerName() { -+ return issuer; -+ } -+ -+ /** -+ * Returns the algorithm used by the issuer to sign the certificate. -+ * Null is returned in the case of a partially constructed cert. -+ */ -+ public AlgorithmId getIssuerAlgorithmId() { -+ return issuerSigAlg; -+ } -+ -+ /** -+ * Returns the first time the certificate is valid. -+ */ -+ public Date getNotBefore() { -+ return notbefore; -+ } -+ -+ /** -+ * Returns the last time the certificate is valid. -+ */ -+ public Date getNotAfter() { -+ return notafter; -+ } -+ -+ /** -+ * Returns the subject's public key. Note that some public key -+ * algorithms support an optional certificate generation policy -+ * where the keys in the certificates are not in themselves sufficient -+ * to perform a public key operation. Those keys need to be augmented -+ * by algorithm parameters, which the certificate generation policy -+ * chose not to place in the certificate. -+ * -+ *

-+ * Two such public key algorithms are: DSS/DSA, where algorithm parameters could be acquired from a CA certificate -+ * in the chain of issuers; and Diffie-Hellman, with a similar solution although the CA then needs both a -+ * Diffie-Hellman certificate and a signature capable certificate. -+ */ -+ public PublicKey getPublicKey() { -+ return pubkey; -+ } -+ -+ /** -+ * Returns the X.509 version number of this certificate, zero based. -+ * That is, "2" indicates an X.509 version 3 (1993) certificate, -+ * and "0" indicates X.509v1 (1988). -+ * Zero is returned in the case of a partially constructed cert. -+ */ -+ public int getVersion() { -+ return version; -+ } -+ -+ /** -+ * Calculates a hash code value for the object. Objects -+ * which are equal will also have the same hashcode. -+ */ -+ public int hashCode() { -+ int retval = 0; -+ -+ for (int i = 0; i < signedCert.length; i++) -+ retval += signedCert[i] * i; -+ return retval; -+ } -+ -+ /** -+ * Returns a printable representation of the certificate. This does not -+ * contain all the information available to distinguish this from any -+ * other certificate. The certificate must be fully constructed -+ * before this function may be called; in particular, if you are -+ * creating certificates you must call encodeAndSign() before calling -+ * this function. -+ */ -+ public String toString() { -+ String s; -+ -+ if (subject == null || pubkey == null -+ || notbefore == null || notafter == null -+ || issuer == null || issuerSigAlg == null -+ || serialnum == null) -+ throw new NullPointerException("X.509 cert is incomplete"); -+ -+ s = " X.509v" + (version + 1) + " certificate,\n"; -+ s += " Subject is " + subject + "\n"; -+ s += " Key: " + pubkey; -+ s += " Validity <" + notbefore + "> until <" + notafter + ">\n"; -+ s += " Issuer is " + issuer + "\n"; -+ s += " Issuer signature used " + issuerSigAlg.toString() + "\n"; -+ s += " Serial number = " + serialnum + "\n"; -+ -+ // optional v2, v3 extras -+ -+ return "[\n" + s + "]"; -+ } -+ -+ /** -+ * Returns a printable representation of the certificate. -+ * -+ * @param detailed true iff lots of detail is requested -+ */ -+ public String toString(boolean detailed) { -+ return toString(); -+ } -+ -+ /* -+ * Certificate data, and its envelope -+ */ -+ private byte rawCert[]; -+ private byte signature[]; -+ private byte signedCert[]; -+ -+ /* -+ * X509.v1 data (parsed) -+ */ -+ private X500Name subject; // from subject -+ private X509Key pubkey; -+ -+ private Date notafter; // from CA (constructor) -+ private Date notbefore; -+ -+ private int version; // from CA (signAndEncode) -+ private BigInt serialnum; -+ private X500Name issuer; -+ private AlgorithmId issuerSigAlg; -+ -+ /* -+ * X509.v2 extensions -+ */ -+ -+ /* -+ * X509.v3 extensions -+ */ -+ -+ /* -+ * Other extensions ... Netscape, Verisign, SET, etc -+ */ -+ -+ /************************************************************/ -+ -+ /* -+ * Cert is a SIGNED ASN.1 macro, a three elment sequence: -+ * -+ * - Data to be signed (ToBeSigned) -- the "raw" cert -+ * - Signature algorithm (SigAlgId) -+ * - The signature bits -+ * -+ * This routine unmarshals the certificate, saving the signature -+ * parts away for later verification. -+ */ -+ private void parse(DerValue val) -+ throws IOException { -+ DerValue seq[] = new DerValue[3]; -+ -+ seq[0] = val.data.getDerValue(); -+ seq[1] = val.data.getDerValue(); -+ seq[2] = val.data.getDerValue(); -+ -+ if (val.data.available() != 0) -+ throw new CertParseError("signed overrun, bytes = " -+ + val.data.available()); -+ if (seq[0].tag != DerValue.tag_Sequence) -+ throw new CertParseError("signed fields invalid"); -+ -+ rawCert = seq[0].toByteArray(); // XXX slow; fixme! -+ -+ issuerSigAlg = AlgorithmId.parse(seq[1]); -+ signature = seq[2].getBitString(); -+ -+ if (seq[1].data.available() != 0) { -+ // XXX why was this error check commented out? -+ // It was originally part of the next check. -+ throw new CertParseError("algid field overrun"); -+ } -+ -+ if (seq[2].data.available() != 0) -+ throw new CertParseError("signed fields overrun"); -+ -+ /* -+ * Let's have fun parsing the cert itself. -+ */ -+ DerInputStream in; -+ DerValue tmp; -+ -+ in = seq[0].data; -+ -+ /* -+ * Version -- this is optional (default zero). If it's there it's -+ * the first field and is specially tagged. -+ * -+ * Both branches leave "tmp" holding a value for the serial -+ * number that comes next. -+ */ -+ version = 0; -+ tmp = in.getDerValue(); -+ if (tmp.isConstructed() && tmp.isContextSpecific()) { -+ version = tmp.data.getInteger().toInt(); -+ if (tmp.data.available() != 0) -+ throw new IOException("X.509 version, bad format"); -+ tmp = in.getDerValue(); -+ } -+ -+ /* -+ * serial number ... an integer -+ */ -+ serialnum = tmp.getInteger(); -+ -+ /* -+ * algorithm type for CA's signature ... needs to match the -+ * one on the envelope, and that's about it! different IDs -+ * may represent a signature attack. In general we want to -+ * inherit parameters. -+ */ -+ tmp = in.getDerValue(); -+ { -+ AlgorithmId algid; -+ -+ algid = AlgorithmId.parse(tmp); -+ -+ if (!algid.equals(issuerSigAlg)) -+ throw new CertParseError("CA Algorithm mismatch!"); -+ -+ this.algid = algid; -+ } -+ -+ /* -+ * issuer name -+ */ -+ issuer = new X500Name(in); -+ -+ /* -+ * validity: SEQUENCE { start date, end date } -+ */ -+ tmp = in.getDerValue(); -+ if (tmp.tag != DerValue.tag_Sequence) -+ throw new CertParseError("corrupt validity field"); -+ -+ notbefore = tmp.data.getUTCTime(); -+ notafter = tmp.data.getUTCTime(); -+ if (tmp.data.available() != 0) -+ throw new CertParseError("excess validity data"); -+ -+ /* -+ * subject name and public key -+ */ -+ subject = new X500Name(in); -+ -+ tmp = in.getDerValue(); -+ pubkey = X509Key.parse(tmp); -+ -+ /* -+ * XXX for v2 and later, a bunch of tagged options follow -+ */ -+ -+ if (in.available() != 0) { -+ /* -+ * Until we parse V2/V3 data ... ignore it. -+ * -+ // throw new CertParseError ("excess cert data"); -+ System.out.println ( -+ "@end'o'cert, optional V2/V3 data unparsed: " -+ + in.available () -+ + " bytes" -+ ); -+ */ -+ } -+ } -+ -+ /* -+ * Encode only the parts that will later be signed. -+ */ -+ private byte[] DERencode() throws IOException { -+ DerOutputStream raw = new DerOutputStream(); -+ -+ encode(raw); -+ return raw.toByteArray(); -+ } -+ -+ /* -+ * Marshal the contents of a "raw" certificate into a DER sequence. -+ */ -+ private void encode(DerOutputStream out) throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ /* -+ * encode serial number, issuer signing algorithm, -+ * and issuer name into the data we'll return -+ */ -+ tmp.putInteger(serialnum); -+ issuerSigAlg.encode(tmp); -+ issuer.encode(tmp); -+ -+ /* -+ * Validity is a two element sequence ... encode the -+ * elements, then wrap them into the data we'll return -+ */ -+ { -+ DerOutputStream seq = new DerOutputStream(); -+ -+ seq.putUTCTime(notbefore); -+ seq.putUTCTime(notafter); -+ tmp.write(DerValue.tag_Sequence, seq); -+ } -+ -+ /* -+ * Encode subject (principal) and associated key -+ */ -+ subject.encode(tmp); -+ pubkey.encode(tmp); -+ -+ /* -+ * Wrap the data; encoding of the "raw" cert is now complete. -+ */ -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+ -+ /* -+ * Calculate the signature of the "raw" certificate, -+ * and marshal the cert with the signature and a -+ * description of the signing algorithm. -+ */ -+ private byte[] sign(X500Signer issuer, byte data[]) -+ throws IOException, SignatureException { -+ /* -+ * Encode the to-be-signed data, then the algorithm used -+ * to create the signature. -+ */ -+ try (DerOutputStream out = new DerOutputStream()) { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ tmp.write(data); -+ issuer.getAlgorithmId().encode(tmp); -+ -+ /* -+ * Create and encode the signature itself. -+ */ -+ issuer.update(data, 0, data.length); -+ signature = issuer.sign(); -+ tmp.putBitString(signature); -+ -+ /* -+ * Wrap the signed data in a SEQUENCE { data, algorithm, sig } -+ */ -+ out.write(DerValue.tag_Sequence, tmp); -+ return out.toByteArray(); -+ } -+ } -+ -+ /** -+ * Serialization write ... X.509 certificates serialize as -+ * themselves, and they're parsed when they get read back. -+ * (Actually they serialize as some type data from the -+ * serialization subsystem, then the cert data.) -+ */ -+ private void writeObject(java.io.ObjectOutputStream stream) throws IOException { -+ encode(stream); -+ } -+ -+ /** -+ * Serialization read ... X.509 certificates serialize as -+ * themselves, and they're parsed when they get read back. -+ */ -+ private void readObject(ObjectInputStream stream) throws IOException { -+ decode(stream); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X509CertImpl.java b/org/mozilla/jss/netscape/security/x509/X509CertImpl.java -new file mode 100755 -index 00000000..62fe2113 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X509CertImpl.java -@@ -0,0 +1,1239 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.math.BigInteger; -+import java.security.InvalidKeyException; -+import java.security.NoSuchAlgorithmException; -+import java.security.NoSuchProviderException; -+import java.security.Principal; -+import java.security.PrivateKey; -+import java.security.PublicKey; -+import java.security.Signature; -+import java.security.SignatureException; -+import java.security.cert.CertificateEncodingException; -+import java.security.cert.CertificateException; -+import java.security.cert.CertificateExpiredException; -+import java.security.cert.CertificateFactory; -+import java.security.cert.CertificateNotYetValidException; -+import java.security.cert.CertificateParsingException; -+import java.security.cert.X509Certificate; -+import java.util.Date; -+import java.util.Enumeration; -+import java.util.LinkedHashSet; -+import java.util.Set; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerEncoder; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+import org.mozilla.jss.netscape.security.util.ObjectIdentifier; -+ -+/** -+ * The X509CertImpl class represents an X.509 certificate. These certificates -+ * are widely used to support authentication and other functionality in -+ * Internet security systems. Common applications include Privacy Enhanced -+ * Mail (PEM), Transport Layer Security (SSL), code signing for trusted -+ * software distribution, and Secure Electronic Transactions (SET). There -+ * is a commercial infrastructure ready to manage large scale deployments -+ * of X.509 identity certificates. -+ * -+ *

-+ * These certificates are managed and vouched for by Certificate -+ * Authorities (CAs). CAs are services which create certificates by placing data in the X.509 standard format and -+ * then digitally signing that data. Such signatures are quite difficult to forge. CAs act as trusted third parties, -+ * making introductions between agents who have no direct knowledge of each other. CA certificates are either signed by -+ * themselves, or by some other CA such as a "root" CA. -+ * -+ *

-+ * RFC 1422 is very informative, though it does not describe much of the recent work being done with X.509 certificates. -+ * That includes a 1996 version (X.509v3) and a variety of enhancements being made to facilitate an explosion of -+ * personal certificates used as "Internet Drivers' Licences", or with SET for credit card transactions. -+ * -+ *

-+ * More recent work includes the IETF PKIX Working Group efforts, especially part 1. -+ * -+ * @author Dave Brownell -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.94 97/12/10 -+ * @see X509CertInfo -+ */ -+public class X509CertImpl extends X509Certificate -+ implements Serializable, DerEncoder { -+ // Serialization compatibility with the X509CertImpl in x509v1.jar -+ // supporting the subset of X509Certificate on JDK1.1.x platforms. -+ static final long serialVersionUID = -2048442350420423405L; -+ -+ private static final String DOT = "."; -+ /** -+ * Public attribute names. -+ */ -+ public static final String NAME = "x509"; -+ public static final String INFO = X509CertInfo.NAME; -+ public static final String ALG_ID = "algorithm"; -+ public static final String SIGNATURE = "signature"; -+ public static final String SIGNED_CERT = "signed_cert"; -+ -+ /** -+ * The following are defined for ease-of-use. These -+ * are the most frequently retrieved attributes. -+ */ -+ // x509.info.subject.dname -+ public static final String SUBJECT_DN = NAME + DOT + INFO + DOT + -+ X509CertInfo.SUBJECT + DOT + -+ CertificateSubjectName.DN_NAME; -+ // x509.info.issuer.dname -+ public static final String ISSUER_DN = NAME + DOT + INFO + DOT + -+ X509CertInfo.ISSUER + DOT + -+ CertificateIssuerName.DN_NAME; -+ // x509.info.serialNumber.number -+ public static final String SERIAL_ID = NAME + DOT + INFO + DOT + -+ X509CertInfo.SERIAL_NUMBER + DOT + -+ CertificateSerialNumber.NUMBER; -+ // x509.info.key.value -+ public static final String PUBLIC_KEY = NAME + DOT + INFO + DOT + -+ X509CertInfo.KEY + DOT + -+ CertificateX509Key.KEY; -+ -+ // x509.algorithm -+ public static final String SIG_ALG = NAME + DOT + ALG_ID; -+ -+ // x509.signature -+ public static final String SIG = NAME + DOT + SIGNATURE; -+ -+ // when we sign and decode we set this to true -+ // this is our means to make certificates immutable -+ private boolean readOnly = false; -+ -+ // Certificate data, and its envelope -+ private byte[] signedCert; -+ protected X509CertInfo info = null; -+ protected AlgorithmId algId; -+ protected byte[] signature; -+ -+ // recognized extension OIDS -+ private static final String KEY_USAGE_OID = "2.5.29.15"; -+ private static final String BASIC_CONSTRAINT_OID = "2.5.29.19"; -+ -+ /** -+ * Default constructor. -+ */ -+ public X509CertImpl() { -+ } -+ -+ /** -+ * Unmarshals a certificate from its encoded form, parsing the -+ * encoded bytes. This form of constructor is used by agents which -+ * need to examine and use certificate contents. That is, this is -+ * one of the more commonly used constructors. Note that the buffer -+ * must include only a certificate, and no "garbage" may be left at -+ * the end. If you need to ignore data at the end of a certificate, -+ * use another constructor. -+ * -+ * @param certData the encoded bytes, with no trailing padding. -+ * @exception CertificateException on parsing and initialization errors. -+ */ -+ public X509CertImpl(byte[] certData) -+ throws CertificateException { -+ this(certData, null); -+ } -+ -+ /** -+ * As a special optimization, this constructor acts as X509CertImpl(byte[]) -+ * except that it takes an X509CertInfo which it uses as a 'hint' for -+ * how to construct one field. -+ * -+ * @param certData the encode bytes, with no traiing padding -+ * @param certInfo the certInfo which has already been constructed -+ * from the certData -+ */ -+ -+ public X509CertImpl(byte[] certData, X509CertInfo certInfo) -+ throws CertificateException { -+ -+ // setting info here causes it to skip decoding in the parse() -+ // method -+ info = certInfo; -+ -+ try { -+ DerValue in = new DerValue(certData); -+ -+ parse(in); -+ signedCert = certData; -+ } catch (IOException e) { -+ throw new CertificateException("Unable to initialize, " + e); -+ } -+ } -+ -+ /** -+ * unmarshals an X.509 certificate from an input stream. -+ * -+ * @param in an input stream holding at least one certificate -+ * @exception CertificateException on parsing and initialization errors. -+ */ -+ public X509CertImpl(InputStream in) -+ throws CertificateException { -+ try { -+ DerValue val = new DerValue(in); -+ -+ parse(val); -+ signedCert = val.toByteArray(); -+ } catch (IOException e) { -+ throw new CertificateException("Unable to initialize, " + e); -+ } -+ } -+ -+ /** -+ * Construct an initialized X509 Certificate. The certificate is stored -+ * in raw form and has to be signed to be useful. -+ * -+ * @param certInfo the X509CertificateInfo which the Certificate is to be -+ * created from. -+ */ -+ public X509CertImpl(X509CertInfo certInfo) { -+ this.info = certInfo; -+ } -+ -+ /** -+ * Unmarshal a certificate from its encoded form, parsing a DER value. -+ * This form of constructor is used by agents which need to examine -+ * and use certificate contents. -+ * -+ * @param derVal the der value containing the encoded cert. -+ * @exception CertificateException on parsing and initialization errors. -+ */ -+ public X509CertImpl(DerValue derVal) -+ throws CertificateException { -+ try { -+ parse(derVal); -+ signedCert = derVal.toByteArray(); -+ } catch (IOException e) { -+ throw new CertificateException("Unable to initialize, " + e); -+ } -+ } -+ -+ public boolean hasUnsupportedCriticalExtension() { -+ // XXX NOT IMPLEMENTED -+ return true; -+ } -+ -+ /** -+ * Decode an X.509 certificate from an input stream. -+ * -+ * @param in an input stream holding at least one certificate -+ * @exception CertificateException on parsing errors. -+ * @exception IOException on other errors. -+ */ -+ public void decode(InputStream in) -+ throws CertificateException, IOException { -+ DerValue val = new DerValue(in); -+ -+ parse(val); -+ signedCert = val.toByteArray(); -+ } -+ -+ /** -+ * Appends the certificate to an output stream. -+ * -+ * @param out an input stream to which the certificate is appended. -+ * @exception CertificateEncodingException on encoding errors. -+ */ -+ public void encode(OutputStream out) -+ throws CertificateEncodingException { -+ if (signedCert == null) -+ throw new CertificateEncodingException( -+ "Null certificate to encode"); -+ try { -+ out.write(signedCert); -+ } catch (IOException e) { -+ throw new CertificateEncodingException(e.toString()); -+ } -+ } -+ -+ /** -+ * DER encode this object onto an output stream. -+ * Implements the DerEncoder interface. -+ * -+ * @param out -+ * the output stream on which to write the DER encoding. -+ * -+ * @exception IOException on encoding error. -+ */ -+ public void derEncode(OutputStream out) throws IOException { -+ if (signedCert == null) -+ throw new IOException("Null certificate to encode"); -+ -+ out.write(signedCert); -+ } -+ -+ /** -+ * Returns the encoded form of this certificate. It is -+ * assumed that each certificate type would have only a single -+ * form of encoding; for example, X.509 certificates would -+ * be encoded as ASN.1 DER. -+ * -+ * @exception CertificateEncodingException if an encoding error occurs. -+ */ -+ public byte[] getEncoded() throws CertificateEncodingException { -+ if (signedCert == null) -+ throw new CertificateEncodingException( -+ "Null certificate to encode"); -+ byte[] dup = new byte[signedCert.length]; -+ System.arraycopy(signedCert, 0, dup, 0, dup.length); -+ return dup; -+ } -+ -+ /** -+ * Throws an exception if the certificate was not signed using the -+ * verification key provided. Successfully verifying a certificate -+ * does not indicate that one should trust the entity which -+ * it represents. -+ * -+ * @param key the public key used for verification. -+ * -+ * @exception InvalidKeyException on incorrect key. -+ * @exception NoSuchAlgorithmException on unsupported signature -+ * algorithms. -+ * @exception NoSuchProviderException if there's no default provider. -+ * @exception SignatureException on signature errors. -+ * @exception CertificateException on encoding errors. -+ */ -+ public void verify(PublicKey key) -+ throws CertificateException, NoSuchAlgorithmException, -+ InvalidKeyException, NoSuchProviderException, SignatureException { -+ String sigProvider = null; -+ verify(key, sigProvider); -+ } -+ -+ /** -+ * Throws an exception if the certificate was not signed using the -+ * verification key provided. Successfully verifying a certificate -+ * does not indicate that one should trust the entity which -+ * it represents. -+ * -+ * @param key the public key used for verification. -+ * @param sigProvider the name of the provider. -+ * -+ * @exception NoSuchAlgorithmException on unsupported signature -+ * algorithms. -+ * @exception InvalidKeyException on incorrect key. -+ * @exception NoSuchProviderException on incorrect provider. -+ * @exception SignatureException on signature errors. -+ * @exception CertificateException on encoding errors. -+ */ -+ public void verify(PublicKey key, String sigProvider) -+ throws CertificateException, NoSuchAlgorithmException, -+ InvalidKeyException, NoSuchProviderException, SignatureException { -+ if (signedCert == null) { -+ throw new CertificateEncodingException("Uninitialized certificate"); -+ } -+ // Verify the signature ... -+ Signature sigVerf = null; -+ -+ sigVerf = Signature.getInstance(algId.getName(), sigProvider); -+ sigVerf.initVerify(key); -+ -+ byte[] rawCert = info.getEncodedInfo(); -+ sigVerf.update(rawCert, 0, rawCert.length); -+ -+ if (!sigVerf.verify(signature)) { -+ throw new SignatureException("Signature does not match."); -+ } -+ } -+ -+ /** -+ * Creates an X.509 certificate, and signs it using the key -+ * passed (associating a signature algorithm and an X.500 name). -+ * This operation is used to implement the certificate generation -+ * functionality of a certificate authority. -+ * -+ * @param key the private key used for signing. -+ * @param algorithm the name of the signature algorithm used. -+ * -+ * @exception InvalidKeyException on incorrect key. -+ * @exception NoSuchAlgorithmException on unsupported signature -+ * algorithms. -+ * @exception NoSuchProviderException if there's no default provider. -+ * @exception SignatureException on signature errors. -+ * @exception CertificateException on encoding errors. -+ */ -+ public void sign(PrivateKey key, String algorithm) -+ throws CertificateException, NoSuchAlgorithmException, -+ InvalidKeyException, NoSuchProviderException, SignatureException { -+ sign(key, algorithm, null); -+ } -+ -+ /** -+ * Creates an X.509 certificate, and signs it using the key -+ * passed (associating a signature algorithm and an X.500 name). -+ * This operation is used to implement the certificate generation -+ * functionality of a certificate authority. -+ * -+ * @param key the private key used for signing. -+ * @param algorithm the name of the signature algorithm used. -+ * @param provider the name of the provider. -+ * -+ * @exception NoSuchAlgorithmException on unsupported signature -+ * algorithms. -+ * @exception InvalidKeyException on incorrect key. -+ * @exception NoSuchProviderException on incorrect provider. -+ * @exception SignatureException on signature errors. -+ * @exception CertificateException on encoding errors. -+ */ -+ public void sign(PrivateKey key, String algorithm, String provider) -+ throws CertificateException, NoSuchAlgorithmException, -+ InvalidKeyException, NoSuchProviderException, SignatureException { -+ try (DerOutputStream out = new DerOutputStream()){ -+ if (readOnly) -+ throw new CertificateEncodingException( -+ "cannot over-write existing certificate"); -+ Signature sigEngine = null; -+ if (provider == null) -+ sigEngine = Signature.getInstance(algorithm); -+ else -+ sigEngine = Signature.getInstance(algorithm, provider); -+ -+ sigEngine.initSign(key); -+ -+ // in case the name is reset -+ algId = AlgorithmId.get(sigEngine.getAlgorithm()); -+ -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ // encode certificate info -+ info.encode(tmp); -+ byte[] rawCert = tmp.toByteArray(); -+ -+ // encode algorithm identifier -+ algId.encode(tmp); -+ -+ // Create and encode the signature itself. -+ sigEngine.update(rawCert, 0, rawCert.length); -+ signature = sigEngine.sign(); -+ tmp.putBitString(signature); -+ -+ // Wrap the signed data in a SEQUENCE { data, algorithm, sig } -+ out.write(DerValue.tag_Sequence, tmp); -+ signedCert = out.toByteArray(); -+ readOnly = true; -+ -+ } catch (IOException e) { -+ throw new CertificateEncodingException(e.toString()); -+ } -+ } -+ -+ /** -+ * Checks that the certificate is currently valid, i.e. the current -+ * time is within the specified validity period. -+ * -+ * @exception CertificateExpiredException if the certificate has expired. -+ * @exception CertificateNotYetValidException if the certificate is not -+ * yet valid. -+ */ -+ public void checkValidity() -+ throws CertificateExpiredException, CertificateNotYetValidException { -+ Date date = new Date(); -+ checkValidity(date); -+ } -+ -+ /** -+ * Checks that the specified date is within the certificate's -+ * validity period, or basically if the certificate would be -+ * valid at the specified date/time. -+ * -+ * @param date the Date to check against to see if this certificate -+ * is valid at that date/time. -+ * -+ * @exception CertificateExpiredException if the certificate has expired -+ * with respect to the date supplied. -+ * @exception CertificateNotYetValidException if the certificate is not -+ * yet valid with respect to the date supplied. -+ */ -+ public void checkValidity(Date date) -+ throws CertificateExpiredException, CertificateNotYetValidException { -+ -+ CertificateValidity interval = null; -+ try { -+ interval = (CertificateValidity) info.get(CertificateValidity.NAME); -+ } catch (Exception e) { -+ throw new CertificateNotYetValidException("Incorrect validity period"); -+ } -+ if (interval == null) -+ throw new CertificateNotYetValidException("Null validity period"); -+ interval.valid(date); -+ } -+ -+ /** -+ * Return the requested attribute from the certificate. -+ * -+ * @param name the name of the attribute. -+ * @exception CertificateParsingException on invalid attribute identifier. -+ */ -+ public Object get(String name) -+ throws CertificateParsingException { -+ X509AttributeName attr = new X509AttributeName(name); -+ String id = attr.getPrefix(); -+ if (!(id.equalsIgnoreCase(NAME))) { -+ throw new CertificateParsingException("Invalid root of " -+ + "attribute name, expected [" + NAME + -+ "], received " + "[" + id + "]"); -+ } -+ attr = new X509AttributeName(attr.getSuffix()); -+ id = attr.getPrefix(); -+ -+ if (id.equalsIgnoreCase(INFO)) { -+ if (attr.getSuffix() != null) { -+ try { -+ return info.get(attr.getSuffix()); -+ } catch (IOException e) { -+ throw new CertificateParsingException(e.toString()); -+ } catch (CertificateException e) { -+ throw new CertificateParsingException(e.toString()); -+ } -+ } else { -+ return (info); -+ } -+ } else if (id.equalsIgnoreCase(ALG_ID)) { -+ return (algId); -+ } else if (id.equalsIgnoreCase(SIGNATURE)) { -+ return (signature); -+ } else if (id.equalsIgnoreCase(SIGNED_CERT)) { -+ return (signedCert); -+ } else { -+ throw new CertificateParsingException("Attribute name not " -+ + "recognized or get() not allowed for the same: " + id); -+ } -+ } -+ -+ /** -+ * Set the requested attribute in the certificate. -+ * -+ * @param name the name of the attribute. -+ * @param obj the value of the attribute. -+ * @exception CertificateException on invalid attribute identifier. -+ * @exception IOException on encoding error of attribute. -+ */ -+ public void set(String name, Object obj) -+ throws CertificateException, IOException { -+ // check if immutable -+ if (readOnly) -+ throw new CertificateException("cannot over-write existing" -+ + " certificate"); -+ -+ X509AttributeName attr = new X509AttributeName(name); -+ String id = attr.getPrefix(); -+ if (!(id.equalsIgnoreCase(NAME))) { -+ throw new CertificateException("Invalid root of attribute name," -+ + " expected [" + NAME + "], received " + id); -+ } -+ attr = new X509AttributeName(attr.getSuffix()); -+ id = attr.getPrefix(); -+ -+ if (id.equalsIgnoreCase(INFO)) { -+ if (attr.getSuffix() == null) { -+ if (!(obj instanceof X509CertInfo)) { -+ throw new CertificateException("Attribute value should" -+ + " be of type X509CertInfo."); -+ } -+ info = (X509CertInfo) obj; -+ signedCert = null; //reset this as certificate data has changed -+ } else { -+ info.set(attr.getSuffix(), obj); -+ signedCert = null; //reset this as certificate data has changed -+ } -+ } else { -+ throw new CertificateException("Attribute name not recognized or " + -+ "set() not allowed for the same: " + id); -+ } -+ } -+ -+ /** -+ * Delete the requested attribute from the certificate. -+ * -+ * @param name the name of the attribute. -+ * @exception CertificateException on invalid attribute identifier. -+ * @exception IOException on other errors. -+ */ -+ public void delete(String name) -+ throws CertificateException, IOException { -+ // check if immutable -+ if (readOnly) -+ throw new CertificateException("cannot over-write existing" -+ + " certificate"); -+ -+ X509AttributeName attr = new X509AttributeName(name); -+ String id = attr.getPrefix(); -+ if (!(id.equalsIgnoreCase(NAME))) { -+ throw new CertificateException("Invalid root of attribute name," -+ + " expected [" -+ + NAME + "], received " + id); -+ } -+ attr = new X509AttributeName(attr.getSuffix()); -+ id = attr.getPrefix(); -+ -+ if (id.equalsIgnoreCase(INFO)) { -+ if (attr.getSuffix() != null) { -+ info = null; -+ } else { -+ info.delete(attr.getSuffix()); -+ } -+ } else if (id.equalsIgnoreCase(ALG_ID)) { -+ algId = null; -+ } else if (id.equalsIgnoreCase(SIGNATURE)) { -+ signature = null; -+ } else if (id.equalsIgnoreCase(SIGNED_CERT)) { -+ signedCert = null; -+ } else { -+ throw new CertificateException("Attribute name not recognized or " + -+ "delete() not allowed for the same: " + id); -+ } -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getElements() { -+ Vector elements = new Vector(); -+ elements.addElement(NAME + DOT + INFO); -+ elements.addElement(NAME + DOT + ALG_ID); -+ elements.addElement(NAME + DOT + SIGNATURE); -+ elements.addElement(NAME + DOT + SIGNED_CERT); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ /** -+ * Returns a printable representation of the certificate. This does not -+ * contain all the information available to distinguish this from any -+ * other certificate. The certificate must be fully constructed -+ * before this function may be called. -+ */ -+ public String toString() { -+ if (info == null || algId == null || signature == null) -+ return ""; -+ -+ StringBuffer sb = new StringBuffer("[\n"+info.toString() + "\n" + " Algorithm: [" + algId.toString() + "]\n"); -+ -+ org.mozilla.jss.netscape.security.util.PrettyPrintFormat pp = -+ new org.mozilla.jss.netscape.security.util.PrettyPrintFormat(" ", 20); -+ String signaturebits = pp.toHexString(signature); -+ sb.append(" Signature:\n" + signaturebits); -+ sb.append("]"); -+ -+ return sb.toString(); -+ } -+ -+ // the strongly typed gets, as per java.security.cert.X509Certificate -+ -+ /** -+ * Gets the publickey from this certificate. -+ * -+ * @return the publickey. -+ */ -+ public PublicKey getPublicKey() { -+ if (info == null) -+ return null; -+ try { -+ PublicKey key = (PublicKey) info.get(CertificateX509Key.NAME -+ + DOT + CertificateX509Key.KEY); -+ return key; -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Gets the version number from the certificate. -+ * -+ * @return the version number. -+ */ -+ public int getVersion() { -+ if (info == null) -+ return -1; -+ try { -+ int vers = ((Integer) info.get(CertificateVersion.NAME -+ + DOT + CertificateVersion.VERSION)).intValue(); -+ return vers; -+ } catch (Exception e) { -+ return -1; -+ } -+ } -+ -+ /** -+ * Gets the serial number from the certificate. -+ * -+ * @return the serial number. -+ */ -+ public BigInteger getSerialNumber() { -+ if (info == null) -+ return null; -+ try { -+ SerialNumber ser = (SerialNumber) info.get( -+ CertificateSerialNumber.NAME + DOT + -+ CertificateSerialNumber.NUMBER); -+ return ser.getNumber().toBigInteger(); -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Gets the subject distinguished name from the certificate. -+ * -+ * @return the subject name. -+ */ -+ public Principal getSubjectDN() { -+ if (info == null) -+ return null; -+ try { -+ Principal subject = (Principal) info.get( -+ CertificateSubjectName.NAME + DOT + -+ CertificateSubjectName.DN_NAME); -+ return subject; -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ public CertificateSubjectName getSubjectObj() { -+ return info.getSubjectObj(); -+ } -+ -+ public X509CertInfo getInfo() { -+ return info; -+ } -+ -+ /** -+ * Gets the issuer distinguished name from the certificate. -+ * -+ * @return the issuer name. -+ */ -+ public Principal getIssuerDN() { -+ if (info == null) -+ return null; -+ try { -+ Principal issuer = (Principal) info.get( -+ CertificateIssuerName.NAME + DOT + -+ CertificateIssuerName.DN_NAME); -+ return issuer; -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ public CertificateIssuerName getIssuerObj() { -+ return info.getIssuerObj(); -+ } -+ -+ /** -+ * Gets the notBefore date from the validity period of the certificate. -+ * -+ * @return the start date of the validity period. -+ */ -+ public Date getNotBefore() { -+ if (info == null) -+ return null; -+ try { -+ Date d = (Date) info.get(CertificateValidity.NAME + DOT + -+ CertificateValidity.NOT_BEFORE); -+ return d; -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Gets the notAfter date from the validity period of the certificate. -+ * -+ * @return the end date of the validity period. -+ */ -+ public Date getNotAfter() { -+ if (info == null) -+ return null; -+ try { -+ Date d = (Date) info.get(CertificateValidity.NAME + DOT + -+ CertificateValidity.NOT_AFTER); -+ return d; -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Gets the DER encoded certificate informations, the tbsCertificate from this certificate. -+ * This can be used to verify the signature independently. -+ * -+ * @return the DER encoded certificate information. -+ * @exception CertificateEncodingException if an encoding error occurs. -+ */ -+ public byte[] getTBSCertificate() throws CertificateEncodingException { -+ if (info != null) { -+ return info.getEncodedInfo(); -+ } else -+ throw new CertificateEncodingException("Uninitialized certificate"); -+ } -+ -+ /** -+ * Gets the raw Signature bits from the certificate. -+ * -+ * @return the signature. -+ */ -+ public byte[] getSignature() { -+ if (signature == null) -+ return null; -+ byte[] dup = new byte[signature.length]; -+ System.arraycopy(signature, 0, dup, 0, dup.length); -+ return dup; -+ } -+ -+ /** -+ * Gets the signature algorithm name for the certificate -+ * signature algorithm. -+ * For example, the string "SHA-1/DSA" or "DSS". -+ * -+ * @return the signature algorithm name. -+ */ -+ public String getSigAlgName() { -+ if (algId == null) -+ return null; -+ return (algId.getName()); -+ } -+ -+ /** -+ * Gets the signature algorithm OID string from the certificate. -+ * For example, the string "1.2.840.10040.4.3" -+ * -+ * @return the signature algorithm oid string. -+ */ -+ public String getSigAlgOID() { -+ if (algId == null) -+ return null; -+ ObjectIdentifier oid = algId.getOID(); -+ return (oid.toString()); -+ } -+ -+ /** -+ * Gets the DER encoded signature algorithm parameters from this -+ * certificate's signature algorithm. -+ * -+ * @return the DER encoded signature algorithm parameters, or -+ * null if no parameters are present. -+ */ -+ public byte[] getSigAlgParams() { -+ if (algId == null) -+ return null; -+ try { -+ return algId.getEncodedParams(); -+ } catch (IOException e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Gets the Issuer Unique Identity from the certificate. -+ * -+ * @return the Issuer Unique Identity. -+ */ -+ public boolean[] getIssuerUniqueID() { -+ if (info == null) -+ return null; -+ try { -+ UniqueIdentity id = (UniqueIdentity) info.get( -+ CertificateIssuerUniqueIdentity.NAME -+ + DOT + CertificateIssuerUniqueIdentity.ID); -+ if (id == null) -+ return null; -+ else -+ return (id.getId()); -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Gets the Subject Unique Identity from the certificate. -+ * -+ * @return the Subject Unique Identity. -+ */ -+ public boolean[] getSubjectUniqueID() { -+ if (info == null) -+ return null; -+ try { -+ UniqueIdentity id = (UniqueIdentity) info.get( -+ CertificateSubjectUniqueIdentity.NAME -+ + DOT + CertificateSubjectUniqueIdentity.ID); -+ if (id == null) -+ return null; -+ else -+ return (id.getId()); -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Gets a Set of the extension(s) marked CRITICAL in the -+ * certificate by OID strings. -+ * -+ * @return a set of the extension oid strings in the -+ * certificate that are marked critical. -+ */ -+ public Set getCriticalExtensionOIDs() { -+ if (info == null) -+ return null; -+ try { -+ CertificateExtensions exts = (CertificateExtensions) info.get( -+ CertificateExtensions.NAME); -+ if (exts == null) -+ return null; -+ Set extSet = new LinkedHashSet(); -+ Extension ex; -+ for (Enumeration e = exts.getAttributes(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ if (ex.isCritical()) -+ extSet.add(ex.getExtensionId().toString()); -+ } -+ return extSet; -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Gets a Set of the extension(s) marked NON-CRITICAL in the -+ * certificate by OID strings. -+ * -+ * @return a set of the extension oid strings in the -+ * certificate that are NOT marked critical. -+ */ -+ public Set getNonCriticalExtensionOIDs() { -+ if (info == null) -+ return null; -+ try { -+ CertificateExtensions exts = (CertificateExtensions) info.get( -+ CertificateExtensions.NAME); -+ if (exts == null) -+ return null; -+ -+ Set extSet = new LinkedHashSet(); -+ Extension ex; -+ for (Enumeration e = exts.getAttributes(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ if (!ex.isCritical()) -+ extSet.add(ex.getExtensionId().toString()); -+ } -+ return extSet; -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ public Extension getExtension(String oid) { -+ try { -+ CertificateExtensions exts = (CertificateExtensions) info.get( -+ CertificateExtensions.NAME); -+ if (exts == null) -+ return null; -+ ObjectIdentifier findOID = new ObjectIdentifier(oid); -+ Extension ex = null; -+ ; -+ ObjectIdentifier inCertOID; -+ for (Enumeration e = exts.getAttributes(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ inCertOID = ex.getExtensionId(); -+ if (inCertOID.equals(findOID)) { -+ return ex; -+ } -+ } -+ } catch (Exception e) { -+ } -+ return null; -+ } -+ -+ /** -+ * Gets the DER encoded extension identified by the passed -+ * in oid String. -+ * -+ * @param oid the Object Identifier value for the extension. -+ */ -+ public byte[] getExtensionValue(String oid) { -+ DerOutputStream out = null; -+ try { -+ String extAlias = OIDMap.getName(new ObjectIdentifier(oid)); -+ Extension certExt = null; -+ -+ if (extAlias == null) { // may be unknown -+ // get the extensions, search thru' for this oid -+ CertificateExtensions exts = (CertificateExtensions) info.get( -+ CertificateExtensions.NAME); -+ if (exts == null) -+ return null; -+ -+ ObjectIdentifier findOID = new ObjectIdentifier(oid); -+ Extension ex = null; -+ ; -+ ObjectIdentifier inCertOID; -+ for (Enumeration e = exts.getAttributes(); e.hasMoreElements();) { -+ ex = e.nextElement(); -+ inCertOID = ex.getExtensionId(); -+ if (inCertOID.equals(findOID)) { -+ certExt = ex; -+ break; -+ } -+ } -+ } else { // there's sub-class that can handle this extension -+ certExt = (Extension) this.get(extAlias); -+ } -+ if (certExt == null) -+ return null; -+ byte[] extData = certExt.getExtensionValue(); -+ if (extData == null) -+ return null; -+ -+ out = new DerOutputStream(); -+ out.putOctetString(extData); -+ return out.toByteArray(); -+ } catch (Exception e) { -+ return null; -+ } finally { -+ if (out != null) { -+ try { -+ out.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ -+ /** -+ * Get a boolean array representing the bits of the KeyUsage extension, -+ * (oid = 2.5.29.15). -+ * -+ * @return the bit values of this extension as an array of booleans. -+ */ -+ public boolean[] getKeyUsage() { -+ try { -+ String extAlias = OIDMap.getName(new ObjectIdentifier( -+ KEY_USAGE_OID)); -+ if (extAlias == null) -+ return null; -+ -+ KeyUsageExtension certExt = (KeyUsageExtension) this.get(extAlias); -+ if (certExt == null) -+ return null; -+ -+ return certExt.getBits(); -+ } catch (Exception e) { -+ return null; -+ } -+ } -+ -+ /** -+ * Get the certificate constraints path length from the -+ * the critical BasicConstraints extension, (oid = 2.5.29.19). -+ * -+ * @return the length of the constraint. -+ */ -+ public int getBasicConstraints() { -+ try { -+ String extAlias = OIDMap.getName(new ObjectIdentifier( -+ BASIC_CONSTRAINT_OID)); -+ if (extAlias == null) -+ return -1; -+ BasicConstraintsExtension certExt = -+ (BasicConstraintsExtension) this.get(extAlias); -+ if (certExt == null) -+ return -1; -+ -+ if (((Boolean) certExt.get(BasicConstraintsExtension.IS_CA)).booleanValue() == true) -+ return ((Integer) certExt.get( -+ BasicConstraintsExtension.PATH_LEN)).intValue(); -+ else -+ return -1; -+ } catch (Exception e) { -+ return -1; -+ } -+ } -+ -+ public boolean getBasicConstraintsIsCA() { -+ boolean isCA = false; -+ try { -+ String extAlias = OIDMap.getName(new ObjectIdentifier( -+ BASIC_CONSTRAINT_OID)); -+ if (extAlias == null) -+ return false; -+ -+ BasicConstraintsExtension certExt = -+ (BasicConstraintsExtension) this.get(extAlias); -+ if (certExt == null) -+ return false; -+ -+ isCA = ((Boolean) certExt.get(BasicConstraintsExtension.IS_CA)).booleanValue(); -+ } catch (Exception e) { -+ return false; -+ } -+ return isCA; -+ } -+ -+ /************************************************************/ -+ -+ /* -+ * Cert is a SIGNED ASN.1 macro, a three elment sequence: -+ * -+ * - Data to be signed (ToBeSigned) -- the "raw" cert -+ * - Signature algorithm (SigAlgId) -+ * - The signature bits -+ * -+ * This routine unmarshals the certificate, saving the signature -+ * parts away for later verification. -+ */ -+ private void parse(DerValue val) throws CertificateException, IOException { -+ // check if can over write the certificate -+ if (readOnly) -+ throw new CertificateParsingException( -+ "cannot over-write existing certificate"); -+ -+ readOnly = true; -+ DerValue seq[] = new DerValue[3]; -+ -+ seq[0] = val.data.getDerValue(); -+ seq[1] = val.data.getDerValue(); -+ seq[2] = val.data.getDerValue(); -+ -+ if (val.data.available() != 0) { -+ throw new CertificateParsingException("signed overrun, bytes = " -+ + val.data.available()); -+ } -+ if (seq[0].tag != DerValue.tag_Sequence) { -+ throw new CertificateParsingException("signed fields invalid"); -+ } -+ -+ algId = AlgorithmId.parse(seq[1]); -+ signature = seq[2].getBitString(); -+ -+ if (seq[1].data.available() != 0) { -+ throw new CertificateParsingException("algid field overrun"); -+ } -+ if (seq[2].data.available() != 0) -+ throw new CertificateParsingException("signed fields overrun"); -+ -+ // The CertificateInfo -+ if (info == null) { -+ info = new X509CertInfo(seq[0]); -+ } -+ } -+ -+ /** -+ * Serialization write ... X.509 certificates serialize as -+ * themselves, and they're parsed when they get read back. -+ * (Actually they serialize as some type data from the -+ * serialization subsystem, then the cert data.) -+ */ -+ private void writeObject(ObjectOutputStream stream) throws CertificateException, IOException { -+ encode(stream); -+ } -+ -+ /** -+ * Serialization read ... X.509 certificates serialize as -+ * themselves, and they're parsed when they get read back. -+ */ -+ private void readObject(ObjectInputStream stream) throws CertificateException, IOException { -+ decode(stream); -+ } -+ -+ protected static class CertificateRep1 implements java.io.Serializable { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -5207881613631592409L; -+ private String type1; -+ private byte[] data1; -+ -+ /** -+ * Construct the alternate Certificate class with the Certificate -+ * type and Certificate encoding bytes. -+ * -+ *

-+ * -+ * @param type the standard name of the Certificate type. -+ *

-+ * -+ * @param data the Certificate data. -+ */ -+ protected CertificateRep1(String type, byte[] data) { -+ this.type1 = type; -+ this.data1 = data; -+ } -+ -+ /** -+ * Resolve the Certificate Object. -+ * -+ *

-+ * -+ * @return the resolved Certificate Object. -+ * -+ * @throws java.io.ObjectStreamException if the Certificate could not -+ * be resolved. -+ */ -+ protected Object readResolve() throws java.io.ObjectStreamException { -+ try { -+ @SuppressWarnings("unused") -+ CertificateFactory cf = CertificateFactory.getInstance(type1); // check for errors -+ return new X509CertImpl(data1); -+ -+ /* -+ return cf.generateCertificate -+ (new java.io.ByteArrayInputStream(data1)); -+ */ -+ } catch (CertificateException e) { -+ throw new java.io.NotSerializableException("java.security.cert.Certificate: " + -+ type1 + -+ ": " + -+ e.getMessage()); -+ } -+ } -+ -+ } -+ -+ protected Object writeReplace() throws java.io.ObjectStreamException { -+ try { -+ return new CertificateRep1("X.509", getEncoded()); -+ } catch (CertificateException e) { -+ throw new java.io.NotSerializableException("java.security.cert.Certificate: " + -+ "X.509" + -+ ": " + -+ e.getMessage()); -+ } -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X509CertInfo.java b/org/mozilla/jss/netscape/security/x509/X509CertInfo.java -new file mode 100644 -index 00000000..ea565d9d ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X509CertInfo.java -@@ -0,0 +1,976 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.io.ObjectOutputStream; -+import java.io.OutputStream; -+import java.io.Serializable; -+import java.security.cert.CertificateEncodingException; -+import java.security.cert.CertificateException; -+import java.security.cert.CertificateParsingException; -+import java.util.Enumeration; -+import java.util.Hashtable; -+import java.util.Vector; -+ -+import org.mozilla.jss.netscape.security.util.DerInputStream; -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * The X509CertInfo class represents X.509 certificate information. -+ * -+ *

-+ * X.509 certificates have several base data elements, including: -+ *

    -+ * -+ *
  • The Subject Name, an X.500 Distinguished Name for the entity (subject) for which the certificate was -+ * issued. -+ * -+ *
  • The Subject Public Key, the public key of the subject. This is one of the most important parts of the -+ * certificate. -+ * -+ *
  • The Validity Period, a time period (e.g. six months) within which the certificate is valid (unless -+ * revoked). -+ * -+ *
  • The Issuer Name, an X.500 Distinguished Name for the Certificate Authority (CA) which issued the -+ * certificate. -+ * -+ *
  • A Serial Number assigned by the CA, for use in certificate revocation and other applications. -+ * -+ * @author Amit Kapoor -+ * @author Hemma Prafullchandra -+ * @version 1.16 -+ * @see CertAttrSet -+ * @see Serializable -+ * @see X509CertImpl -+ */ -+public class X509CertInfo implements CertAttrSet, Serializable { -+ /** -+ * -+ */ -+ private static final long serialVersionUID = -5094073467876311577L; -+ /** -+ * Identifier for this attribute, to be used with the -+ * get, set, delete methods of Certificate, x509 type. -+ */ -+ public static final String IDENT = "x509.info"; -+ // Certificate attribute names -+ public static final String NAME = "info"; -+ public static final String VERSION = CertificateVersion.NAME; -+ public static final String SERIAL_NUMBER = CertificateSerialNumber.NAME; -+ public static final String ALGORITHM_ID = CertificateAlgorithmId.NAME; -+ public static final String ISSUER = CertificateIssuerName.NAME; -+ public static final String VALIDITY = CertificateValidity.NAME; -+ public static final String SUBJECT = CertificateSubjectName.NAME; -+ public static final String KEY = CertificateX509Key.NAME; -+ public static final String ISSUER_ID = CertificateIssuerUniqueIdentity.NAME; -+ public static final String SUBJECT_ID = CertificateSubjectUniqueIdentity.NAME; -+ public static final String EXTENSIONS = CertificateExtensions.NAME; -+ -+ // X509.v1 data -+ protected CertificateVersion version = new CertificateVersion(); -+ protected CertificateSerialNumber serialNum = null; -+ protected CertificateAlgorithmId algId = null; -+ protected CertificateIssuerName issuer = null; -+ protected CertificateValidity interval = null; -+ protected CertificateSubjectName subject = null; -+ protected CertificateX509Key pubKey = null; -+ -+ // X509.v2 & v3 extensions -+ protected CertificateIssuerUniqueIdentity issuerUniqueId = null; -+ protected CertificateSubjectUniqueIdentity subjectUniqueId = null; -+ -+ // X509.v3 extensions -+ protected CertificateExtensions extensions = null; -+ -+ // Attribute numbers for internal manipulation -+ private static final int ATTR_VERSION = 1; -+ private static final int ATTR_SERIAL = 2; -+ private static final int ATTR_ALGORITHM = 3; -+ private static final int ATTR_ISSUER = 4; -+ private static final int ATTR_VALIDITY = 5; -+ private static final int ATTR_SUBJECT = 6; -+ private static final int ATTR_KEY = 7; -+ private static final int ATTR_ISSUER_ID = 8; -+ private static final int ATTR_SUBJECT_ID = 9; -+ private static final int ATTR_EXTENSIONS = 10; -+ -+ // DER encoded CertificateInfo data -+ private byte[] rawCertInfo = null; -+ -+ // The certificate attribute name to integer mapping stored here -+ private static final Hashtable map = new Hashtable(); -+ static { -+ map.put(VERSION, Integer.valueOf(ATTR_VERSION)); -+ map.put(SERIAL_NUMBER, Integer.valueOf(ATTR_SERIAL)); -+ map.put(ALGORITHM_ID, Integer.valueOf(ATTR_ALGORITHM)); -+ map.put(ISSUER, Integer.valueOf(ATTR_ISSUER)); -+ map.put(VALIDITY, Integer.valueOf(ATTR_VALIDITY)); -+ map.put(SUBJECT, Integer.valueOf(ATTR_SUBJECT)); -+ map.put(KEY, Integer.valueOf(ATTR_KEY)); -+ map.put(ISSUER_ID, Integer.valueOf(ATTR_ISSUER_ID)); -+ map.put(SUBJECT_ID, Integer.valueOf(ATTR_SUBJECT_ID)); -+ map.put(EXTENSIONS, Integer.valueOf(ATTR_EXTENSIONS)); -+ } -+ -+ /** -+ * Construct an uninitialized X509CertInfo on which -+ * decode must later be called (or which may be deserialized). -+ */ -+ public X509CertInfo() { -+ } -+ -+ /** -+ * Unmarshals a certificate from its encoded form, parsing the -+ * encoded bytes. This form of constructor is used by agents which -+ * need to examine and use certificate contents. That is, this is -+ * one of the more commonly used constructors. Note that the buffer -+ * must include only a certificate, and no "garbage" may be left at -+ * the end. If you need to ignore data at the end of a certificate, -+ * use another constructor. -+ * -+ * @param cert the encoded bytes, with no trailing data. -+ * @exception CertificateParsingException on parsing errors. -+ */ -+ public X509CertInfo(byte[] cert) throws CertificateParsingException { -+ try { -+ DerValue in = new DerValue(cert); -+ -+ parse(in); -+ } catch (IOException e) { -+ throw new CertificateParsingException(e); -+ } -+ } -+ -+ /** -+ * Unmarshal a certificate from its encoded form, parsing a DER value. -+ * This form of constructor is used by agents which need to examine -+ * and use certificate contents. -+ * -+ * @param derVal the der value containing the encoded cert. -+ * @exception CertificateParsingException on parsing errors. -+ */ -+ public X509CertInfo(DerValue derVal) throws CertificateParsingException { -+ try { -+ parse(derVal); -+ } catch (IOException e) { -+ throw new CertificateParsingException(e); -+ } -+ } -+ -+ /** -+ * Decode an X.509 certificate from an input stream. -+ * -+ * @param in an input stream holding at least one certificate -+ * @exception CertificateParsingException on decoding errors. -+ * @exception IOException on other errors. -+ */ -+ public void decode(InputStream in) -+ throws CertificateParsingException, IOException { -+ DerValue val = new DerValue(in); -+ -+ parse(val); -+ } -+ -+ /** -+ * Appends the certificate to an output stream. -+ * -+ * @param out an output stream to which the certificate is appended. -+ * @exception CertificateException on encoding errors. -+ * @exception IOException on other errors. -+ */ -+ public void encode(OutputStream out) -+ throws CertificateException, IOException { -+ encode(out, false); -+ } -+ -+ /** -+ * Appends the certificate to an output stream. -+ * -+ * @param out An output stream to which the certificate is appended. -+ * @param ignoreCache Whether to ignore the internal cache when encoding. -+ * (the cache can easily become out of date). -+ */ -+ public void encode(OutputStream out, boolean ignoreCache) -+ throws IOException, CertificateException { -+ if (ignoreCache || (rawCertInfo == null)) { -+ DerOutputStream tmp = new DerOutputStream(); -+ emit(tmp); -+ rawCertInfo = tmp.toByteArray(); -+ } -+ out.write(rawCertInfo); -+ } -+ -+ /** -+ * Return an enumeration of names of attributes existing within this -+ * attribute. -+ */ -+ public Enumeration getAttributeNames() { -+ Vector elements = new Vector(); -+ elements.addElement(VERSION); -+ elements.addElement(SERIAL_NUMBER); -+ elements.addElement(ALGORITHM_ID); -+ elements.addElement(ISSUER); -+ elements.addElement(VALIDITY); -+ elements.addElement(SUBJECT); -+ elements.addElement(KEY); -+ elements.addElement(ISSUER_ID); -+ elements.addElement(SUBJECT_ID); -+ elements.addElement(EXTENSIONS); -+ -+ return (elements.elements()); -+ } -+ -+ /** -+ * Return the name of this attribute. -+ */ -+ public String getName() { -+ return (NAME); -+ } -+ -+ /** -+ * Returns the encoded certificate info. -+ * -+ * @exception CertificateEncodingException on encoding information errors. -+ */ -+ public byte[] getEncodedInfo() throws CertificateEncodingException { -+ return getEncodedInfo(false); -+ } -+ -+ public byte[] getEncodedInfo(boolean ignoreCache) throws CertificateEncodingException { -+ try { -+ if (ignoreCache || (rawCertInfo == null)) { -+ DerOutputStream tmp = new DerOutputStream(); -+ emit(tmp); -+ rawCertInfo = tmp.toByteArray(); -+ } -+ byte[] dup = new byte[rawCertInfo.length]; -+ System.arraycopy(rawCertInfo, 0, dup, 0, dup.length); -+ return dup; -+ } catch (IOException e) { -+ throw new CertificateEncodingException(e); -+ } catch (CertificateException e) { -+ throw new CertificateEncodingException(e); -+ } -+ } -+ -+ /** -+ * Compares two X509CertInfo objects. This is false if the -+ * certificates are not both X.509 certs, otherwise it -+ * compares them as binary data. -+ * -+ * @param other the object being compared with this one -+ * @return true iff the certificates are equivalent -+ */ -+ public boolean equals(Object other) { -+ if (other instanceof X509CertInfo) { -+ return equals((X509CertInfo) other); -+ } else { -+ return false; -+ } -+ } -+ -+ /** -+ * Compares two certificates, returning false if any data -+ * differs between the two. -+ * -+ * @param other the object being compared with this one -+ * @return true iff the certificates are equivalent -+ */ -+ public boolean equals(X509CertInfo other) { -+ if (this == other) { -+ return (true); -+ } else if (rawCertInfo == null || other.rawCertInfo == null) { -+ return (false); -+ } else if (rawCertInfo.length != other.rawCertInfo.length) { -+ return (false); -+ } -+ for (int i = 0; i < rawCertInfo.length; i++) { -+ if (rawCertInfo[i] != other.rawCertInfo[i]) { -+ return (false); -+ } -+ } -+ return (true); -+ } -+ -+ /** -+ * Calculates a hash code value for the object. Objects -+ * which are equal will also have the same hashcode. -+ */ -+ public int hashCode() { -+ int retval = 0; -+ -+ for (int i = 1; i < rawCertInfo.length; i++) { -+ retval += rawCertInfo[i] * i; -+ } -+ return (retval); -+ } -+ -+ /** -+ * Returns a printable representation of the certificate. -+ */ -+ public String toString() { -+ -+ if (subject == null || pubKey == null || interval == null -+ || issuer == null || algId == null || serialNum == null) { -+ throw new NullPointerException("X.509 cert is incomplete"); -+ } -+ StringBuffer sb = new StringBuffer("[\n" + " " + version.toString() + "\n" + " Subject: " -+ + subject.toString() + "\n" -+ + " Signature Algorithm: " + algId.toString() + "\n" + " Key: " + pubKey.toString() + "\n"); -+ -+ sb.append(" " + interval.toString() + "\n" + " Issuer: " + issuer.toString() + "\n" -+ + " " + serialNum.toString() + "\n"); -+ // optional v2, v3 extras -+ if (issuerUniqueId != null) { -+ sb.append(" Issuer Id:\n" + issuerUniqueId.toString() + "\n"); -+ } -+ if (subjectUniqueId != null) { -+ sb.append(" Subject Id:\n" + subjectUniqueId.toString() + "\n"); -+ } -+ if (extensions != null) { -+ org.mozilla.jss.netscape.security.util.PrettyPrintFormat pp = -+ new org.mozilla.jss.netscape.security.util.PrettyPrintFormat(" ", 20); -+ for (int i = 0; i < extensions.size(); i++) { -+ sb.append(" Extension[" + i + "] = "); -+ Extension ext = extensions.elementAt(i); -+ DerOutputStream out = null; -+ try { -+ if (OIDMap.getClass(ext.getExtensionId()) == null) { -+ sb.append(ext.toString()); -+ byte[] extValue = ext.getExtensionValue(); -+ if (extValue != null) { -+ out = new DerOutputStream(); -+ out.putOctetString(extValue); -+ extValue = out.toByteArray(); -+ String extValuebits = pp.toHexString(extValue); -+ sb.append("Extension unknown: " -+ + "DER encoded OCTET string =\n" -+ + extValuebits); -+ } -+ } else -+ sb.append(ext.toString()); //sub-class exists -+ } catch (CertificateException e) { -+ sb.append(", Error parsing this extension"); -+ } catch (IOException e) { -+ sb.append(", Error parsing this extension"); -+ } finally { -+ if (out != null) { -+ try { -+ out.close(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ } -+ sb.append("\n]"); -+ return sb.toString(); -+ } -+ -+ /** -+ * Set the certificate attribute. -+ * -+ * @param name the name of the Certificate attribute. -+ * @param val the value of the Certificate attribute. -+ * @exception CertificateException on invalid attributes. -+ * @exception IOException on other errors. -+ */ -+ public void set(String name, Object val) -+ throws CertificateException, IOException { -+ X509AttributeName attrName = new X509AttributeName(name); -+ -+ int attr = attributeMap(attrName.getPrefix()); -+ if (attr == 0) { -+ throw new CertificateException("Attribute name not recognized: " -+ + name); -+ } -+ // set rawCertInfo to null, so that we are forced to re-encode -+ rawCertInfo = null; -+ -+ switch (attr) { -+ case ATTR_VERSION: -+ if (attrName.getSuffix() == null) { -+ setVersion(val); -+ } else { -+ version.set(attrName.getSuffix(), val); -+ } -+ break; -+ -+ case ATTR_SERIAL: -+ if (attrName.getSuffix() == null) { -+ setSerialNumber(val); -+ } else { -+ serialNum.set(attrName.getSuffix(), val); -+ } -+ break; -+ -+ case ATTR_ALGORITHM: -+ if (attrName.getSuffix() == null) { -+ setAlgorithmId(val); -+ } else { -+ algId.set(attrName.getSuffix(), val); -+ } -+ break; -+ -+ case ATTR_ISSUER: -+ if (attrName.getSuffix() == null) { -+ setIssuer(val); -+ } else { -+ issuer.set(attrName.getSuffix(), val); -+ } -+ break; -+ -+ case ATTR_VALIDITY: -+ if (attrName.getSuffix() == null) { -+ setValidity(val); -+ } else { -+ interval.set(attrName.getSuffix(), val); -+ } -+ break; -+ -+ case ATTR_SUBJECT: -+ if (attrName.getSuffix() == null) { -+ setSubject(val); -+ } else { -+ subject.set(attrName.getSuffix(), val); -+ } -+ break; -+ -+ case ATTR_KEY: -+ if (attrName.getSuffix() == null) { -+ setKey(val); -+ } else { -+ pubKey.set(attrName.getSuffix(), val); -+ } -+ break; -+ -+ case ATTR_ISSUER_ID: -+ if (attrName.getSuffix() == null) { -+ setIssuerUniqueId(val); -+ } else { -+ issuerUniqueId.set(attrName.getSuffix(), val); -+ } -+ break; -+ -+ case ATTR_SUBJECT_ID: -+ if (attrName.getSuffix() == null) { -+ setSubjectUniqueId(val); -+ } else { -+ subjectUniqueId.set(attrName.getSuffix(), val); -+ } -+ break; -+ -+ case ATTR_EXTENSIONS: -+ if (attrName.getSuffix() == null) { -+ setExtensions(val); -+ } else { -+ extensions.set(attrName.getSuffix(), val); -+ } -+ break; -+ } -+ } -+ -+ /** -+ * Delete the certificate attribute. -+ * -+ * @param name the name of the Certificate attribute. -+ * @exception CertificateException on invalid attributes. -+ * @exception IOException on other errors. -+ */ -+ public void delete(String name) -+ throws CertificateException, IOException { -+ X509AttributeName attrName = new X509AttributeName(name); -+ -+ int attr = attributeMap(attrName.getPrefix()); -+ if (attr == 0) { -+ throw new CertificateException("Attribute name not recognized: " -+ + name); -+ } -+ // set rawCertInfo to null, so that we are forced to re-encode -+ rawCertInfo = null; -+ -+ switch (attr) { -+ case ATTR_VERSION: -+ if (attrName.getSuffix() == null) { -+ version = null; -+ } else { -+ version.delete(attrName.getSuffix()); -+ } -+ break; -+ case (ATTR_SERIAL): -+ if (attrName.getSuffix() == null) { -+ serialNum = null; -+ } else { -+ serialNum.delete(attrName.getSuffix()); -+ } -+ break; -+ case (ATTR_ALGORITHM): -+ if (attrName.getSuffix() == null) { -+ algId = null; -+ } else { -+ algId.delete(attrName.getSuffix()); -+ } -+ break; -+ case (ATTR_ISSUER): -+ if (attrName.getSuffix() == null) { -+ issuer = null; -+ } else { -+ issuer.delete(attrName.getSuffix()); -+ } -+ break; -+ case (ATTR_VALIDITY): -+ if (attrName.getSuffix() == null) { -+ interval = null; -+ } else { -+ interval.delete(attrName.getSuffix()); -+ } -+ break; -+ case (ATTR_SUBJECT): -+ if (attrName.getSuffix() == null) { -+ subject = null; -+ } else { -+ subject.delete(attrName.getSuffix()); -+ } -+ break; -+ case (ATTR_KEY): -+ if (attrName.getSuffix() == null) { -+ pubKey = null; -+ } else { -+ pubKey.delete(attrName.getSuffix()); -+ } -+ break; -+ case (ATTR_ISSUER_ID): -+ if (attrName.getSuffix() == null) { -+ issuerUniqueId = null; -+ } else { -+ issuerUniqueId.delete(attrName.getSuffix()); -+ } -+ break; -+ case (ATTR_SUBJECT_ID): -+ if (attrName.getSuffix() == null) { -+ subjectUniqueId = null; -+ } else { -+ subjectUniqueId.delete(attrName.getSuffix()); -+ } -+ break; -+ case (ATTR_EXTENSIONS): -+ if (attrName.getSuffix() == null) { -+ extensions = null; -+ } else { -+ extensions.delete(attrName.getSuffix()); -+ } -+ break; -+ } -+ } -+ -+ /** -+ * Get the certificate attribute. -+ * -+ * @param name the name of the Certificate attribute. -+ * -+ * @exception CertificateException on invalid attributes. -+ * @exception IOException on other errors. -+ */ -+ public Object get(String name) -+ throws CertificateException, IOException { -+ X509AttributeName attrName = new X509AttributeName(name); -+ -+ int attr = attributeMap(attrName.getPrefix()); -+ if (attr == 0) { -+ throw new CertificateParsingException( -+ "Attribute name not recognized: " + name); -+ } -+ -+ switch (attr) { -+ case (ATTR_VERSION): -+ if (attrName.getSuffix() == null) { -+ return (version); -+ } else { -+ return (version.get(attrName.getSuffix())); -+ } -+ case (ATTR_SERIAL): -+ if (attrName.getSuffix() == null) { -+ return (serialNum); -+ } else { -+ return (serialNum.get(attrName.getSuffix())); -+ } -+ case (ATTR_ALGORITHM): -+ if (attrName.getSuffix() == null) { -+ return (algId); -+ } else { -+ return (algId.get(attrName.getSuffix())); -+ } -+ case (ATTR_ISSUER): -+ if (attrName.getSuffix() == null) { -+ return (issuer); -+ } else { -+ return (issuer.get(attrName.getSuffix())); -+ } -+ case (ATTR_VALIDITY): -+ if (attrName.getSuffix() == null) { -+ return (interval); -+ } else { -+ return (interval.get(attrName.getSuffix())); -+ } -+ case (ATTR_SUBJECT): -+ if (attrName.getSuffix() == null) { -+ return (subject); -+ } else { -+ return (subject.get(attrName.getSuffix())); -+ } -+ case (ATTR_KEY): -+ if (attrName.getSuffix() == null) { -+ return (pubKey); -+ } else { -+ return (pubKey.get(attrName.getSuffix())); -+ } -+ case (ATTR_ISSUER_ID): -+ if (attrName.getSuffix() == null) { -+ return (issuerUniqueId); -+ } else { -+ if (issuerUniqueId == null) -+ return null; -+ else -+ return (issuerUniqueId.get(attrName.getSuffix())); -+ } -+ case (ATTR_SUBJECT_ID): -+ if (attrName.getSuffix() == null) { -+ return (subjectUniqueId); -+ } else { -+ if (subjectUniqueId == null) -+ return null; -+ else -+ return (subjectUniqueId.get(attrName.getSuffix())); -+ } -+ case (ATTR_EXTENSIONS): -+ if (attrName.getSuffix() == null) { -+ return (extensions); -+ } else { -+ if (extensions == null) -+ return null; -+ else -+ return (extensions.get(attrName.getSuffix())); -+ } -+ } -+ return null; -+ } -+ -+ /* -+ * This routine unmarshals the certificate information. -+ */ -+ private void parse(DerValue val) -+ throws CertificateParsingException, IOException { -+ DerInputStream in; -+ DerValue tmp; -+ -+ if (val.tag != DerValue.tag_Sequence) { -+ throw new CertificateParsingException("signed fields invalid"); -+ } -+ rawCertInfo = val.toByteArray(); -+ -+ in = val.data; -+ -+ // Version -+ tmp = in.getDerValue(); -+ if (tmp.isContextSpecific((byte) 0)) { -+ version = new CertificateVersion(tmp); -+ tmp = in.getDerValue(); -+ } -+ -+ // Serial number ... an integer -+ serialNum = new CertificateSerialNumber(tmp); -+ -+ // Algorithm Identifier -+ algId = new CertificateAlgorithmId(in); -+ -+ // Issuer name -+ issuer = new CertificateIssuerName(in); -+ -+ // validity: SEQUENCE { start date, end date } -+ interval = new CertificateValidity(in); -+ -+ // subject name -+ subject = new CertificateSubjectName(in); -+ -+ // public key -+ pubKey = new CertificateX509Key(in); -+ -+ // If more data available, make sure version is not v1. -+ if (in.available() != 0) { -+ if (version.compare(CertificateVersion.V1) == 0) { -+ throw new CertificateParsingException("excess cert data"); -+ } -+ } else { -+ return; -+ } -+ -+ // Get the issuerUniqueId if present -+ tmp = in.getDerValue(); -+ if (tmp.isContextSpecific((byte) 1)) { -+ issuerUniqueId = new CertificateIssuerUniqueIdentity(tmp); -+ if (in.available() == 0) { -+ return; -+ } -+ tmp = in.getDerValue(); -+ } -+ -+ // Get the subjectUniqueId if present. -+ if (tmp.isContextSpecific((byte) 2)) { -+ subjectUniqueId = new CertificateSubjectUniqueIdentity(tmp); -+ if (in.available() == 0) { -+ return; -+ } -+ tmp = in.getDerValue(); -+ } -+ -+ // Get the extensions. -+ if (version.compare(CertificateVersion.V3) != 0) { -+ throw new CertificateParsingException("excess cert data"); -+ } -+ if (tmp.isConstructed() && tmp.isContextSpecific((byte) 3)) { -+ extensions = new CertificateExtensions(tmp.data); -+ } -+ } -+ -+ /* -+ * Marshal the contents of a "raw" certificate into a DER sequence. -+ */ -+ private void emit(DerOutputStream out) -+ throws CertificateException, IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ -+ // version number, iff not V1 -+ version.encode(tmp); -+ -+ // Encode serial number, issuer signing algorithm, issuer name -+ // and validity -+ serialNum.encode(tmp); -+ algId.encode(tmp); -+ issuer.encode(tmp); -+ interval.encode(tmp); -+ -+ // Encode subject (principal) and associated key -+ subject.encode(tmp); -+ pubKey.encode(tmp); -+ -+ // Encode issuerUniqueId & subjectUniqueId. -+ if (issuerUniqueId != null) { -+ issuerUniqueId.encode(tmp); -+ } -+ if (subjectUniqueId != null) { -+ subjectUniqueId.encode(tmp); -+ } -+ -+ // Write all the extensions. -+ if (extensions != null) { -+ extensions.encode(tmp); -+ } -+ -+ // Wrap the data; encoding of the "raw" cert is now complete. -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+ -+ /** -+ * Serialization write ... X.509 certificates serialize as -+ * themselves, and they're parsed when they get read back. -+ * (Actually they serialize as some type data from the -+ * serialization subsystem, then the cert data.) -+ */ -+ private void writeObject(ObjectOutputStream stream) throws CertificateException, IOException { -+ encode(stream); -+ } -+ -+ /** -+ * Serialization read ... X.509 certificates serialize as -+ * themselves, and they're parsed when they get read back. -+ */ -+ private void readObject(ObjectInputStream stream) throws CertificateException, IOException { -+ decode(stream); -+ } -+ -+ /** -+ * Returns the integer attribute number for the passed attribute name. -+ */ -+ private int attributeMap(String name) { -+ Integer num = map.get(name); -+ if (num == null) { -+ return (0); -+ } -+ return (num.intValue()); -+ } -+ -+ /** -+ * Set the version number of the certificate. -+ * -+ * @param val the Object class value for the Extensions -+ * @exception CertificateException on invalid data. -+ */ -+ private void setVersion(Object val) throws CertificateException { -+ if (!(val instanceof CertificateVersion)) { -+ throw new CertificateException("Version class type invalid."); -+ } -+ version = (CertificateVersion) val; -+ } -+ -+ /** -+ * Set the serial number of the certificate. -+ * -+ * @param val the Object class value for the CertificateSerialNumber -+ * @exception CertificateException on invalid data. -+ */ -+ private void setSerialNumber(Object val) throws CertificateException { -+ if (!(val instanceof CertificateSerialNumber)) { -+ throw new CertificateException("SerialNumber class type invalid."); -+ } -+ serialNum = (CertificateSerialNumber) val; -+ } -+ -+ /** -+ * Set the algorithm id of the certificate. -+ * -+ * @param val the Object class value for the AlgorithmId -+ * @exception CertificateException on invalid data. -+ */ -+ private void setAlgorithmId(Object val) throws CertificateException { -+ if (!(val instanceof CertificateAlgorithmId)) { -+ throw new CertificateException( -+ "AlgorithmId class type invalid."); -+ } -+ algId = (CertificateAlgorithmId) val; -+ } -+ -+ /** -+ * Set the issuer name of the certificate. -+ * -+ * @param val the Object class value for the issuer -+ * @exception CertificateException on invalid data. -+ */ -+ private void setIssuer(Object val) throws CertificateException { -+ if (!(val instanceof CertificateIssuerName)) { -+ throw new CertificateException( -+ "Issuer class type invalid."); -+ } -+ issuer = (CertificateIssuerName) val; -+ } -+ -+ public CertificateIssuerName getIssuerObj() { -+ return issuer; -+ } -+ -+ /** -+ * Set the validity interval of the certificate. -+ * -+ * @param val the Object class value for the CertificateValidity -+ * @exception CertificateException on invalid data. -+ */ -+ private void setValidity(Object val) throws CertificateException { -+ if (!(val instanceof CertificateValidity)) { -+ throw new CertificateException( -+ "CertificateValidity class type invalid."); -+ } -+ interval = (CertificateValidity) val; -+ } -+ -+ /** -+ * Set the subject name of the certificate. -+ * -+ * @param val the Object class value for the Subject -+ * @exception CertificateException on invalid data. -+ */ -+ private void setSubject(Object val) throws CertificateException { -+ if (!(val instanceof CertificateSubjectName)) { -+ throw new CertificateException( -+ "Subject class type invalid."); -+ } -+ subject = (CertificateSubjectName) val; -+ } -+ -+ public CertificateSubjectName getSubjectObj() { -+ return subject; -+ } -+ -+ /** -+ * Set the public key in the certificate. -+ * -+ * @param val the Object class value for the PublicKey -+ * @exception CertificateException on invalid data. -+ */ -+ private void setKey(Object val) throws CertificateException { -+ if (!(val instanceof CertificateX509Key)) { -+ throw new CertificateException( -+ "Key class type invalid."); -+ } -+ pubKey = (CertificateX509Key) val; -+ } -+ -+ /** -+ * Set the Issuer Unique Identity in the certificate. -+ * -+ * @param val the Object class value for the IssuerUniqueId -+ * @exception CertificateException -+ */ -+ private void setIssuerUniqueId(Object val) throws CertificateException { -+ if (version.compare(CertificateVersion.V2) < 0) { -+ throw new CertificateException("Invalid version"); -+ } -+ if (!(val instanceof CertificateIssuerUniqueIdentity)) { -+ throw new CertificateException( -+ "IssuerUniqueId class type invalid."); -+ } -+ issuerUniqueId = (CertificateIssuerUniqueIdentity) val; -+ } -+ -+ /** -+ * Set the Subject Unique Identity in the certificate. -+ * -+ * @param val the Object class value for the SubjectUniqueId -+ * @exception CertificateException -+ */ -+ private void setSubjectUniqueId(Object val) throws CertificateException { -+ if (version.compare(CertificateVersion.V2) < 0) { -+ throw new CertificateException("Invalid version"); -+ } -+ if (!(val instanceof CertificateSubjectUniqueIdentity)) { -+ throw new CertificateException( -+ "SubjectUniqueId class type invalid."); -+ } -+ subjectUniqueId = (CertificateSubjectUniqueIdentity) val; -+ } -+ -+ /** -+ * Set the extensions in the certificate. -+ * -+ * @param val the Object class value for the Extensions -+ * @exception CertificateException -+ */ -+ private void setExtensions(Object val) throws CertificateException { -+ if (version.compare(CertificateVersion.V3) < 0) { -+ throw new CertificateException("Invalid version"); -+ } -+ if (!(val instanceof CertificateExtensions)) { -+ throw new CertificateException( -+ "Extensions class type invalid."); -+ } -+ extensions = (CertificateExtensions) val; -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X509ExtensionException.java b/org/mozilla/jss/netscape/security/x509/X509ExtensionException.java -new file mode 100644 -index 00000000..ac6c90c9 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X509ExtensionException.java -@@ -0,0 +1,54 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.security.GeneralSecurityException; -+ -+/** -+ * X.509 Extension Exception. -+ * -+ * @author Hemma Prafullchandra -+ * 1.2 -+ */ -+public class X509ExtensionException extends GeneralSecurityException { -+ -+ /** -+ * -+ */ -+ private static final long serialVersionUID = 8152491877676477910L; -+ -+ /** -+ * Constructs an X509ExtensionException with no detail message. A -+ * detail message is a String that describes this particular -+ * exception. -+ */ -+ public X509ExtensionException() { -+ super(); -+ } -+ -+ /** -+ * Constructs the exception with the specified detail -+ * message. A detail message is a String that describes this -+ * particular exception. -+ * -+ * @param message the detail message. -+ */ -+ public X509ExtensionException(String message) { -+ super(message); -+ } -+} -diff --git a/org/mozilla/jss/netscape/security/x509/X509Key.java b/org/mozilla/jss/netscape/security/x509/X509Key.java -new file mode 100644 -index 00000000..bd630ce2 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/X509Key.java -@@ -0,0 +1,501 @@ -+// --- 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 org.mozilla.jss.netscape.security.x509; -+ -+import java.io.ByteArrayInputStream; -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.ObjectInputStream; -+import java.security.InvalidKeyException; -+import java.security.Key; -+import java.security.KeyFactory; -+import java.security.NoSuchAlgorithmException; -+import java.security.Provider; -+import java.security.PublicKey; -+import java.security.Security; -+import java.security.spec.InvalidKeySpecException; -+import java.security.spec.X509EncodedKeySpec; -+ -+import org.mozilla.jss.netscape.security.util.DerOutputStream; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+/** -+ * Holds an X.509 key, for example a public key found in an X.509 -+ * certificate. Includes a description of the algorithm to be used -+ * with the key; these keys normally are used as -+ * "SubjectPublicKeyInfo". -+ * -+ *

    -+ * While this class can represent any kind of X.509 key, it may be desirable to provide subclasses which understand how -+ * to parse keying data. For example, RSA public keys have two members, one for the public modulus and one for the prime -+ * exponent. If such a class is provided, it is used when parsing X.509 keys. If one is not provided, the key still -+ * parses correctly. -+ * -+ * @version 1.74, 97/12/10 -+ * @author David Brownell -+ */ -+public class X509Key implements PublicKey { -+ -+ /** use serialVersionUID from JDK 1.1. for interoperability */ -+ private static final long serialVersionUID = -5359250853002055002L; -+ -+ /* The algorithm information (name, parameters, etc). */ -+ protected AlgorithmId algid; -+ -+ /* The key bytes, without the algorithm information */ -+ protected byte[] key; -+ -+ /* The encoding for the key. */ -+ protected byte[] encodedKey; -+ -+ /** -+ * Default constructor. The key constructed must have its key -+ * and algorithm initialized before it may be used, for example -+ * by using decode. -+ */ -+ public X509Key() { -+ } -+ -+ /* -+ * Build and initialize as a "default" key. All X.509 key -+ * data is stored and transmitted losslessly, but no knowledge -+ * about this particular algorithm is available. -+ */ -+ public X509Key(AlgorithmId algid, byte[] key) -+ throws InvalidKeyException { -+ this.algid = algid; -+ this.key = key; -+ encode(); -+ } -+ -+ /** -+ * Construct X.509 subject public key from a DER value. If -+ * the runtime environment is configured with a specific class for -+ * this kind of key, a subclass is returned. Otherwise, a generic -+ * X509Key object is returned. -+ * -+ *

    -+ * This mechanism gurantees that keys (and algorithms) may be freely manipulated and transferred, without risk of -+ * losing information. Also, when a key (or algorithm) needs some special handling, that specific need can be -+ * accomodated. -+ * -+ * @param in the DER-encoded SubjectPublicKeyInfo value -+ * @exception IOException on data format errors -+ */ -+ public static X509Key parse(DerValue in) throws IOException { -+ AlgorithmId algorithm; -+ X509Key subjectKey; -+ -+ if (in.tag != DerValue.tag_Sequence) -+ throw new IOException("corrupt subject key"); -+ -+ algorithm = AlgorithmId.parse(in.data.getDerValue()); -+ try { -+ subjectKey = buildX509Key(algorithm, in.data.getBitString()); -+ -+ } catch (InvalidKeyException e) { -+ throw new IOException("subject key, " + e.getMessage()); -+ } -+ -+ if (in.data.available() != 0) -+ throw new IOException("excess subject key"); -+ return subjectKey; -+ } -+ -+ /** -+ * Parse the key bits. This may be redefined by subclasses to take -+ * advantage of structure within the key. For example, RSA public -+ * keys encapsulate two unsigned integers (modulus and exponent) as -+ * DER values within the key bits; Diffie-Hellman and -+ * DSS/DSA keys encapsulate a single unsigned integer. -+ * -+ *

    -+ * This function is called when creating X.509 SubjectPublicKeyInfo values using the X509Key member functions, such -+ * as parse and decode. -+ * -+ * @exception IOException on parsing errors. -+ * @exception InvalidKeyException on invalid key encodings. -+ */ -+ protected void parseKeyBits() throws IOException, InvalidKeyException { -+ encode(); -+ } -+ -+ /* -+ * Factory interface, building the kind of key associated with this -+ * specific algorithm ID or else returning this generic base class. -+ * See the description above. -+ */ -+ static X509Key buildX509Key(AlgorithmId algid, byte[] key) -+ throws IOException, InvalidKeyException { -+ /* -+ * Use the algid and key parameters to produce the ASN.1 encoding -+ * of the key, which will then be used as the input to the -+ * key factory. -+ */ -+ DerOutputStream x509EncodedKeyStream = new DerOutputStream(); -+ encode(x509EncodedKeyStream, algid, key); -+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(x509EncodedKeyStream.toByteArray()); -+ -+ try { -+ // Instantiate the key factory of the appropriate algorithm -+ KeyFactory keyFac = null; -+ if (Security.getProvider("Mozilla-JSS") == null) { -+ keyFac = KeyFactory.getInstance(algid.getName()); -+ } else { -+ keyFac = KeyFactory.getInstance(algid.getName(), -+ "Mozilla-JSS"); -+ } -+ -+ // Generate the public key -+ PublicKey pubKey = keyFac.generatePublic(x509KeySpec); -+ -+ if (pubKey instanceof X509Key) { -+ /* -+ * Return specialized X509Key, where the structure within the -+ * key has been parsed -+ */ -+ return (X509Key) pubKey; -+ } -+ } catch (NoSuchAlgorithmException e) { -+ // Return generic X509Key with opaque key data (see below) -+ } catch (InvalidKeySpecException e) { -+ throw new InvalidKeyException(e.toString()); -+ } catch (Exception e) { -+ throw new InvalidKeyException(e.toString()); -+ } -+ -+ /* -+ * Try again using JDK1.1-style for backwards compatibility. -+ */ -+ String classname = ""; -+ try { -+ Provider sunProvider; -+ -+ sunProvider = Security.getProvider("SUN"); -+ if (sunProvider == null) -+ throw new InstantiationException(); -+ classname = sunProvider.getProperty("PublicKey.X.509." + -+ algid.getName()); -+ if (classname == null) { -+ throw new InstantiationException(); -+ } -+ -+ Class keyClass = Class.forName(classname); -+ Object inst; -+ X509Key result; -+ -+ inst = keyClass.newInstance(); -+ if (inst instanceof X509Key) { -+ result = (X509Key) inst; -+ result.algid = algid; -+ result.key = key; -+ result.parseKeyBits(); -+ return result; -+ } -+ } catch (ClassNotFoundException e) { -+ } catch (InstantiationException e) { -+ } catch (IllegalAccessException e) { -+ // this should not happen. -+ throw new IOException(classname + " [internal error]"); -+ } -+ -+ X509Key result = new X509Key(); -+ result.algid = algid; -+ result.key = key; -+ return result; -+ } -+ -+ /** -+ * Returns the algorithm to be used with this key. -+ */ -+ public String getAlgorithm() { -+ return algid.getName(); -+ } -+ -+ /** -+ * Returns the algorithm ID to be used with this key. -+ */ -+ public AlgorithmId getAlgorithmId() { -+ return algid; -+ } -+ -+ /** -+ * Encode SubjectPublicKeyInfo sequence on the DER output stream. -+ * -+ * @exception IOException on encoding errors. -+ */ -+ public final void encode(DerOutputStream out) throws IOException { -+ encode(out, this.algid, this.key); -+ } -+ -+ /** -+ * Returns the DER-encoded form of the key as a byte array. -+ */ -+ public synchronized byte[] getEncoded() { -+ byte[] result = null; -+ try { -+ result = encode(); -+ } catch (InvalidKeyException e) { -+ } -+ return result; -+ } -+ -+ /** -+ * Returns the format for this key: "X.509" -+ */ -+ public String getFormat() { -+ return "X.509"; -+ } -+ -+ /** -+ * Returns the raw key as a byte array -+ */ -+ public byte[] getKey() { -+ return key; -+ } -+ -+ /** -+ * Returns the DER-encoded form of the key as a byte array. -+ * -+ * @exception InvalidKeyException on encoding errors. -+ */ -+ public byte[] encode() throws InvalidKeyException { -+ if (encodedKey == null) { -+ try { -+ DerOutputStream out; -+ -+ out = new DerOutputStream(); -+ encode(out); -+ encodedKey = out.toByteArray(); -+ -+ } catch (IOException e) { -+ throw new InvalidKeyException("IOException : " + -+ e.getMessage()); -+ } -+ } -+ return copyEncodedKey(encodedKey); -+ } -+ -+ /* -+ * Returns a printable representation of the key -+ */ -+ public String toString() { -+ org.mozilla.jss.netscape.security.util.PrettyPrintFormat pp = -+ new org.mozilla.jss.netscape.security.util.PrettyPrintFormat(" ", 20); -+ String keybits = pp.toHexString(key); -+ -+ return "algorithm = " + algid.toString() -+ + ", unparsed keybits = \n" + keybits; -+ } -+ -+ /** -+ * Initialize an X509Key object from an input stream. The data on that -+ * input stream must be encoded using DER, obeying the X.509 SubjectPublicKeyInfo format. That is, the -+ * data is a -+ * sequence consisting of an algorithm ID and a bit string which holds -+ * the key. (That bit string is often used to encapsulate another DER -+ * encoded sequence.) -+ * -+ *

    -+ * Subclasses should not normally redefine this method; they should instead provide a parseKeyBits -+ * method to parse any fields inside the key member. -+ * -+ *

    -+ * The exception to this rule is that since private keys need not be encoded using the X.509 -+ * SubjectPublicKeyInfo format, private keys may override this method, encode, and of -+ * course getFormat. -+ * -+ * @param in an input stream with a DER-encoded X.509 -+ * SubjectPublicKeyInfo value -+ * @exception InvalidKeyException on parsing errors. -+ */ -+ public void decode(InputStream in) -+ throws InvalidKeyException { -+ DerValue val; -+ -+ try { -+ val = new DerValue(in); -+ if (val.tag != DerValue.tag_Sequence) -+ throw new InvalidKeyException("invalid key format"); -+ -+ algid = AlgorithmId.parse(val.data.getDerValue()); -+ key = val.data.getBitString(); -+ parseKeyBits(); -+ if (val.data.available() != 0) -+ throw new InvalidKeyException("excess key data"); -+ -+ } catch (IOException e) { -+ // e.printStackTrace (); -+ throw new InvalidKeyException("IOException : " + -+ e.getMessage()); -+ } -+ } -+ -+ public void decode(byte[] encodedKey) throws InvalidKeyException { -+ decode(new ByteArrayInputStream(encodedKey)); -+ } -+ -+ /** -+ * Serialization write ... X.509 keys serialize as -+ * themselves, and they're parsed when they get read back. -+ */ -+ private void writeObject(java.io.ObjectOutputStream stream) throws IOException { -+ stream.write(getEncoded()); -+ } -+ -+ /** -+ * Serialization read ... X.509 keys serialize as -+ * themselves, and they're parsed when they get read back. -+ */ -+ private void readObject(ObjectInputStream stream) throws IOException { -+ try { -+ decode(stream); -+ } catch (InvalidKeyException e) { -+ e.printStackTrace(); -+ throw new IOException("deserialized key is invalid: " + e.getMessage()); -+ } -+ } -+ -+ public boolean equals(Object object) { -+ if (this == object) { -+ return true; -+ } -+ -+ if (object instanceof Key) { -+ Key key = (Key) object; -+ -+ byte[] b1; -+ if (encodedKey != null) { -+ b1 = encodedKey; -+ } else { -+ b1 = getEncoded(); -+ } -+ byte[] b2 = key.getEncoded(); -+ -+ return java.security.MessageDigest.isEqual(b1, b2); -+ } -+ -+ return false; -+ } -+ -+ /** -+ * Calculates a hash code value for the object. Objects -+ * which are equal will also have the same hashcode. -+ */ -+ public int hashCode() { -+ int retval = 0; -+ byte[] b1 = getEncoded(); -+ -+ for (int i = 1; i < b1.length; i++) { -+ retval += b1[i] * i; -+ } -+ return (retval); -+ } -+ -+ /* -+ * Make a copy of the encoded key. -+ */ -+ private byte[] copyEncodedKey(byte[] encodedKey) { -+ int len = encodedKey.length; -+ byte[] copy = new byte[len]; -+ System.arraycopy(encodedKey, 0, copy, 0, len); -+ return copy; -+ } -+ -+ /* -+ * Produce SubjectPublicKey encoding from algorithm id and key material. -+ */ -+ static void encode(DerOutputStream out, AlgorithmId algid, byte[] key) -+ throws IOException { -+ DerOutputStream tmp = new DerOutputStream(); -+ algid.encode(tmp); -+ tmp.putBitString(key); -+ out.write(DerValue.tag_Sequence, tmp); -+ } -+ -+ /* -+ * parsePublicKey returns a PublicKey for use with package JSS from within netscape.security.*. -+ * This function provide an interim solution for migrating from using the netscape.security.* package -+ * to using the JSS package. -+ */ -+ -+ public static PublicKey parsePublicKey(DerValue in) throws IOException { -+ AlgorithmId algorithm; -+ PublicKey subjectKey; -+ -+ if (in.tag != DerValue.tag_Sequence) -+ throw new IOException("corrupt subject key"); -+ -+ algorithm = AlgorithmId.parse(in.data.getDerValue()); -+ try { -+ subjectKey = buildPublicKey(algorithm, in.data.getBitString()); -+ -+ } catch (InvalidKeyException e) { -+ throw new IOException("subject key, " + e.getMessage()); -+ } -+ -+ if (in.data.available() != 0) -+ throw new IOException("excess subject key"); -+ return subjectKey; -+ } -+ -+ /* buildPublicKey returns a PublicKey for use with the JSS package from within netscape.security.*. -+ * This function provide an interim solution for migrating from using the netscape.security.* package -+ * to using the JSS package. -+ */ -+ static PublicKey buildPublicKey(AlgorithmId algid, byte[] key) -+ throws IOException, InvalidKeyException { -+ /* -+ * Use the algid and key parameters to produce the ASN.1 encoding -+ * of the key, which will then be used as the input to the -+ * key factory. -+ */ -+ DerOutputStream x509EncodedKeyStream = new DerOutputStream(); -+ encode(x509EncodedKeyStream, algid, key); -+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(x509EncodedKeyStream.toByteArray()); -+ -+ try { -+ // Instantiate the key factory of the appropriate algorithm -+ KeyFactory keyFac = null; -+ if (Security.getProvider("Mozilla-JSS") == null) { -+ keyFac = KeyFactory.getInstance(algid.getName()); -+ } else { -+ keyFac = KeyFactory.getInstance(algid.getName(), -+ "Mozilla-JSS"); -+ } -+ -+ // Generate the public key -+ PublicKey pubKey = keyFac.generatePublic(x509KeySpec); -+ -+ /* -+ * Return specialized X509Key, where the structure within the -+ * key has been parsed -+ */ -+ return pubKey; -+ } catch (NoSuchAlgorithmException e) { -+ // Return generic X509Key with opaque key data (see below) -+ throw new InvalidKeyException(e.toString()); -+ } catch (InvalidKeySpecException e) { -+ throw new InvalidKeyException(e.toString()); -+ } catch (Exception e) { -+ throw new InvalidKeyException(e.toString()); -+ } -+ -+ } -+ -+} -diff --git a/org/mozilla/jss/netscape/security/x509/manifest.mn b/org/mozilla/jss/netscape/security/x509/manifest.mn -new file mode 100644 -index 00000000..fb17fcef ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/manifest.mn -@@ -0,0 +1,10 @@ -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+CORE_DEPTH = ../../../../../.. -+ -+PACKAGE = org/mozilla/jss/netscape/security/x509 -+ -+MODULE = jss -diff --git a/org/mozilla/jss/netscape/security/x509/rules.mk b/org/mozilla/jss/netscape/security/x509/rules.mk -new file mode 100644 -index 00000000..edc59392 ---- /dev/null -+++ b/org/mozilla/jss/netscape/security/x509/rules.mk -@@ -0,0 +1,18 @@ -+# -+# This Source Code Form is subject to the terms of the Mozilla Public -+# License, v. 2.0. If a copy of the MPL was not distributed with this -+# file, You can obtain one at http://mozilla.org/MPL/2.0/. -+ -+javadoc: -+ @echo Steve's Javadoc rule ------------------------- -+ /usr/java/jdk1.1.5/bin/javadoc -sourcepath $(JAVA_HOME)/lib/classes.zip:$(CORE_DEPTH)/ninja -d /u/stevep/javadoc $(JSRCS) -+ @echo End of Steve's Javadoc rule ------------------ -+ -+runserver: -+ $(DEBUG_CMD) $(SOURCE_BIN_DIR)/jssjava -classpath $(JAVA_HOME)/lib/classes.zip:$(SOURCE_CLASSES_DIR)_DBG org.mozilla.jss.ssl.SSLServer -+ -+runclient: -+ $(DEBUG_CMD) $(SOURCE_BIN_DIR)/jssjava -classpath $(JAVA_HOME)/lib/classes.zip:$(SOURCE_CLASSES_DIR)_DBG org.mozilla.jss.ssl.SSLClient -+ -+debugcore: -+ dbx $(SOURCE_BIN_DIR)/jssjava core -diff --git a/org/mozilla/jss/tests/X509CertTest.java b/org/mozilla/jss/tests/X509CertTest.java -new file mode 100644 -index 00000000..c5f96132 ---- /dev/null -+++ b/org/mozilla/jss/tests/X509CertTest.java -@@ -0,0 +1,155 @@ -+/* This Source Code Form is subject to the terms of the Mozilla Public -+ * License, v. 2.0. If a copy of the MPL was not distributed with this -+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -+package org.mozilla.jss.tests; -+ -+import java.io.*; -+import org.mozilla.jss.CryptoManager; -+import org.mozilla.jss.util.Debug; -+import java.security.MessageDigest; -+import java.security.Provider; -+import java.security.Security; -+import java.security.PublicKey; -+import java.security.cert.CertificateException; -+import java.security.InvalidKeyException; -+import java.security.NoSuchAlgorithmException; -+import java.security.KeyPair; -+import java.security.interfaces.RSAPublicKey; -+ -+ -+import org.mozilla.jss.crypto.CryptoToken; -+import org.mozilla.jss.crypto.KeyPairGenerator; -+import org.mozilla.jss.crypto.KeyPairAlgorithm; -+ -+import org.mozilla.jss.pkcs11.PK11ECPublicKey; -+ -+import org.mozilla.jss.netscape.security.x509.X509CertImpl; -+import org.mozilla.jss.netscape.security.x509.X509CertInfo; -+import org.mozilla.jss.netscape.security.x509.X509Key; -+import org.mozilla.jss.netscape.security.x509.CertificateIssuerName; -+import org.mozilla.jss.netscape.security.x509.CertificateVersion; -+import org.mozilla.jss.netscape.security.x509.CertificateSerialNumber; -+import org.mozilla.jss.netscape.security.x509.CertificateValidity; -+import org.mozilla.jss.netscape.security.x509.CertificateSubjectName; -+import org.mozilla.jss.netscape.security.x509.CertificateAlgorithmId; -+import org.mozilla.jss.netscape.security.x509.AlgorithmId; -+import org.mozilla.jss.netscape.security.x509.CertificateX509Key; -+import org.mozilla.jss.netscape.security.x509.X500Name; -+import org.mozilla.jss.netscape.security.x509.CertificateExtensions; -+ -+import org.mozilla.jss.netscape.security.util.BigInt; -+import org.mozilla.jss.netscape.security.util.DerValue; -+ -+import java.util.Date; -+import java.util.Calendar; -+import java.math.BigInteger; -+ -+public class X509CertTest { -+ -+ public static String subjectDN = "CN = 8a99f98342b97d130142ba2cc30f07d3"; -+ public static String issuerDN= "C = US, ST = North Carolina, O = Red Hat Inc., OU = Red Hat Network, CN = Red Hat Candlepin Authority, E = ca-support@redhat.com "; -+ -+ /* Just some sample code to exercise the new classes */ -+ public static void main(String []args) { -+ -+ X509CertImpl certImpl = null; -+ X509CertInfo certInfo = null; -+ -+ if( args.length != 1 ) { -+ System.out.println("Usage: X509CertTest "); -+ return; -+ } -+ String dbdir = args[0]; -+ -+ try { -+ -+ Date notBefore = new Date(); -+ Calendar cal=Calendar.getInstance(); -+ cal.setTime(notBefore); -+ cal.set(Calendar.YEAR,2037); -+ -+ Date notAfter = cal.getTime(); -+ -+ //Generate ca keyPair -+ -+ CryptoManager.initialize(dbdir); -+ CryptoManager cryptoManager = CryptoManager.getInstance(); -+ CryptoToken token = cryptoManager.getInternalKeyStorageToken(); -+ KeyPairGenerator gen = token.getKeyPairGenerator(KeyPairAlgorithm.RSA); -+ gen.initialize(2048); -+ KeyPair keypairCA = gen.genKeyPair(); -+ PublicKey pubCA = keypairCA.getPublic(); -+ -+ -+ gen.initialize(2048); -+ KeyPair keypairUser = gen.genKeyPair(); -+ PublicKey pubUser = keypairUser.getPublic(); -+ -+ CertificateIssuerName issuernameObj = -+ new CertificateIssuerName(new X500Name(issuerDN)); -+ -+ certInfo = createX509CertInfo(convertPublicKeyToX509Key(pubUser), -+ BigInteger.valueOf((long) 1),issuernameObj,subjectDN, -+ notBefore, notAfter, "SHA256withRSA"); -+ -+ certImpl = new X509CertImpl(certInfo); -+ certImpl.sign(keypairCA.getPrivate(),"SHA256withRSA"); -+ -+ String certOutput = certImpl.toString(); -+ -+ System.out.println("Test certificate output: \n" + certOutput); -+ -+ -+ } catch( Exception e ) { -+ e.printStackTrace(); -+ System.exit(1); -+ } -+ System.exit(0); -+ } -+ -+ public static X509CertInfo createX509CertInfo(X509Key x509key, -+ BigInteger serialno, CertificateIssuerName issuernameObj, String subjname, -+ Date notBefore, Date notAfter, String alg) -+ throws IOException, -+ CertificateException, -+ InvalidKeyException, -+ NoSuchAlgorithmException { -+ X509CertInfo info = new X509CertInfo(); -+ -+ info.set(X509CertInfo.VERSION, new -+ CertificateVersion(CertificateVersion.V3)); -+ info.set(X509CertInfo.SERIAL_NUMBER, new -+ CertificateSerialNumber(serialno)); -+ if (issuernameObj != null) { -+ info.set(X509CertInfo.ISSUER, -+ issuernameObj); -+ } -+ info.set(X509CertInfo.SUBJECT, new -+ CertificateSubjectName(new X500Name(subjname))); -+ info.set(X509CertInfo.VALIDITY, new -+ CertificateValidity(notBefore, notAfter)); -+ info.set(X509CertInfo.ALGORITHM_ID, new -+ CertificateAlgorithmId(AlgorithmId.get(alg))); -+ info.set(X509CertInfo.KEY, new CertificateX509Key(x509key)); -+ info.set(X509CertInfo.EXTENSIONS, new CertificateExtensions()); -+ return info; -+ } -+ -+ public static X509Key convertPublicKeyToX509Key(PublicKey pubk) -+ throws InvalidKeyException , IOException { -+ X509Key xKey = null; -+ -+ if (pubk instanceof RSAPublicKey) { -+ RSAPublicKey rsaKey = (RSAPublicKey) pubk; -+ -+ xKey = new org.mozilla.jss.netscape.security.provider.RSAPublicKey( -+ new BigInt(rsaKey.getModulus()), -+ new BigInt(rsaKey.getPublicExponent())); -+ } else if (pubk instanceof PK11ECPublicKey) { -+ byte encoded[] = pubk.getEncoded(); -+ -+ xKey = X509Key.parse(new DerValue(encoded)); -+ } -+ return xKey; -+ } -+} --- -2.14.4 - diff --git a/SOURCES/jss-disallow-curve-x25519-in-FIPS-mode.patch b/SOURCES/jss-disallow-curve-x25519-in-FIPS-mode.patch deleted file mode 100644 index 36d1811..0000000 --- a/SOURCES/jss-disallow-curve-x25519-in-FIPS-mode.patch +++ /dev/null @@ -1,51 +0,0 @@ -From ab0bb8952fbd0f2c06703f26c49c0c039cd67c00 Mon Sep 17 00:00:00 2001 -From: Alexander Scheel -Date: Wed, 23 Jan 2019 10:57:27 -0500 -Subject: [PATCH] Disable x25519 in FIPS mode - -NSS's pkcs11.txt includes global ciphersuite options, however, it -doesn't understand Curve25519 as a parameter. Until such support is -added (or NIST finally approves Curve25519 for FIPS 140-2 usage!), -manually disable Curve25519 when FIPS mode is enabled. - -Signed-off-by: Alexander Scheel ---- - org/mozilla/jss/CryptoManager.c | 6 ++++++ - org/mozilla/jss/CryptoManager.java | 2 ++ - 2 files changed, 8 insertions(+) - -diff --git a/org/mozilla/jss/CryptoManager.c b/org/mozilla/jss/CryptoManager.c -index 56e66b2..eb8b922 100644 ---- a/jss/org/mozilla/jss/CryptoManager.c -+++ b/jss/org/mozilla/jss/CryptoManager.c -@@ -976,8 +976,14 @@ JNIEXPORT jboolean JNICALL - Java_org_mozilla_jss_CryptoManager_FIPSEnabled(JNIEnv *env, jobject this) - { - if( PK11_IsFIPS() ) { -+ /* There's a bug in NSS where it won't disable x25519 in FIPS mode. -+ * Since they won't fix the bug, we have to do it ourselves. */ -+ NSS_SetAlgorithmPolicy(SEC_OID_CURVE25519, 0, NSS_USE_ALG_IN_SSL_KX); - return JNI_TRUE; - } else { -+ /* In case FIPS mode is toggled, re-enable x25519 as it is a good -+ * curve. */ -+ NSS_SetAlgorithmPolicy(SEC_OID_CURVE25519, 1, NSS_USE_ALG_IN_SSL_KX); - return JNI_FALSE; - } - } -diff --git a/org/mozilla/jss/CryptoManager.java b/org/mozilla/jss/CryptoManager.java -index 9e5503d..f223361 100644 ---- a/jss/org/mozilla/jss/CryptoManager.java -+++ b/jss/org/mozilla/jss/CryptoManager.java -@@ -838,6 +838,8 @@ public final class CryptoManager implements TokenSupplier - if(instance==null) { - throw new NotInitializedException(); - } -+ /* throw away call -- disables x25519 if we're in FIPS mode */ -+ instance.FIPSEnabled(); - return instance; - } - --- -1.8.3.1 - diff --git a/SOURCES/jss-enable-AIA-OCSP-cert-checking-for-entire-cert-chain-2.patch b/SOURCES/jss-enable-AIA-OCSP-cert-checking-for-entire-cert-chain-2.patch deleted file mode 100644 index b5891ab..0000000 --- a/SOURCES/jss-enable-AIA-OCSP-cert-checking-for-entire-cert-chain-2.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 5e55a4bd86d7df8e24b78feaea772255d53efaa5 Mon Sep 17 00:00:00 2001 -From: Jack Magne -Date: Fri, 8 Feb 2019 11:21:48 -0800 -Subject: [PATCH] Additional: Resolve Bug 1666872 - CC: Enable AIA OCSP cert - checking for entire cert chain. - -Simple fix to make sure we are using the correct variant of the NSS cert usage quantity. - -It turns out some calls need a SECCertUsage and others need a SECCertificateUsage. -We also need to convert between the two in certain instances. - -Found and fixed double certificate object free issue. ---- - org/mozilla/jss/ssl/callbacks.c | 10 ++++++++-- - org/mozilla/jss/ssl/common.c | 19 ++++++++++++++----- - org/mozilla/jss/ssl/jssl.h | 2 +- - 3 files changed, 23 insertions(+), 8 deletions(-) - -diff --git a/org/mozilla/jss/ssl/callbacks.c b/org/mozilla/jss/ssl/callbacks.c -index dfbe408..1f8cc56 100644 ---- a/jss/org/mozilla/jss/ssl/callbacks.c -+++ b/jss/org/mozilla/jss/ssl/callbacks.c -@@ -473,6 +473,9 @@ JSSL_DefaultCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, - - certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; - -+ /* PKIX call needs a SECCertificate usage, convert */ -+ SECCertificateUsage certificateUsage = (SECCertificateUsage)1 << certUsage; -+ - /* SSL_PeerCertificate() returns a shallow copy of the cert, so we - must destroy it before we exit this function */ - -@@ -480,7 +483,7 @@ JSSL_DefaultCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, - - if (peerCert) { - if( ocspPolicy == OCSP_LEAF_AND_CHAIN_POLICY) { -- rv = JSSL_verifyCertPKIX( peerCert, certUsage, -+ rv = JSSL_verifyCertPKIX( peerCert, certificateUsage, - NULL /* pin arg */, ocspPolicy, NULL, NULL); - } else { - rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, -@@ -616,6 +619,9 @@ JSSL_JavaCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, - if (peerCert == NULL) goto finish; - - certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; -+ /* PKIX call needs a SECCertificate usage, convert */ -+ SECCertificateUsage certificateUsage = (SECCertificateUsage)1 << certUsage; -+ - - /* - * verify it against current time - (can't use -@@ -624,7 +630,7 @@ JSSL_JavaCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, - */ - - if( ocspPolicy == OCSP_LEAF_AND_CHAIN_POLICY) { -- verificationResult = JSSL_verifyCertPKIX( peerCert, certUsage, -+ verificationResult = JSSL_verifyCertPKIX( peerCert, certificateUsage, - NULL /* pin arg */, ocspPolicy, &log, NULL); - } else { - verificationResult = CERT_VerifyCert( CERT_GetDefaultCertDB(), -diff --git a/org/mozilla/jss/ssl/common.c b/org/mozilla/jss/ssl/common.c -index 7952488..8c2a224 100644 ---- a/jss/org/mozilla/jss/ssl/common.c -+++ b/jss/org/mozilla/jss/ssl/common.c -@@ -903,7 +903,7 @@ finish: - /* Get the trusted anchor for pkix */ - - CERTCertificate * getRoot(CERTCertificate *cert, -- SECCertificateUsage certUsage) -+ SECCertUsage certUsage) - { - CERTCertificate *root = NULL; - CERTCertListNode *node = NULL; -@@ -945,7 +945,7 @@ finish: - */ - - SECStatus JSSL_verifyCertPKIX(CERTCertificate *cert, -- SECCertificateUsage certUsage,secuPWData *pwdata, int ocspPolicy, -+ SECCertificateUsage certificateUsage,secuPWData *pwdata, int ocspPolicy, - CERTVerifyLog *log, SECCertificateUsage *usage) - { - -@@ -1002,6 +1002,8 @@ SECStatus JSSL_verifyCertPKIX(CERTCertificate *cert, - - PRBool fetchCerts = PR_FALSE; - -+ SECCertUsage certUsage = certUsageSSLClient /* 0 */; -+ - SECStatus res = SECFailure; - if(cert == NULL) { - goto finish; -@@ -1036,9 +1038,15 @@ SECStatus JSSL_verifyCertPKIX(CERTCertificate *cert, - cvin[inParamIndex].value.pointer.revocation = rev; - inParamIndex++; - -- - /* establish trust anchor */ - -+ /* We need to convert the SECCertificateUsage to a SECCertUsage to obtain -+ * the root. -+ */ -+ -+ SECCertificateUsage testUsage = certificateUsage; -+ while (0 != (testUsage = testUsage >> 1)) { certUsage++; } -+ - CERTCertificate *root = getRoot(cert,certUsage); - - /* Try to add the root as the trust anchor so all the -@@ -1073,7 +1081,7 @@ SECStatus JSSL_verifyCertPKIX(CERTCertificate *cert, - - cvout[outParamIndex].type = cert_po_end; - -- res = CERT_PKIXVerifyCert(cert, certUsage, cvin, cvout, &pwdata); -+ res = CERT_PKIXVerifyCert(cert, certificateUsage, cvin, cvout, &pwdata); - - finish: - /* clean up any trusted cert list */ -@@ -1083,8 +1091,9 @@ finish: - trustedCertList = NULL; - } - -+ /* CERT_DestroyCertList destroys interior certs for us. */ -+ - if(root) { -- CERT_DestroyCertificate(root); - root = NULL; - } - -diff --git a/org/mozilla/jss/ssl/jssl.h b/org/mozilla/jss/ssl/jssl.h -index 02771f8..e76db90 100644 ---- a/jss/org/mozilla/jss/ssl/jssl.h -+++ b/jss/org/mozilla/jss/ssl/jssl.h -@@ -145,7 +145,7 @@ JSSL_getOCSPPolicy(); - - SECStatus - JSSL_verifyCertPKIX(CERTCertificate *cert, -- SECCertificateUsage certUsage, -+ SECCertificateUsage certificateUsage, - secuPWData *pwdata, int ocspPolicy, - CERTVerifyLog *log,SECCertificateUsage *usage); - --- -1.8.3.1 - diff --git a/SOURCES/jss-enable-AIA-OCSP-cert-checking-for-entire-cert-chain.patch b/SOURCES/jss-enable-AIA-OCSP-cert-checking-for-entire-cert-chain.patch deleted file mode 100644 index f051c45..0000000 --- a/SOURCES/jss-enable-AIA-OCSP-cert-checking-for-entire-cert-chain.patch +++ /dev/null @@ -1,662 +0,0 @@ -From f609ff042970a30015862f3a962f52c631780dd0 Mon Sep 17 00:00:00 2001 -From: Jack Magne -Date: Fri, 25 Jan 2019 14:54:11 -0800 -Subject: [PATCH] Resolve Bug 1666872 - CC: Enable AIA OCSP cert checking for - entire cert chain. - -This fix for jss, solves the one use case where the pki server is configured to perform ocsp checking ONLY with the contents of the AIA extension. Previously, jss could only check the ocsp server for the leaf node cert of the cert being verified. This fix allows the cert chain to be checked over ocsp for each cert in question. This is possible due to the fact that we have made a call in the PKIX library of nss to do the actual cert verfication. This call is made with all the needed flags to tell the PKIX library to make the ocsp verifications remotely over the network using the contents of the AIA extension. - -Later on we can use this code to handle the other cases, but for now we want to solve this one particular problem. If the server is configured in any other configuration than the one stated, the original verification code will be called as before. Below is an example of a configuration in server.xml, that will trigger this new code: - -< .... enableOCSP="true" ocspCacheSize="10000" ocspMinCacheEntryDuration="7200" .... > - -Note that due to ocsp caching, the cert chain verification may only be apparent after a restart of the server. A way to force an ocsp fetch every time is to set the value of ocspCacheSize=-1, which essentially disables the cache. - -Added a couple of minor fixes due to review comments. Possibly more to come. -Minor include directive change to compile on branch. ---- - org/mozilla/jss/CryptoManager.java | 48 +++++++++ - org/mozilla/jss/PK11Finder.c | 95 +++++++++++++++--- - org/mozilla/jss/ssl/callbacks.c | 67 +++++++++++-- - org/mozilla/jss/ssl/common.c | 196 +++++++++++++++++++++++++++++++++++++ - org/mozilla/jss/ssl/jssl.h | 29 ++++++ - org/mozilla/jss/util/java_ids.h | 9 ++ - 6 files changed, 422 insertions(+), 22 deletions(-) - -diff --git a/org/mozilla/jss/CryptoManager.java b/org/mozilla/jss/CryptoManager.java -index f223361..81f4f95 100644 ---- a/jss/org/mozilla/jss/CryptoManager.java -+++ b/jss/org/mozilla/jss/CryptoManager.java -@@ -1715,6 +1715,44 @@ public final class CryptoManager implements TokenSupplier - // OCSP management - /////////////////////////////////////////////////////////////////////// - -+ /* OCSP Policy related */ -+ -+ public enum OCSPPolicy { -+ NONE, -+ NORMAL, -+ LEAF_AND_CHAIN; -+ } -+ -+ private static OCSPPolicy ocspPolicy = OCSPPolicy.NONE; -+ -+ /** -+ * Gets the current ocsp Policy. -+ * Currently we only support 2 modes OCSP_LEAF_AND_CHAIN_POLICY. -+ * And OCSP_NORMAL_POLICY, which is current processing , by default. -+ * If we have AIA based OCSP enabled we will check all certs in the chain. -+ * using PKIX cert verfication calls in the various cert auth callbacks we -+ * have. -+ * @return - The current ocsp policy in effect. -+ */ -+ -+ public static synchronized int getOCSPPolicy() { -+ return ocspPolicy.ordinal(); -+ } -+ -+ /** -+ * Sets the current ocsp Policy. -+ * Currently we only support one mode OCSP_LEAF_AND_CHAIN_POLICY. -+ * If we have AIA based OCSP enabled we will check all certs in the chain. -+ * using PKIX cert verfication calls in the various cert auth callbacks we -+ * have. -+ * @param policy - Either cert and chain or normal default processing. -+ * -+ */ -+ -+ public static synchronized void setOCSPPolicy(OCSPPolicy policy) { -+ ocspPolicy = policy; -+ } -+ - /** - * Enables OCSP, note when you Initialize JSS for the first time, for - * backwards compatibility, the initialize will enable OCSP if you -@@ -1733,6 +1771,16 @@ public final class CryptoManager implements TokenSupplier - String ocspResponderCertNickname ) - throws GeneralSecurityException - { -+ /* set the ocsp policy */ -+ -+ if(ocspCheckingEnabled && -+ ocspResponderURL == null && -+ ocspResponderCertNickname == null) { -+ setOCSPPolicy(OCSPPolicy.LEAF_AND_CHAIN); -+ } else { -+ setOCSPPolicy(OCSPPolicy.NORMAL); -+ } -+ - configureOCSPNative(ocspCheckingEnabled, - ocspResponderURL, - ocspResponderCertNickname ); -diff --git a/org/mozilla/jss/PK11Finder.c b/org/mozilla/jss/PK11Finder.c -index a7a6e28..152227e 100644 ---- a/jss/org/mozilla/jss/PK11Finder.c -+++ b/jss/org/mozilla/jss/PK11Finder.c -@@ -14,9 +14,9 @@ - #include - - #include -- - #include - #include "pk11util.h" -+#include "ssl/jssl.h" - #include - - /* -@@ -1574,6 +1574,9 @@ SECStatus verifyCertificateNow(JNIEnv *env, jobject self, jstring nickString, - goto finish; - } - -+ int ocspPolicy = JSSL_getOCSPPolicy(); -+ -+ - certificateUsage = required_certificateUsage; - - cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), nickname); -@@ -1587,8 +1590,24 @@ SECStatus verifyCertificateNow(JNIEnv *env, jobject self, jstring nickString, - /* 0 for certificateUsage in call to CERT_VerifyCertificateNow will - * retrieve the current valid usage into currUsage - */ -- rv = CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, -- checkSig, certificateUsage, NULL, currUsage ); -+ if( ocspPolicy == OCSP_LEAF_AND_CHAIN_POLICY) { -+ rv = JSSL_verifyCertPKIX( cert, certificateUsage, -+ NULL /* pin arg */, ocspPolicy, NULL, currUsage); -+ -+ /* we need to do this just to get the cert usages, the pkix version -+ doesn't seem to honor the method to get the usages as of yet. -+ Let the PKIX call only determine the final fate. -+ */ -+ if(rv == SECSuccess) { -+ CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, -+ checkSig, certificateUsage, NULL, currUsage ); -+ } -+ -+ } else { -+ rv = CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, -+ checkSig, certificateUsage, NULL, currUsage ); -+ } -+ - if ((rv == SECSuccess) && certificateUsage == 0x0000) { - if (*currUsage == - ( certUsageUserCertImport | -@@ -1639,6 +1658,8 @@ Java_org_mozilla_jss_CryptoManager_verifyCertificateNowNative(JNIEnv *env, - goto finish; - } - -+ int ocspPolicy = JSSL_getOCSPPolicy(); -+ - certificateUsage = required_certificateUsage; - - cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), nickname); -@@ -1653,8 +1674,23 @@ Java_org_mozilla_jss_CryptoManager_verifyCertificateNowNative(JNIEnv *env, - * just get the current usage (which we are not passing back for now - * but will bypass the certificate usage check - */ -- rv = CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, -- checkSig, certificateUsage, NULL, &currUsage ); -+ -+ if( ocspPolicy == OCSP_LEAF_AND_CHAIN_POLICY) { -+ rv= JSSL_verifyCertPKIX( cert, certificateUsage, -+ NULL /* pin arg */, ocspPolicy, NULL, &currUsage); -+ -+ /* we need to do this just to get the cert usages, the pkix version -+ doesn't seem to honor the method to get the usages as of yet. -+ Let the PKIX call only determine the final fate. -+ */ -+ if(rv == SECSuccess) { -+ CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, -+ checkSig, certificateUsage, NULL, &currUsage ); -+ } -+ } else { -+ rv = CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, -+ checkSig, certificateUsage, NULL, &currUsage ); -+ } - } - - finish: -@@ -1720,12 +1756,14 @@ Java_org_mozilla_jss_CryptoManager_verifyCertificateNowNative2(JNIEnv *env, - SECStatus rv = SECFailure; - CERTCertificate *cert = NULL; - char *nickname = NULL; -- -+ - if (nickString == NULL) { - JSS_throwMsg(env, INVALID_NICKNAME_EXCEPTION, "Missing certificate nickname"); - goto finish; - } - -+ int ocspPolicy = JSSL_getOCSPPolicy(); -+ - nickname = (char *) (*env)->GetStringUTFChars(env, nickString, NULL); - if (nickname == NULL) { - JSS_throwMsg(env, INVALID_NICKNAME_EXCEPTION, "Missing certificate nickname"); -@@ -1747,8 +1785,25 @@ Java_org_mozilla_jss_CryptoManager_verifyCertificateNowNative2(JNIEnv *env, - /* 0 for certificateUsage in call to CERT_VerifyCertificateNow will - * retrieve the current valid usage into currUsage - */ -- rv = CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, -- checkSig, certificateUsage, NULL, &currUsage); -+ -+ if( ocspPolicy == OCSP_LEAF_AND_CHAIN_POLICY) { -+ rv = JSSL_verifyCertPKIX( cert, certificateUsage, -+ NULL /* pin arg */, ocspPolicy, NULL, &currUsage); -+ -+ /* we need to do this just to get the cert usages, the pkix version -+ doesn't seem to honor the method to get the usages as of yet. -+ Let the PKIX call only determine the final fate. -+ */ -+ if(rv == SECSuccess) { -+ CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, -+ checkSig, certificateUsage, NULL, &currUsage ); -+ -+ } -+ -+ } else { -+ rv = CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, -+ checkSig, certificateUsage, NULL, &currUsage); -+ } - - if (rv != SECSuccess) { - JSS_throwMsgPrErr(env, CERTIFICATE_EXCEPTION, "Invalid certificate"); -@@ -1803,6 +1858,9 @@ Java_org_mozilla_jss_CryptoManager_verifyCertNowNative(JNIEnv *env, - if( nickname == NULL ) { - goto finish; - } -+ -+ int ocspPolicy = JSSL_getOCSPPolicy(); -+ - certUsage = cUsage; - cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), nickname); - -@@ -1812,8 +1870,13 @@ Java_org_mozilla_jss_CryptoManager_verifyCertNowNative(JNIEnv *env, - PR_smprintf_free(message); - goto finish; - } else { -- rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), cert, -- checkSig, certUsage, NULL ); -+ if( ocspPolicy == OCSP_LEAF_AND_CHAIN_POLICY) { -+ rv = JSSL_verifyCertPKIX( cert, certUsage, -+ NULL /* pin arg */, ocspPolicy, NULL, NULL); -+ } else { -+ rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), cert, -+ checkSig, certUsage, NULL ); -+ } - } - - finish: -@@ -1858,6 +1921,8 @@ Java_org_mozilla_jss_CryptoManager_verifyCertTempNative(JNIEnv *env, - derCerts[0] = JSS_ByteArrayToSECItem(env, packageArray); - derCerts[1] = NULL; - -+ int ocspPolicy = JSSL_getOCSPPolicy(); -+ - rv = CERT_ImportCerts(certdb, cUsage, - 1, derCerts, &certArray, PR_FALSE /*temp Certs*/, - PR_FALSE /*caOnly*/, NULL); -@@ -1869,8 +1934,14 @@ Java_org_mozilla_jss_CryptoManager_verifyCertTempNative(JNIEnv *env, - } - - certUsage = cUsage; -- rv = CERT_VerifyCertNow(certdb, certArray[0], -- checkSig, certUsage, NULL ); -+ -+ if( ocspPolicy == OCSP_LEAF_AND_CHAIN_POLICY) { -+ rv = JSSL_verifyCertPKIX( certArray[0], certUsage, -+ NULL /* pin arg */, ocspPolicy, NULL, NULL); -+ } else { -+ rv = CERT_VerifyCertNow(certdb, certArray[0], -+ checkSig, certUsage, NULL ); -+ } - - finish: - /* this checks for NULL */ -diff --git a/org/mozilla/jss/ssl/callbacks.c b/org/mozilla/jss/ssl/callbacks.c -index 0738e79..dfbe408 100644 ---- a/jss/org/mozilla/jss/ssl/callbacks.c -+++ b/jss/org/mozilla/jss/ssl/callbacks.c -@@ -20,6 +20,40 @@ - #include - #include - -+int -+JSSL_getOCSPPolicy() { -+ JNIEnv *env; -+ jint policy = -1; -+ -+ jmethodID getOCSPPolicyID; -+ jclass cryptoManagerClass; -+ -+ /* get the JNI environment */ -+ if((*JSS_javaVM)->AttachCurrentThread(JSS_javaVM, (void**)&env, NULL) != 0){ -+ PR_ASSERT(PR_FALSE); -+ goto finish; -+ } -+ -+ cryptoManagerClass = (*env)->FindClass(env, CRYPTO_MANAGER_NAME); -+ if( cryptoManagerClass == NULL ) { -+ ASSERT_OUTOFMEM(env); -+ goto finish; -+ } -+ getOCSPPolicyID = (*env)->GetStaticMethodID(env, cryptoManagerClass, -+ GET_OCSP_POLICY_NAME,GET_OCSP_POLICY_SIG); -+ -+ if( getOCSPPolicyID == NULL ) { -+ ASSERT_OUTOFMEM(env); -+ goto finish; -+ } -+ -+ policy = (*env)->CallStaticIntMethod(env, cryptoManagerClass, -+ getOCSPPolicyID); -+ -+finish: -+ return (int) policy; -+} -+ - static SECStatus - secCmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames) - { -@@ -435,8 +469,9 @@ JSSL_DefaultCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, - SECCertUsage certUsage; - CERTCertificate *peerCert=NULL; - -+ int ocspPolicy = JSSL_getOCSPPolicy(); -+ - certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; -- - - /* SSL_PeerCertificate() returns a shallow copy of the cert, so we - must destroy it before we exit this function */ -@@ -444,8 +479,13 @@ JSSL_DefaultCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, - peerCert = SSL_PeerCertificate(fd); - - if (peerCert) { -- rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, -- checkSig, certUsage, NULL /*pinarg*/); -+ if( ocspPolicy == OCSP_LEAF_AND_CHAIN_POLICY) { -+ rv = JSSL_verifyCertPKIX( peerCert, certUsage, -+ NULL /* pin arg */, ocspPolicy, NULL, NULL); -+ } else { -+ rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, -+ checkSig, certUsage, NULL /*pinarg*/); -+ } - } - - /* if we're a server, then we don't need to check the CN of the -@@ -561,6 +601,8 @@ JSSL_JavaCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, - log.tail = NULL; - log.count = 0; - -+ int ocspPolicy = JSSL_getOCSPPolicy(); -+ - /* get the JNI environment */ - if((*JSS_javaVM)->AttachCurrentThread(JSS_javaVM, (void**)&env, NULL) != 0){ - PR_ASSERT(PR_FALSE); -@@ -581,13 +623,18 @@ JSSL_JavaCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, - * logging parameter) - */ - -- verificationResult = CERT_VerifyCert( CERT_GetDefaultCertDB(), -- peerCert, -- checkSig, -- certUsage, -- PR_Now(), -- NULL /*pinarg*/, -- &log); -+ if( ocspPolicy == OCSP_LEAF_AND_CHAIN_POLICY) { -+ verificationResult = JSSL_verifyCertPKIX( peerCert, certUsage, -+ NULL /* pin arg */, ocspPolicy, &log, NULL); -+ } else { -+ verificationResult = CERT_VerifyCert( CERT_GetDefaultCertDB(), -+ peerCert, -+ checkSig, -+ certUsage, -+ PR_Now(), -+ NULL /*pinarg*/, -+ &log); -+ } - - if (verificationResult == SECSuccess && log.count > 0) { - verificationResult = SECFailure; -diff --git a/org/mozilla/jss/ssl/common.c b/org/mozilla/jss/ssl/common.c -index 84a4332..7952488 100644 ---- a/jss/org/mozilla/jss/ssl/common.c -+++ b/jss/org/mozilla/jss/ssl/common.c -@@ -15,6 +15,7 @@ - #include - #include "_jni/org_mozilla_jss_ssl_SSLSocket.h" - #include "jssl.h" -+#include "cert.h" - - #ifdef WIN32 - #include -@@ -898,3 +899,198 @@ finish: - PR_ASSERT(ret == 0); - } - } -+ -+/* Get the trusted anchor for pkix */ -+ -+CERTCertificate * getRoot(CERTCertificate *cert, -+ SECCertificateUsage certUsage) -+{ -+ CERTCertificate *root = NULL; -+ CERTCertListNode *node = NULL; -+ -+ if( !cert ) { -+ goto finish; -+ } -+ -+ CERTCertList *certList = CERT_GetCertChainFromCert(cert, -+ PR_Now(), -+ certUsage); -+ -+ if( certList == NULL) { -+ goto finish; -+ } -+ -+ for (node = CERT_LIST_HEAD(certList); -+ !CERT_LIST_END(node, certList); -+ node = CERT_LIST_NEXT(node)) { -+ -+ /* try to find the root */ -+ if( node->cert && node->cert->isRoot ) { -+ root = CERT_DupCertificate(node->cert) ; -+ } -+ } -+ -+finish: -+ -+ CERT_DestroyCertList (certList); -+ return root; -+} -+ -+/* Verify a cert using explicit PKIX call. -+ * For now only used in OCSP AIA context. -+ * The result of this call will be a full chain -+ * and leaf network AIA ocsp validation. -+ * The policy param will be used in the future to -+ * handle more scenarios. -+ */ -+ -+SECStatus JSSL_verifyCertPKIX(CERTCertificate *cert, -+ SECCertificateUsage certUsage,secuPWData *pwdata, int ocspPolicy, -+ CERTVerifyLog *log, SECCertificateUsage *usage) -+{ -+ -+ /* put the first set of possible flags internally here first */ -+ /* later there could be a more complete list to choose from */ -+ /* support our hard core fetch aia ocsp policy for now */ -+ -+ static PRUint64 ocsp_Enabled_Hard_Policy_LeafFlags[2] = { -+ /* crl */ -+ 0, -+ /* ocsp */ -+ CERT_REV_M_TEST_USING_THIS_METHOD | -+ CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO -+ }; -+ -+ static PRUint64 ocsp_Enabled_Hard_Policy_ChainFlags[2] = { -+ /* crl */ -+ 0, -+ /* ocsp */ -+ CERT_REV_M_TEST_USING_THIS_METHOD | -+ CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO -+ }; -+ -+ static CERTRevocationMethodIndex -+ ocsp_Enabled_Hard_Policy_Method_Preference = { -+ cert_revocation_method_ocsp -+ }; -+ -+ static CERTRevocationFlags ocsp_Enabled_Hard_Policy = { -+ { /* leafTests */ -+ 2, -+ ocsp_Enabled_Hard_Policy_LeafFlags, -+ 1, -+ &ocsp_Enabled_Hard_Policy_Method_Preference, -+ 0 }, -+ { /* chainTests */ -+ 2, -+ ocsp_Enabled_Hard_Policy_ChainFlags, -+ 1, -+ &ocsp_Enabled_Hard_Policy_Method_Preference, -+ 0 } -+ }; -+ -+ /* for future expansion */ -+ -+ CERTValOutParam cvout[20] = {0}; -+ CERTValInParam cvin[20] = {0}; -+ -+ int inParamIndex = 0; -+ int outParamIndex = 0; -+ CERTRevocationFlags *rev = NULL; -+ -+ CERTCertList *trustedCertList = NULL; -+ -+ PRBool fetchCerts = PR_FALSE; -+ -+ SECStatus res = SECFailure; -+ if(cert == NULL) { -+ goto finish; -+ } -+ -+ if(ocspPolicy != OCSP_LEAF_AND_CHAIN_POLICY) { -+ goto finish; -+ } -+ -+ /* Force the strict ocsp network check on chain -+ and leaf. -+ */ -+ -+ fetchCerts = PR_TRUE; -+ rev = &ocsp_Enabled_Hard_Policy; -+ -+ /* fetch aia over net */ -+ -+ cvin[inParamIndex].type = cert_pi_useAIACertFetch; -+ cvin[inParamIndex].value.scalar.b = fetchCerts; -+ inParamIndex++; -+ -+ /* time */ -+ -+ cvin[inParamIndex].type = cert_pi_date; -+ cvin[inParamIndex].value.scalar.time = PR_Now(); -+ inParamIndex++; -+ -+ /* flags */ -+ -+ cvin[inParamIndex].type = cert_pi_revocationFlags; -+ cvin[inParamIndex].value.pointer.revocation = rev; -+ inParamIndex++; -+ -+ -+ /* establish trust anchor */ -+ -+ CERTCertificate *root = getRoot(cert,certUsage); -+ -+ /* Try to add the root as the trust anchor so all the -+ other memebers of the ca chain will get validated. -+ */ -+ -+ if( root != NULL ) { -+ trustedCertList = CERT_NewCertList(); -+ CERT_AddCertToListTail(trustedCertList, root); -+ -+ cvin[inParamIndex].type = cert_pi_trustAnchors; -+ cvin[inParamIndex].value.pointer.chain = trustedCertList; -+ -+ inParamIndex++; -+ } -+ -+ cvin[inParamIndex].type = cert_pi_end; -+ -+ if(log != NULL) { -+ cvout[outParamIndex].type = cert_po_errorLog; -+ cvout[outParamIndex].value.pointer.log = log; -+ outParamIndex ++; -+ } -+ -+ int usageIndex = 0; -+ if(usage != NULL) { -+ usageIndex = outParamIndex; -+ cvout[outParamIndex].type = cert_po_usages; -+ cvout[outParamIndex].value.scalar.usages = 0; -+ outParamIndex ++; -+ } -+ -+ cvout[outParamIndex].type = cert_po_end; -+ -+ res = CERT_PKIXVerifyCert(cert, certUsage, cvin, cvout, &pwdata); -+ -+finish: -+ /* clean up any trusted cert list */ -+ -+ if (trustedCertList) { -+ CERT_DestroyCertList(trustedCertList); -+ trustedCertList = NULL; -+ } -+ -+ if(root) { -+ CERT_DestroyCertificate(root); -+ root = NULL; -+ } -+ -+ if(res == SECSuccess && usage) { -+ *usage = cvout[usageIndex].value.scalar.usages; -+ } -+ -+ return res; -+} -diff --git a/org/mozilla/jss/ssl/jssl.h b/org/mozilla/jss/ssl/jssl.h -index 571c2a4..02771f8 100644 ---- a/jss/org/mozilla/jss/ssl/jssl.h -+++ b/jss/org/mozilla/jss/ssl/jssl.h -@@ -5,8 +5,27 @@ - #ifndef ORG_MOZILLA_JSS_SSL_JSSL_H - #define ORG_MOZILLA_JSS_SSL_JSSL_H - -+/* ocsp policy constants */ -+ -+/* ocsp policy constants */ -+static const int OCSP_NO_POLICY = 0; -+static const int OCSP_NORMAL_POLICY = 1; -+static const int OCSP_LEAF_AND_CHAIN_POLICY = 2; -+ - #include - -+typedef struct -+{ -+ enum -+ { -+ PW_NONE = 0, -+ PW_FROMFILE = 1, -+ PW_PLAINTEXT = 2, -+ PW_EXTERNAL = 3 -+ } source; -+ char *data; -+} secuPWData; -+ - struct JSSL_SocketData { - PRFileDesc *fd; - jobject socketObject; /* weak global ref */ -@@ -120,4 +139,14 @@ JSS_SSL_processExceptions(JNIEnv *env, PRFilePrivate *priv); - - void JSSL_throwSSLSocketException(JNIEnv *env, char *message); - -+int -+JSSL_getOCSPPolicy(); -+ -+ -+SECStatus -+JSSL_verifyCertPKIX(CERTCertificate *cert, -+ SECCertificateUsage certUsage, -+ secuPWData *pwdata, int ocspPolicy, -+ CERTVerifyLog *log,SECCertificateUsage *usage); -+ - #endif -diff --git a/org/mozilla/jss/util/java_ids.h b/org/mozilla/jss/util/java_ids.h -index b69a204..523642a 100644 ---- a/jss/org/mozilla/jss/util/java_ids.h -+++ b/jss/org/mozilla/jss/util/java_ids.h -@@ -277,6 +277,15 @@ PR_BEGIN_EXTERN_C - #define GET_BUF_SIZE_SIG "()I" - - /* -+ * CryptoManager -+ * -+*/ -+ -+#define CRYPTO_MANAGER_NAME "org/mozilla/jss/CryptoManager" -+#define GET_OCSP_POLICY_NAME "getOCSPPolicy" -+#define GET_OCSP_POLICY_SIG "()I" -+ -+/* - * SocketBase - */ - #define SOCKET_BASE_NAME "org/mozilla/jss/ssl/SocketBase" --- -1.8.3.1 - diff --git a/SOURCES/jss-fix-README.patch b/SOURCES/jss-fix-README.patch deleted file mode 100644 index e2c8020..0000000 --- a/SOURCES/jss-fix-README.patch +++ /dev/null @@ -1,67 +0,0 @@ -commit 76f7c710435d28c9dc8cad8540615ba73f3c00c4 -Author: Alexander Scheel -Date: Thu May 31 08:17:15 2018 -0400 - - Updated README instructions for git - - Signed-off-by: Alexander Scheel - -diff --git a/README b/README -index 5a1bc49c..9f1929ac 100644 ---- a/jss/README -+++ b/jss/README -@@ -17,7 +17,7 @@ - (There is no need to clone every time. For additional builds, - simply use: - cd nspr; hg pull -u -v; cd ..; cd nss; hg pull -u -v; cd ..; -- cd jss; hg pull -u -v; cd .. -+ cd jss; git pull -u -v; cd .. - ) - - (b) Alternatively, for upstream builds which use -@@ -39,7 +39,7 @@ - - (There is no need to clone every time. For additional builds, - simply use: -- cd jss; hg pull -u -v; cd .. -+ cd jss; git pull -u -v; cd .. - ) - - -@@ -164,7 +164,7 @@ - good practice to create a "regular tag" to the source code at these - various points in time using the following format: - -- # hg tag -m "message" JSS___YYYYMMDD -+ # git tag -m "message" JSS___YYYYMMDD - - where: = JSS Major Version Number - = JSS Minor Version Number -@@ -174,10 +174,10 @@ - - For example: - -- # hg id -- b3e864205ff0+ tip -+ # git rev-parse HEAD -+ b3e864205ff0... - -- # hg tag -m "Added tag JSS_4_4_20170328 for changeset b3e864205ff0" JSS_4_4_20170328 -+ # git tag -m "Added tag JSS_4_4_20170328 for changeset b3e864205ff0" JSS_4_4_20170328 - - At the appropriate time, a new major.minor version may be created. At this - time, it is important to create a maintenance branch for any future changes -@@ -185,10 +185,10 @@ - - For example: - -- # hg id -- f00f00f00f00+ tip -+ # git rev-parse HEAD -+ f00f00f00f00... - -- # hg branch -m "Created branch JSS_4_4_BRANCH for changeset f00f00f00f00" JSS_4_4_BRANCH -+ # git checkout -b JSS_4_4_BRANCH - - - (8) Known Issues diff --git a/SOURCES/jss-fix-algorithm-identifier-encode-decode.patch b/SOURCES/jss-fix-algorithm-identifier-encode-decode.patch deleted file mode 100644 index 6f39b7c..0000000 --- a/SOURCES/jss-fix-algorithm-identifier-encode-decode.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 7c7a97f60c1b3400b921981a3cd9e9aae4f28987 Mon Sep 17 00:00:00 2001 -From: Christina Fu -Date: Tue, 26 Jun 2018 17:59:28 -0700 -Subject: [PATCH] Ticket 12 AlgorithmIdentifier decode/encode process alters - original data - -This patch provides fix to ensure that the encoding and decoding of an AlgorithmIdentifier -structure would not alter the data. - -credit: original fix suggestion provided by david.k.stutzman2.ctr@mail.mil - -fixes https://pagure.io/jss/issue/12 ---- - org/mozilla/jss/pkix/primitive/AlgorithmIdentifier.java | 13 +------------ - 1 file changed, 1 insertion(+), 12 deletions(-) - -diff --git a/org/mozilla/jss/pkix/primitive/AlgorithmIdentifier.java b/org/mozilla/jss/pkix/primitive/AlgorithmIdentifier.java -index 0662f76..3487707 100644 ---- a/jss/org/mozilla/jss/pkix/primitive/AlgorithmIdentifier.java -+++ b/jss/org/mozilla/jss/pkix/primitive/AlgorithmIdentifier.java -@@ -103,19 +103,8 @@ public static class Template implements ASN1Template { - Assert._assert( seq.size() == 2 ); - - OBJECT_IDENTIFIER algOID = (OBJECT_IDENTIFIER)seq.elementAt(0); -- boolean allowParams = true; -- try { -- if (algOID.equals(SignatureAlgorithm.ECSignatureWithSHA256Digest.toOID()) || -- algOID.equals(SignatureAlgorithm.ECSignatureWithSHA384Digest.toOID()) || -- algOID.equals(SignatureAlgorithm.ECSignatureWithSHA512Digest.toOID())) { -- allowParams = false; -- } -- } catch (NoSuchAlgorithmException e) { -- // System.out.println("JSS: AlgorithmIdentifier:decode: " + e.toString()); -- // unlikely to happen; swallow it. treat it as allowParams; -- } - -- if (!allowParams) { -+ if (seq.elementAt(1) == null) { - return new AlgorithmIdentifier( - algOID // OID - ); --- -2.14.4 - diff --git a/SOURCES/jss-fix-classpath.patch b/SOURCES/jss-fix-classpath.patch deleted file mode 100644 index fb350ab..0000000 --- a/SOURCES/jss-fix-classpath.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/build_java.pl b/build_java.pl -index 78cc5fd0..b74a9338 100644 ---- a/jss/build_java.pl -+++ b/jss/build_java.pl -@@ -162,8 +162,9 @@ sub setup_vars { - } - $jni_header_dir = "$dist_dir/private/jss/_jni"; - -+ $classpath = "-classpath /usr/share/java/apache-commons-codec.jar:/usr/share/java/commons-lang.jar:/usr/share/java/ldapjdk.jar:"; - if( $jce_jar ) { -- $classpath = "-classpath $jce_jar"; -+ $classpath .= ":$jce_jar"; - } - - # retrieve present working directory diff --git a/SOURCES/jss-update-jss-spec-in-template.patch b/SOURCES/jss-update-jss-spec-in-template.patch deleted file mode 100644 index 970f4ea..0000000 --- a/SOURCES/jss-update-jss-spec-in-template.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 56979bf6b22a81355fe948d3c28ec78d925db1d8 Mon Sep 17 00:00:00 2001 -From: Jack Magne -Date: Thu, 21 Jun 2018 22:18:38 -0600 -Subject: [PATCH] Update dependencies in 'jss.spec.in' template - ---- - jss.spec.in | 27 ++++++++++++++++++++++----- - 1 file changed, 22 insertions(+), 5 deletions(-) - -diff --git a/jss.spec.in b/jss.spec.in -index f1e629f2..4a240138 100644 ---- a/jss/jss.spec.in -+++ b/jss/jss.spec.in -@@ -10,13 +10,22 @@ Version: 4.4.4 - Release: 1%{?_timestamp}%{?_commit_id}%{?dist} - - # To generate the source tarball: --# --# git clone https://github.com/dogtagpki/jss.git --# cd jss --# git archive --format=tar.gz --prefix jss-VERSION/jss/ -o jss-VERSION.tar.gz -v HEAD --# -+# $ git clone https://github.com/dogtagpki/jss.git -+# $ cd jss -+# $ git archive \ -+# --format=tar.gz \ -+# --prefix jss-VERSION/jss/ \ -+# -o jss-VERSION.tar.gz \ -+# - Source: https://github.com/dogtagpki/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz - -+# To create a patch for all changes since a version tag: -+# $ git format-patch \ -+# --stdout \ -+# \ -+# > jss-VERSION-RELEASE.patch -+# Patch: jss-VERSION-RELEASE.patch -+ - Conflicts: idm-console-framework < 1.1.17-4 - Conflicts: pki-base < 10.4.0 - Conflicts: tomcatjss < 7.2.1 -@@ -31,10 +40,18 @@ BuildRequires: jpackage-utils - %if 0%{?fedora} >= 25 || 0%{?rhel} > 7 - BuildRequires: perl-interpreter - %endif -+BuildRequires: apache-commons-lang -+BuildRequires: apache-commons-codec -+BuildRequires: ldapjdk -+ - - Requires: nss >= 3.28.4-6 - Requires: java-headless - Requires: jpackage-utils -+Requires: apache-commons-lang -+Requires: apache-commons-codec -+Requires: ldapjdk -+ - - %description - Java Security Services (JSS) is a java native interface which provides a bridge --- -2.14.4 - diff --git a/SPECS/jss.spec b/SPECS/jss.spec index 66463c6..91f266d 100644 --- a/SPECS/jss.spec +++ b/SPECS/jss.spec @@ -6,29 +6,24 @@ Summary: Java Security Services (JSS) URL: http://www.dogtagpki.org/wiki/JSS License: MPLv1.1 or GPLv2+ or LGPLv2+ -Version: 4.4.4 -Release: 5%{?_timestamp}%{?_commit_id}%{?dist} +Version: 4.4.6 +Release: 1%{?_timestamp}%{?_commit_id}%{?dist} # To generate the source tarball: -# -# git clone https://github.com/dogtagpki/jss.git -# cd jss -# git archive --format=tar.gz --prefix jss-VERSION/jss/ -o jss-VERSION.tar.gz -v HEAD -# +# $ git clone https://github.com/dogtagpki/jss.git +# $ cd jss +# $ git tag v4.4. +# $ git push origin v4.4. +# Then go to https://github.com/dogtagpki/jss/releases and download the source +# tarball. Source: https://github.com/dogtagpki/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz -Patch0: jss-fix-classpath.patch -Patch1: jss-fix-README.patch -Patch2: jss-update-jss-spec-in-template.patch -Patch3: jss-add-build-sh.patch -Patch4: jss-add-travis-yml.patch -Patch5: jss-add-x509-cert-and-crl-migration.patch -Patch6: jss-fix-algorithm-identifier-encode-decode.patch -Patch7: jss-add-TLS-SHA384-ciphers.patch -Patch8: jss-disallow-curve-x25519-in-FIPS-mode.patch -Patch9: jss-enable-AIA-OCSP-cert-checking-for-entire-cert-chain.patch -Patch10: jss-enable-AIA-OCSP-cert-checking-for-entire-cert-chain-2.patch - +# To create a patch for all changes since a version tag: +# $ git format-patch \ +# --stdout \ +# \ +# > jss-VERSION-RELEASE.patch +# Patch: jss-VERSION-RELEASE.patch Conflicts: idm-console-framework < 1.1.17-4 Conflicts: pki-base < 10.4.0 @@ -39,21 +34,19 @@ BuildRequires: git BuildRequires: nss-devel >= 3.28.4-6 BuildRequires: nspr-devel >= 4.13.1 -BuildRequires: java-devel +BuildRequires: java-1.8.0-openjdk-devel BuildRequires: jpackage-utils %if 0%{?fedora} >= 25 || 0%{?rhel} > 7 BuildRequires: perl-interpreter %endif BuildRequires: apache-commons-lang BuildRequires: apache-commons-codec -BuildRequires: ldapjdk Requires: nss >= 3.28.4-6 -Requires: java-headless +Requires: java-1.8.0-openjdk-headless Requires: jpackage-utils Requires: apache-commons-lang Requires: apache-commons-codec -Requires: ldapjdk %description Java Security Services (JSS) is a java native interface which provides a bridge @@ -74,28 +67,27 @@ This package contains the API documentation for JSS. ################################################################################ %prep -#%autosetup -n %{name}-%{version} -p 1 -S git -%setup -q -n %{name}-%{version} -pushd jss -# Force use of 'patch' rather than 'git apply' by injecting "/jss/" prefix -# on patches of existing files located in top-level directory . . . -%patch0 -p2 -%patch1 -p2 -%patch2 -p2 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p2 -%patch7 -p2 -%patch8 -p2 -%patch9 -p2 -%patch10 -p2 -popd +%autosetup -n %{name}-%{version} -p 1 -S git + +# Prior to version 4.4.5, the source code were stored under "jss-/jss" +# path in the source tarball. Starting from version 4.4.5, the files will be +# stored under "jss-" path. However, since the build system is still +# using the old path (introduced via sandboxing), the unpacked source code has +# to be moved to the old path with the following commands. Otherwise, even +# though we're linking against system libraries, the build will complain about +# a missing sandbox. + +cd .. +mv %{name}-%{version} jss +mkdir %{name}-%{version} +mv jss %{name}-%{version} ################################################################################ %build -#%set_build_flags +%if 0%{?fedora} >= 27 +%set_build_flags +%endif [ -z "$JAVA_HOME" ] && export JAVA_HOME=%{_jvmdir}/java [ -z "$USE_INSTALLED_NSPR" ] && export USE_INSTALLED_NSPR=1 @@ -186,14 +178,8 @@ cp -p jss/*.txt $RPM_BUILD_ROOT%{_javadocdir}/%{name}-%{version} ################################################################################ %changelog -* Fri Feb 15 2019 Dogtag PKI Team 4.4.4-5 -- Bugzilla #1671247 - CC: Enable AIA OCSP cert checking for entire cert - chain [rhel-7.6.z] (jmagne) - -* Thu Jan 31 2019 Dogtag PKI Team 4.4.4-4 -- Bugzilla #1671244 - x25519 allowed in FIPS mode [rhel-7.6.z] (ascheel) -- Bugzilla #1671247 - CC: Enable AIA OCSP cert checking for entire cert - chain [rhel-7.6.z] (jmagne) +* Fri Mar 15 2019 Dogtag PKI Team 4.4.6-1 +- Bugzilla #1659527 - Rebase JSS in RHEL 7.7 (ascheel) * Thu Jul 5 2018 Dogtag PKI Team 4.4.4-3 - Bugzilla #1534772 - org.mozilla.jss.pkix.primitive.AlgorithmIdentifier