From 08529172eab18b74515d77393562a988af06987f Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Sun, 09 Oct 2016 21:21:54 +0000
Subject: [PATCH] OPENDJ-2877: add support for parsing X509 certificates

---
 opendj-core/src/main/java/org/forgerock/opendj/ldap/Functions.java       |   27 +++++++++++++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java |   33 ++++++++++++++++
 opendj-core/src/main/resources/com/forgerock/opendj/ldap/core.properties |    2 +
 3 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java
index 8387622..430af1b 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java
@@ -15,6 +15,7 @@
  */
 package org.forgerock.opendj.ldap;
 
+import java.security.cert.X509Certificate;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashSet;
@@ -209,6 +210,28 @@
     }
 
     /**
+     * Returns the first value decoded as a {@code X509Certificate}, or {@code null} if the attribute does not
+     * contain any values.
+     *
+     * @return The first value decoded as a {@code X509Certificate}.
+     */
+    public X509Certificate asCertificate() {
+        return asCertificate(null);
+    }
+
+    /**
+     * Returns the first value decoded as a {@code X509Certificate}, or {@code defaultValue} if the attribute
+     * does not contain any values.
+     *
+     * @param defaultValue
+     *            The default value to return if the attribute is empty.
+     * @return The first value decoded as a {@code X509Certificate}.
+     */
+    public X509Certificate asCertificate(final X509Certificate defaultValue) {
+        return as(byteStringToCertificate(), defaultValue);
+    }
+
+    /**
      * Returns the first value decoded as a {@code DN} using the schema
      * associated with this parser, or {@code null} if the attribute does not
      * contain any values.
@@ -470,6 +493,16 @@
     }
 
     /**
+     * Returns the values decoded as a set of {@code X509Certificate}s, or an empty set if the attribute does not
+     * contain any values.
+     *
+     * @return The values decoded as a set of {@code X509Certificate}s.
+     */
+    public Set<X509Certificate> asSetOfCertificate() {
+        return asSetOf(byteStringToCertificate());
+    }
+
+    /**
      * Returns the values decoded as a set of {@code DN}s using the schema
      * associated with this parser, or an empty set if the attribute does not
      * contain any values.
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/Functions.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/Functions.java
index 79141a0..4c25321 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/Functions.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/Functions.java
@@ -28,6 +28,10 @@
 
 import static com.forgerock.opendj.ldap.CoreMessages.*;
 
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
 /**
  * Common {@link Function} implementations which may be used when parsing
  * attributes.
@@ -125,6 +129,19 @@
     private static final Function<ByteString, Boolean, LocalizedIllegalArgumentException> BYTESTRING_TO_BOOLEAN =
             compose(byteStringToString(), STRING_TO_BOOLEAN);
 
+    private static final Function<ByteString, X509Certificate, LocalizedIllegalArgumentException> BYTESTRING_TO_CERT =
+            new Function<ByteString, X509Certificate, LocalizedIllegalArgumentException>() {
+                @Override
+                public X509Certificate apply(final ByteString value) {
+                    try {
+                        final CertificateFactory factory = CertificateFactory.getInstance("X.509");
+                        return (X509Certificate) factory.generateCertificate(value.asReader().asInputStream());
+                    } catch (CertificateException e) {
+                        final String head = value.subSequence(0, Math.min(value.length(), 8)).toHexString();
+                        throw new LocalizedIllegalArgumentException(FUNCTIONS_TO_CERT_FAIL.get(head), e);
+                    }
+                }
+            };
 
     private static final Function<ByteString, GeneralizedTime, LocalizedIllegalArgumentException> BYTESTRING_TO_GTIME =
             compose(byteStringToString(), STRING_TO_GTIME);
@@ -385,6 +402,16 @@
     }
 
     /**
+     * Returns a function which parses {@code X509Certificate} values. Invalid values will
+     * result in a {@code LocalizedIllegalArgumentException}.
+     *
+     * @return A function which parses {@code X509Certificate} values.
+     */
+    public static Function<ByteString, X509Certificate, LocalizedIllegalArgumentException> byteStringToCertificate() {
+        return BYTESTRING_TO_CERT;
+    }
+
+    /**
      * Returns a function which parses generalized time strings. Invalid values
      * will result in a {@code LocalizedIllegalArgumentException}.
      *
diff --git a/opendj-core/src/main/resources/com/forgerock/opendj/ldap/core.properties b/opendj-core/src/main/resources/com/forgerock/opendj/ldap/core.properties
index fded58f..e671ee7 100644
--- a/opendj-core/src/main/resources/com/forgerock/opendj/ldap/core.properties
+++ b/opendj-core/src/main/resources/com/forgerock/opendj/ldap/core.properties
@@ -1436,6 +1436,8 @@
  integer
 FUNCTIONS_TO_LONG_FAIL=The provided value "%s" could not be parsed as an \
  long
+FUNCTIONS_TO_CERT_FAIL=The provided value starting with the bytes "%s" could \
+  not be parsed as an X509 certificate
 ERR_LDIF_MALFORMED_CONTROL=Unable to parse LDIF change record starting at line %d \
  with distinguished name "%s" because it contained a malformed control \
  "%s"

--
Gitblit v1.10.0