diff --git a/.gitignore b/.gitignore index d7181f9..edcc16f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,55 @@ +# Local build files +jss-*.src.rpm +jss-*/ +x86_64/ +.build-*.log + +# Releases jss-4.2.6.tar.gz /jss-4.2.6.tar.gz /jss-4.4.0.tar.gz /jss-4.4.1.tar.gz /jss-4.4.2.tar.gz +/jss-4.4.3.tar.gz /jss-4.4.4.tar.gz +/jss-4.5.0-a1.tar.gz +/jss-4.5.0-a2.tar.gz +/jss-4.5.0-a3.tar.gz +/jss-4.5.0-a4.tar.gz +/jss-4.5.0-b1.tar.gz +/jss-4.5.0.tar.gz +/jss-4.5.1.tar.gz +/jss-4.5.2.tar.gz +/jss-4.5.3.tar.gz +/jss-4.6.1.tar.gz +/jss-4.6.2.tar.gz +/jss-4.6.3.tar.gz +/jss-4.6.4.tar.gz +/jss-4.7.0-b2.tar.gz +/jss-4.7.0-b4.tar.gz +/jss-4.7.0.tar.gz +/jss-4.7.2.tar.gz +/jss-4.7.3.tar.gz +/jss-4.8.0-b1.tar.gz +/jss-4.8.0.tar.gz +/jss-4.8.1.tar.gz +/jss-4.9.0-alpha1.tar.gz +/jss-5.0.0-alpha1.tar.gz +/jss-5.0.0-alpha2.tar.gz +/jss-5.0.0-beta1.tar.gz +/jss-5.0.0.tar.gz +/jss-5.1.0-alpha2.tar.gz +/jss-5.1.0.tar.gz +/jss-5.2.0-beta1.tar.gz +/jss-5.2.0-beta2.tar.gz +/jss-5.2.0.tar.gz +/jss-5.3.0.tar.gz +/jss-5.4.2.tar.gz +/jss-5.5.0-alpha2.tar.gz +/jss-5.5.0.tar.gz +/jss-5.5.1.tar.gz +/jss-5.6.0-alpha1.tar.gz +/jss-5.8.0-beta1.tar.gz +/jss-5.8.0-beta3.tar.gz +/jss-5.8.0-beta4.tar.gz +/jss-5.8.0.tar.gz diff --git a/.packit.yaml b/.packit.yaml new file mode 100644 index 0000000..73d2062 --- /dev/null +++ b/.packit.yaml @@ -0,0 +1,30 @@ +--- +# See the documentation for more information: +# https://packit.dev/docs/configuration/ +specfile_path: jss.spec + +# add or remove files that should be synced +files_to_sync: + - jss.spec + - .packit.yaml + +# Allow dist git reactions on packit and ckelley commits and PRs +allowed_pr_authors: + - packit + - ckelleyRH +allowed_committers: + - packit + - ckelleyRH + +upstream_package_name: jss +# downstream (Fedora/CentOS) RPM package name +downstream_package_name: jss +# see: https://packit.dev/docs/configuration/#upstream_tag_template +upstream_tag_template: "v{version}" + +jobs: + - job: propose_downstream + trigger: release + dist_git_branches: + - fedora-development +# - centos-stream-9-x86_64 # When Packit integration with CentOS is avaiable, enable this diff --git a/README.packit b/README.packit new file mode 100644 index 0000000..07bc213 --- /dev/null +++ b/README.packit @@ -0,0 +1,3 @@ +This repository is maintained by packit. +https://packit.dev/ +The file was generated using packit 0.76.0.post10+g0dcb396. diff --git a/copr-build.sh b/copr-build.sh new file mode 100755 index 0000000..156c705 --- /dev/null +++ b/copr-build.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +REPO=$1 + +if [ "$REPO" == "" ]; then + REPO="pki-10.6" +fi + +fedpkg copr-build --nowait $REPO diff --git a/jss-add-TLS-SHA384-ciphers.patch b/jss-add-TLS-SHA384-ciphers.patch deleted file mode 100644 index f67601f..0000000 --- a/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; --- -1.8.3.1 - diff --git a/jss-add-build-sh.patch b/jss-add-build-sh.patch deleted file mode 100644 index 91feff3..0000000 --- a/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/jss-add-travis-yml.patch b/jss-add-travis-yml.patch deleted file mode 100644 index c4e3673..0000000 --- a/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/jss-add-x509-cert-and-crl-migration.patch b/jss-add-x509-cert-and-crl-migration.patch deleted file mode 100644 index 7399d2e..0000000 --- a/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/jss-fix-README.patch b/jss-fix-README.patch deleted file mode 100644 index e2c8020..0000000 --- a/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/jss-fix-algorithm-identifier-encode-decode.patch b/jss-fix-algorithm-identifier-encode-decode.patch deleted file mode 100644 index 415c87e..0000000 --- a/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 - ); --- -1.8.3.1 - diff --git a/jss-fix-classpath.patch b/jss-fix-classpath.patch deleted file mode 100644 index fb350ab..0000000 --- a/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/jss-update-jss-spec-in-template.patch b/jss-update-jss-spec-in-template.patch deleted file mode 100644 index 970f4ea..0000000 --- a/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/jss.spec b/jss.spec index 0b435c8..794ee73 100644 --- a/jss.spec +++ b/jss.spec @@ -2,54 +2,117 @@ Name: jss ################################################################################ -Summary: Java Security Services (JSS) -URL: http://www.dogtagpki.org/wiki/JSS -License: MPLv1.1 or GPLv2+ or LGPLv2+ +%global vendor_id dogtag +%global product_id %{vendor_id}-jss -Version: 4.4.4 -Release: 3%{?_timestamp}%{?_commit_id}%{?dist} +# Upstream version number: +%global major_version 5 +%global minor_version 8 +%global update_version 0 + +# Downstream release number: +# - development/stabilization (unsupported): 0. where n >= 1 +# - GA/update (supported): where n >= 1 +%global release_number 1 + +# Development phase: +# - development (unsupported): alpha where n >= 1 +# - stabilization (unsupported): beta where n >= 1 +# - GA/update (supported): +#global phase + +%if 0%{?rhel} && 0%{?rhel} >= 10 +%global enable_nss_version_pqc_def_flag -DENABLE_NSS_VERSION_PQC_DEF=ON +%endif + +%undefine timestamp +%undefine commit_id + +Summary: Java Security Services (JSS) +URL: https://github.com/dogtagpki/jss +License: (MPL-1.1 OR GPL-2.0-or-later OR LGPL-2.1-or-later) AND Apache-2.0 +Version: %{major_version}.%{minor_version}.%{update_version} +Release: %{release_number}%{?phase:.}%{?phase}%{?timestamp:.}%{?timestamp}%{?commit_id:.}%{?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 -# -Source: https://github.com/dogtagpki/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz +# $ git clone https://github.com/dogtagpki/jss.git +# $ cd jss +# $ git tag v4.5. +# $ git push origin v4.5. +# Then go to https://github.com/dogtagpki/jss/releases and download the source +# tarball. +Source: https://github.com/dogtagpki/jss/archive/v%{version}%{?phase:-}%{?phase}/jss-%{version}%{?phase:-}%{?phase}.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 +# 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 - -# autosetup -BuildRequires: git - -BuildRequires: nss-devel >= 3.28.4-6 -BuildRequires: nspr-devel >= 4.13.1 -BuildRequires: java-devel -BuildRequires: jpackage-utils -%if 0%{?fedora} >= 25 || 0%{?rhel} > 7 -BuildRequires: perl-interpreter +%if 0%{?java_arches:1} +ExclusiveArch: %{java_arches} +%else +ExcludeArch: i686 %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 +################################################################################ +# Java +################################################################################ + +# use Java 17 on Fedora 39 or older and RHEL 9 or older +# otherwise, use Java 21 + +# maven-local is a subpackage of javapackages-tools + +%if 0%{?fedora} && 0%{?fedora} >= 43 || 0%{?rhel} >= 11 + +%define java_devel java-25-openjdk-devel +%define java_headless java-25-openjdk-headless +%define java_home %{_jvmdir}/jre-25-openjdk +%define maven_local maven-local-openjdk25 + +%else + +%define java_devel java-21-openjdk-devel +%define java_headless java-21-openjdk-headless +%define java_home %{_jvmdir}/jre-21-openjdk +%define maven_local maven-local + +%endif + +################################################################################ +# Build Options +################################################################################ + +# By default the javadoc package will be built unless --without javadoc +# option is specified. + +%bcond_without javadoc + +# By default the tests package will be built and the tests will executed +# unless --without tests option is specified. + +%bcond_without tests + +################################################################################ +# Build Dependencies +################################################################################ + +BuildRequires: make +BuildRequires: cmake >= 3.14 +BuildRequires: zip +BuildRequires: unzip + +BuildRequires: gcc-c++ +BuildRequires: nss-devel >= 3.101 +BuildRequires: nss-tools >= 3.101 + +BuildRequires: %{java_devel} +BuildRequires: %{maven_local} +BuildRequires: mvn(org.apache.commons:commons-lang3) +BuildRequires: mvn(org.slf4j:slf4j-api) +BuildRequires: mvn(org.slf4j:slf4j-jdk14) %description Java Security Services (JSS) is a java native interface which provides a bridge @@ -57,141 +120,390 @@ for java-based applications to use native Network Security Services (NSS). This only works with gcj. Other JREs require that JCE providers be signed. ################################################################################ -%package javadoc +%package -n %{product_id} +################################################################################ + +Summary: Java Security Services (JSS) + +Requires: nss >= 3.101 + +Requires: %{java_headless} +Requires: mvn(org.apache.commons:commons-lang3) +Requires: mvn(org.slf4j:slf4j-api) +Requires: mvn(org.slf4j:slf4j-jdk14) + +Obsoletes: jss < %{version}-%{release} +Provides: jss = %{version}-%{release} +Provides: jss = %{major_version}.%{minor_version} +Provides: %{product_id} = %{major_version}.%{minor_version} + +Conflicts: ldapjdk < 4.20 +Conflicts: idm-console-framework < 1.2 +Conflicts: pki-base < 10.10.0 + +%description -n %{product_id} +Java Security Services (JSS) is a java native interface which provides a bridge +for java-based applications to use native Network Security Services (NSS). +This only works with gcj. Other JREs require that JCE providers be signed. + +################################################################################ +%package -n %{product_id}-tomcat +################################################################################ + +Summary: Java Security Services (JSS) Connector for Tomcat + +# Tomcat +BuildRequires: mvn(org.apache.tomcat:tomcat-catalina) >= 10.1.36 +BuildRequires: mvn(org.apache.tomcat:tomcat-coyote) >= 10.1.36 +BuildRequires: mvn(org.apache.tomcat:tomcat-juli) >= 10.1.36 + +Requires: %{product_id} = %{version}-%{release} +Requires: mvn(org.apache.tomcat:tomcat-catalina) >= 10.1.36 +Requires: mvn(org.apache.tomcat:tomcat-coyote) >= 10.1.36 +Requires: mvn(org.apache.tomcat:tomcat-juli) >= 10.1.36 + +# Tomcat JSS has been replaced with JSS Connector for Tomcat. +# This will remove installed Tomcat JSS packages. +Obsoletes: tomcatjss <= 8.5 +Conflicts: tomcatjss <= 8.5 +Obsoletes: %{vendor_id}-tomcatjss <= 8.5 +Conflicts: %{vendor_id}-tomcatjss <= 8.5 + +%if 0%{?rhel} <= 8 +# PKI Servlet Engine has been replaced with Tomcat. +# This will remove installed PKI Servlet Engine packages. +Obsoletes: pki-servlet-engine <= 9.0 +Conflicts: pki-servlet-engine <= 9.0 +%endif + +%description -n %{product_id}-tomcat +JSS Connector for Tomcat is a Java Secure Socket Extension (JSSE) +module for Apache Tomcat that uses Java Security Services (JSS), +a Java interface to Network Security Services (NSS). + +################################################################################ +%package -n %{product_id}-tools +################################################################################ + +Summary: Java Security Services (JSS) Tools + +Provides: jss-tools = %{version}-%{release} +Provides: jss-tools = %{major_version}.%{minor_version} +Provides: %{product_id}-tools = %{major_version}.%{minor_version} + +# Some PKI tools have been moved into jss-tools. +Conflicts: pki-tools < 11.6 +Conflicts: %{vendor_id}-pki-tools < 11.6 + +%description -n %{product_id}-tools +This package contains JSS tools. + +%if %{with javadoc} +################################################################################ +%package -n %{product_id}-javadoc ################################################################################ Summary: Java Security Services (JSS) Javadocs -Group: Documentation -Requires: jss = %{version}-%{release} -%description javadoc +Obsoletes: jss-javadoc < %{version}-%{release} +Provides: jss-javadoc = %{version}-%{release} +Provides: jss-javadoc = %{major_version}.%{minor_version} +Provides: %{product_id}-javadoc = %{major_version}.%{minor_version} + +%description -n %{product_id}-javadoc This package contains the API documentation for JSS. +%endif + +%if %{with tests} +################################################################################ +%package -n %{product_id}-tests +################################################################################ + +Summary: Java Security Services (JSS) Tests + +BuildRequires: mvn(org.junit.jupiter:junit-jupiter) +BuildRequires: mvn(org.opentest4j:opentest4j) + +%description -n %{product_id}-tests +This package provides test suite for JSS. + +# with tests +%endif ################################################################################ %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 -popd +%autosetup -n jss-%{version}%{?phase:-}%{?phase} -p 1 + +# disable native modules since they will be built by CMake +%pom_disable_module native +%pom_disable_module symkey + +# do not ship examples +%pom_disable_module examples + +# flatten-maven-plugin is not available in RPM +%pom_remove_plugin org.codehaus.mojo:flatten-maven-plugin + +# specify Maven artifact locations +%mvn_file org.dogtagpki.jss:jss-tomcat jss/jss-tomcat +%mvn_file org.dogtagpki.jss:jss-tomcat-10.1 jss/jss-tomcat-10.1 + +# specify Maven artifact packages +%mvn_package org.dogtagpki.jss:jss-tomcat jss-tomcat +%mvn_package org.dogtagpki.jss:jss-tomcat-10.1 jss-tomcat ################################################################################ %build +################################################################################ +# Set build flags for CMake +# (see /usr/lib/rpm/macros.d/macros.cmake) %set_build_flags -[ -z "$JAVA_HOME" ] && export JAVA_HOME=%{_jvmdir}/java -[ -z "$USE_INSTALLED_NSPR" ] && export USE_INSTALLED_NSPR=1 -[ -z "$USE_INSTALLED_NSS" ] && export USE_INSTALLED_NSS=1 +export JAVA_HOME=%{java_home} -# Enable compiler optimizations and disable debugging code -# NOTE: If you ever need to create a debug build with optimizations disabled -# just comment out this line and change in the %%install section below the -# line that copies jars xpclass.jar to be xpclass_dbg.jar +# Enable compiler optimizations export BUILD_OPT=1 # Generate symbolic info for debuggers -XCFLAGS="-g $RPM_OPT_FLAGS" -export XCFLAGS +CFLAGS="-g $RPM_OPT_FLAGS" +export CFLAGS -PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 -PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 +# Check if we're in FIPS mode +modutil -dbdir /etc/pki/nssdb -chkfips true | grep -q enabled && export FIPS_ENABLED=1 -export PKG_CONFIG_ALLOW_SYSTEM_LIBS -export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS +# build Java code, run Java tests, and build Javadoc with Maven +%mvn_build %{!?with_tests:-f} %{!?with_javadoc:-j} -NSPR_INCLUDE_DIR=`/usr/bin/pkg-config --cflags-only-I nspr | sed 's/-I//'` -NSPR_LIB_DIR=`/usr/bin/pkg-config --libs-only-L nspr | sed 's/-L//'` - -NSS_INCLUDE_DIR=`/usr/bin/pkg-config --cflags-only-I nss | sed 's/-I//'` -NSS_LIB_DIR=`/usr/bin/pkg-config --libs-only-L nss | sed 's/-L//'` - -export NSPR_INCLUDE_DIR -export NSPR_LIB_DIR -export NSS_INCLUDE_DIR -export NSS_LIB_DIR - -%if 0%{?__isa_bits} == 64 -USE_64=1 -export USE_64 +# create links to Maven-built classes for CMake +mkdir -p %{_vpath_builddir}/classes/jss +ln -sf ../../../base/target/classes/org %{_vpath_builddir}/classes/jss +%if %{with tests} +mkdir -p %{_vpath_builddir}/classes/tests +ln -sf ../../../base/target/test-classes/org %{_vpath_builddir}/classes/tests %endif -# The Makefile is not thread-safe -make -C jss/coreconf -make -C jss -make -C jss javadoc +# create links to Maven-built JAR files for CMake +ln -sf ../base/target/jss.jar %{_vpath_builddir} +%if %{with tests} +ln -sf ../base/target/jss-tests.jar %{_vpath_builddir} +%endif + +# create links to Maven-built headers for CMake +mkdir -p %{_vpath_builddir}/include/jss +ln -sf ../../../base/target/include/_jni %{_vpath_builddir}/include/jss/_jni + +# mark Maven-built targets so that CMake will not rebuild them +mkdir -p %{_vpath_builddir}/.targets +touch %{_vpath_builddir}/.targets/finished_generate_java +%if %{with tests} +touch %{_vpath_builddir}/.targets/finished_tests_generate_java +%endif +%if %{with javadoc} +touch %{_vpath_builddir}/.targets/finished_generate_javadocs +%endif + +# build native code and run native tests with CMake +./build.sh \ + %{?_verbose:-v} \ + --work-dir=%{_vpath_builddir} \ + --prefix-dir=%{_prefix} \ + --include-dir=%{_includedir} \ + --lib-dir=%{_libdir} \ + --sysconf-dir=%{_sysconfdir} \ + --share-dir=%{_datadir} \ + --cmake="%{__cmake} %{?enable_nss_version_pqc_def_flag}" \ + --java-home=%{java_home} \ + --jni-dir=%{_jnidir} \ + --version=%{version} \ + --without-java \ + --without-javadoc \ + %{!?with_tests:--without-tests} \ + dist ################################################################################ %install - -# Copy the license files here so we can include them in %%doc -cp -p jss/MPL-1.1.txt . -cp -p jss/gpl.txt . -cp -p jss/lgpl.txt . - -# There is no install target so we'll do it by hand - -# jars -install -d -m 0755 $RPM_BUILD_ROOT%{_jnidir} -# NOTE: if doing a debug no opt build change xpclass.jar to xpclass_dbg.jar -install -m 644 dist/xpclass.jar ${RPM_BUILD_ROOT}%{_jnidir}/jss4.jar - -# We have to use the name libjss4.so because this is dynamically -# loaded by the jar file. -install -d -m 0755 $RPM_BUILD_ROOT%{_libdir}/jss -install -m 0755 dist/Linux*.OBJ/lib/libjss4.so ${RPM_BUILD_ROOT}%{_libdir}/jss/ -pushd ${RPM_BUILD_ROOT}%{_libdir}/jss - ln -fs %{_jnidir}/jss4.jar jss4.jar -popd - -# javadoc -install -d -m 0755 $RPM_BUILD_ROOT%{_javadocdir}/%{name}-%{version} -cp -rp dist/jssdoc/* $RPM_BUILD_ROOT%{_javadocdir}/%{name}-%{version} -cp -p jss/jss.html $RPM_BUILD_ROOT%{_javadocdir}/%{name}-%{version} -cp -p jss/*.txt $RPM_BUILD_ROOT%{_javadocdir}/%{name}-%{version} - -# No ldconfig is required since this library is loaded by Java itself. ################################################################################ -%files -%defattr(-,root,root,-) -%doc jss/jss.html jss/MPL-1.1.txt jss/gpl.txt jss/lgpl.txt -%{_libdir}/jss/* -%{_jnidir}/* -%{_libdir}/jss/lib*.so +# install Java binaries and Javadoc +%mvn_install + +# install jss.jar +mkdir -p %{buildroot}%{_javadir}/jss +cp base/target/jss.jar %{buildroot}%{_javadir}/jss/jss.jar + +# create links for backward compatibility +mkdir -p %{buildroot}%{_jnidir} +ln -sf ../../..%{_javadir}/jss/jss.jar %{buildroot}%{_jnidir}/jss.jar + +mkdir -p %{buildroot}%{_libdir}/jss +ln -sf ../../..%{_javadir}/jss/jss.jar %{buildroot}%{_libdir}/jss/jss.jar + +# install native binaries +./build.sh \ + %{?_verbose:-v} \ + --work-dir=%{_vpath_builddir} \ + --install-dir=%{buildroot} \ + --without-java \ + install + +# install tests binaries +%if %{with tests} +mkdir -p %{buildroot}%{_datadir}/jss/tests/lib +cp base/target/jss-tests.jar %{buildroot}%{_datadir}/jss/tests/lib +%endif ################################################################################ -%files javadoc +%files -n %{product_id} -f .mfiles +################################################################################ -%defattr(-,root,root,-) -%dir %{_javadocdir}/%{name}-%{version} -%{_javadocdir}/%{name}-%{version}/* +%doc jss.html +%license MPL-1.1.txt gpl.txt lgpl.txt symkey/LICENSE +%{_javadir}/jss/jss.jar +%{_jnidir}/jss.jar +%{_libdir}/jss/jss.jar +%{_libdir}/jss/libjss.so +%{_libdir}/jss/libjss-symkey.so + +################################################################################ +%files -n %{product_id}-tomcat -f .mfiles-jss-tomcat +################################################################################ + +################################################################################ +%files -n %{product_id}-tools +################################################################################ + +%{_bindir}/p12tool +%{_bindir}/p7tool +%{_bindir}/sslget + +%if %{with javadoc} +################################################################################ +%files -n %{product_id}-javadoc -f .mfiles-javadoc +################################################################################ +%endif + +%if %{with tests} +################################################################################ +%files -n %{product_id}-tests +################################################################################ + +%{_datadir}/jss/tests/ + +# with tests +%endif ################################################################################ %changelog +* Tue Nov 04 2025 Dogtag PKI Team 5.8.0-1 +- Rebase to JSS 5.8.0-1 -* Thu Jul 5 2018 Dogtag PKI Team 4.4.4-3 -- JSS Pagure Issue #12 - org.mozilla.jss.pkix.primitive.AlgorithmIdentifier - decode/encode process alters original data (cfu) -- JSS Pagure Issue #4 - JSS: Add support for TLS_*_SHA384 ciphers (cfu) +* Fri Aug 22 2025 Yaakov Selkowitz - 5.8.0-0.6.beta4 +- Build with Java 25 for ELN -* Thu Jun 21 2018 Dogtag PKI Team 4.4.4-2 -- JSS Pagure Issue #11 - (RFE) Migrate Dogtag x509 cert and crl - functionality to JSS (jmagne) +* Mon Aug 11 2025 Dogtag PKI Team 5.8.0-0.5.beta4 +- Rebuild for Fedora 43 -* Tue May 29 2018 Dogtag PKI Team 4.4.4-1 -- Rebased to JSS 4.4.4 +* Mon Aug 11 2025 Dogtag PKI Team 5.8.0-0.4.beta4.1 +- Rebase to JSS 5.8.0-beta4 -* Thu Apr 05 2018 Dogtag PKI Team 4.4.3-1 -- Rebased to JSS 4.4.3 -- Red Hat Bugzilla #1548548 - Partial Fedora build flags injection +* Mon Jul 28 2025 Dogtag PKI Team 5.8.0-0.3.beta3.1 +- Rebase to JSS 5.8.0-beta3 + +* Thu Jul 24 2025 Fedora Release Engineering - 5.8.0-0.1.beta1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + +* Wed Jul 09 2025 Dogtag PKI Team 5.8.0.1 +- Rebase to JSS 5.8.0-beta1 + +* Fri Jan 17 2025 Fedora Release Engineering - 5.6.0-0.1.alpha1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + +* Wed Nov 20 2024 Dogtag PKI Team 5.6.0-1 +- Rebase to JSS 5.6.0-alpha1 + +* Fri Oct 04 2024 Dogtag PKI Team 5.5.1-1 +- Rebase to JSS 5.5.1 + +* Thu Jul 18 2024 Fedora Release Engineering - 5.5.0-2.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Thu Feb 29 2024 Adam Williamson - 5.5.0-2 +- Really build against java-21 + +* Tue Feb 27 2024 Jiri Vanek - 5.5.0-1.1 +- Rebuilt for java-21-openjdk as system jdk + +* Wed Feb 21 2024 Dogtag PKI Team 5.5.0-1 +- Rebase to JSS 5.5.0 + +* Thu Feb 08 2024 Yaakov Selkowitz - 5.4.2-1.4 +- Fix compatibility with NSS 3.97 + +* Wed Jan 24 2024 Fedora Release Engineering - 5.4.2-1.3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Sat Jan 20 2024 Fedora Release Engineering - 5.4.2-1.2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Thu Jul 20 2023 Fedora Release Engineering - 5.4.2-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Fri Jun 16 2023 Packit - 5.4.2-1 +- Updating version to v5.4.2 (Chris Kelley) +- Upstream spec file changes to reduce diffs (Chris Kelley) +- Introduce Packit configuration for jss (Chris Kelley) + +* Tue Feb 07 2023 Dogtag PKI Team - 5.3.0-2 +- Update version number in JSSConfig.cmake + +* Tue Feb 07 2023 Dogtag PKI Team - 5.3.0-1 +- Rebase to JSS 5.3.0 + +* Thu Jan 19 2023 Fedora Release Engineering - 5.2.0-1.2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + +* Thu Jul 21 2022 Fedora Release Engineering - 5.2.0-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + +* Wed Jun 29 2022 Dogtag PKI Team - 5.2.0-1 +- Rebase to JSS 5.2.0 + +* Wed Apr 27 2022 Dogtag PKI Team - 5.2.0-0.3.beta2 +- Rebase to JSS 5.2.0-beta2 +- Rename packages to dogtag-jss + +* Mon Apr 11 2022 Dogtag PKI Team - 5.2.0-0.2.beta1 +- Rebase to JSS 5.2.0-beta1 + +* Mon Feb 14 2022 Dogtag PKI Team - 5.1.0-1 +- Rebase to JSS 5.1.0 + +* Sat Feb 05 2022 Jiri Vanek - 5.1.0-0.3.alpha2 +- Rebuilt for java-17-openjdk as system jdk + +* Thu Jan 20 2022 Fedora Release Engineering - 5.1.0-0.2.alpha2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + +* Fri Nov 26 2021 Dogtag PKI Team - 5.1.0-0.1.alpha2 +- Rebase to JSS 5.1.0-alpha2 + +* Thu Sep 30 2021 Dogtag PKI Team - 5.0.0-1 +- Rebase to JSS 5.0.0 + +* Wed Sep 29 2021 Dogtag PKI Team - 5.0.0-0.5.beta1 +- Drop BuildRequires and Requires on glassfish-jaxb-api + +* Fri Sep 03 2021 Dogtag PKI Team - 5.0.0-0.4.beta1 +- Rebase to JSS 5.0.0-beta1 + +* Thu Aug 12 2021 Dogtag PKI Team - 5.0.0-0.3.alpha2 +- Rebase to JSS 5.0.0-alpha2 + +* Thu Jul 22 2021 Fedora Release Engineering - 5.0.0-0.2.alpha1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + +* Tue Jun 22 2021 Dogtag PKI Team - 5.0.0-0.1.alpha1 +- Rebase to JSS 5.0.0-alpha1 diff --git a/sources b/sources index 2638641..f69b2ec 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (jss-4.4.4.tar.gz) = 206a2f26239a647b36f19277e2eebb73bfbd3bc436dabe708423498fb509956618a99c6f0532e47c7b7ddda71652612a450f7490b809866339a1d3827f7e2f51 +SHA512 (jss-5.8.0.tar.gz) = 10f5727d78f8b466062396e47c25b7fdac4b70c6862e6857f8aef49b633c43c4485c1d3cd535006ecd090e8dfe787000fb40d8748ed381c4ac4d1d39312e6c3d diff --git a/sources-update.sh b/sources-update.sh new file mode 100755 index 0000000..96129ca --- /dev/null +++ b/sources-update.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +SOURCE=$1 +TARGET=`basename $1` + +cp $SOURCE $TARGET +sha512sum --tag $TARGET > sources