Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*************************************************************************
* *
* CESeCore: CE Security Core *
* *
* This software is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or any later version. *
* *
* See terms of license at gnu.org. *
* *
*************************************************************************/
package org.cesecore.certificates.util.dn;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.cesecore.util.CeSecoreNameStyle;
/**
* DN string utilities.
*
* Optimized to lower object instantiation by performing manipulations "in-place" using StringBuilder and char[].
*
* Not built to handle '+' char separators or take special consideration to Unicode.
* Current implementation will treat unescaped '=' in values as ok (backwards compatible).
*
* @version $Id: DNFieldsUtil.java 25580 2017-03-22 14:30:19Z anatom $
*/
public abstract class DNFieldsUtil {
private static final Logger LOG = Logger.getLogger(DNFieldsUtil.class);
private static final int EMPTY = -1;
private static final String MSG_ERROR_MISSING_EQUAL = "DN field definition is missing the '=': ";
private static final String ATTRIBUTE_SEPARATOR = ",";
private static final String KEY_VALUE_SEPARATOR = "=";
/**
* The method splits an DN string into a map of it's attributes and values.
*
* @param dnString the DN String to split (i.e.: 'C=DE,CN=test,SN=1').
* @return a map containing the attributes and values.
*/
public static final Map dnStringToMap(final String dnString) {
final String[] dnTokens = dnString.split(ATTRIBUTE_SEPARATOR);
final Map result = new HashMap();
if (StringUtils.isNotBlank(dnString)) {
String[] tokens;
for (int i = 0; i 1) {
result.put(tokens[0], tokens[1]);
} else {
result.put(tokens[0], StringUtils.EMPTY);
}
}
}
return result;
}
/**
* The method checks if the subject-DN contains both C and CN attributes
* (in a potential CVCA/CSCA certificate at least the attributes C and CN must be set).
*
* @param map the map of DN attributes and values.
* @return true if the DN map contains non-empty values for both C and CN.
*/
public static final boolean mapContainsCountryAndCN(final Map map) {
boolean result = false;
if (map.size() >= 2) {
result = StringUtils.isNotBlank(map.get(CeSecoreNameStyle.DefaultSymbols.get(CeSecoreNameStyle.C)))
&& StringUtils.isNotBlank(CeSecoreNameStyle.DefaultSymbols.get(CeSecoreNameStyle.CN));
}
return result;
}
/**
* The method checks if the two subject-DN maps are equal except the 'SN' attribute.
* @param map1 the left side subject-DN map.
* @param map2 the right side subject-DN map.
* @return true if both subject-DN are equal except the 'SN' attribute (accepts null or empty Strings as values, but not for 'SN' attribute).
*/
public static final boolean dnEqualsWithOtherSerialNumber(final Map map1, final Map map2) {
if (map1.size() < 2 || map2.size() < 2 || map1.size() != map2.size()) {
return false;
}
String key, value1, value2;
final String snAttributeKey = CeSecoreNameStyle.DefaultSymbols.get(CeSecoreNameStyle.SN);
boolean result = true;
for (Map.Entry entry : map1.entrySet()) {
key = entry.getKey();
value1 = entry.getValue();
value2 = map2.get(key);
if (snAttributeKey.equals( key)) { // check that serial numbers are not blank and not equal.
if (StringUtils.isBlank(value1) || StringUtils.isBlank(value2) || value1 == value2) {
result = false;
}
} else { // All other DN attributes must be equal.
if (!StringUtils.equals(value1, value2)) {
result = false;
}
}
}
return result;
}
/** Invoke removeEmpties and only return the fully clean dn String. */
public static String removeAllEmpties(final String dn) {
if (dn==null) {
return null;
}
final StringBuilder removedAllEmpties = new StringBuilder(dn.length());
DNFieldsUtil.removeEmpties(dn, removedAllEmpties, false);
return removedAllEmpties.toString();
}
/**
* This method will take the supplied string and fill the two provided empty StringBuilders.
*
* removedTrailingEmpties is produced by:
* Removes fields (key=value) where the value is empty if it is the last value with the same key.
* Example: "CN=abc,CN=,CN=def,O=,O=abc,O=" will become "CN=abc,CN=,CN=def,O=,O=abc".
* Example: "CN=abc,DC=,O=,CN=def,O=,O=abc,O=" will become "CN=abc,O=,CN=def,O=,O=abc".
*
* removedAllEmpties is produced by:
* Removes all fields (key=value) where the value is empty.
* Example: "CN=abc,CN=,O=,CN=def,O=,O=abc,O=" will become "CN=abc,CN=def,O=abc".
*
* Since the algorithms are very similar for these two it makes sense to calculate them both at
* the same time for use in EndEntityInformation.
*
* @param sDN the String to clean.
* @param processTrailing true is removedTrailingEmpties should be considered.
* @return removedTrailingEmpties StringBuilder if both types of cleaning give different results or null if they are the same.
*/
public static StringBuilder removeEmpties(final String sDN, final StringBuilder removedAllEmpties, final boolean processTrailing) {
StringBuilder removedTrailingEmpties = null;
// First make a list of where all the key=value pairs start and if they are empty or not
final List startOfPairs = new ArrayList();
final List startOfValues = new ArrayList();
final char[] buf = sDN.toCharArray();
populatePositionLists(startOfPairs, startOfValues, buf);
boolean areStringBuildersEqual = true;
// Go through all the pairs from first to last
for (int i=0; i 0) {
for (int i = sb.length() - 1; i >= 0; i--) {
final char c = sb.charAt(i);
if (c == ' ' || c == ',') {
if (sb.charAt(i - 1) == '\\') {
break;
} else {
sb.deleteCharAt(i);
}
} else {
break;
}
}
}
}
/** Populates the two lists with starting positions in the character buffer where the value=key pair begins and keys begin. */
private static void populatePositionLists(final List startOfPairs, final List startOfValues, final char[] buf) {
if (buf.length>0) {
startOfPairs.add(Integer.valueOf(0));
}
boolean notEscaped = true; // Keep track of what is escapes and not
for (int i=0; i startOfValues.size()) {
// We are missing a '=' in the DN!
LOG.info(MSG_ERROR_MISSING_EQUAL + new String(buf));
}
int j = i+1;
while (j startOfValues.size()) {
int j = i+1;
while (j=buf.length || buf[j] == ',') {
startOfValues.add(Integer.valueOf(EMPTY)); // Use -1 to mark that the value is empty
} else {
startOfValues.add(Integer.valueOf(j));
}
}
} else {
notEscaped = true;
}
break;
default:
notEscaped=true;
}
}
}
/** Compares the two character sequences in the buffer at the positions until a not escaped '=' is found. */
private static boolean hasSameKey(final char[] sb, int pos1, int pos2) {
final int len = sb.length;
boolean notEscaped = true; // Keep track of what is escapes and not
while (len>pos1 && len>pos2 ) {
final char c1 = sb[pos1];
switch (c1) {
case '\\':
notEscaped ^= true;
break;
case '=':
if (notEscaped && c1 == sb[pos2]) {
return true;
} // else.. continue with the default action..
default:
if (c1 != sb[pos2]) {
return false;
}
notEscaped=true;
}
pos1++;
pos2++;
}
return false;
}
}