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.certificate.certextensions;
import java.io.IOException;
import java.math.BigInteger;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.util.encoders.Hex;
import org.cesecore.certificates.ca.CA;
import org.cesecore.certificates.ca.internal.CertificateValidity;
import org.cesecore.certificates.certificateprofile.CertificateProfile;
import org.cesecore.certificates.endentity.EndEntityInformation;
import org.cesecore.certificates.endentity.ExtendedInformation;
import org.cesecore.internal.InternalResources;
/**
* The default basic certificate extension that has two property.
*
* 'value' : The value returned 'encoding' : How the value is encoded.
*
* Optionally, a new property can be defined:
*
* 'nvalues' : number of values of type 'encoding'
*
* Thus, the extension will be of type 'SEQUENCE OF ENCODING' with a size of nvalues. The members will be: 'value1', 'value2' and so on.
*
* Optionally, an other property can be defined:
*
* 'dynamic' : true/false if the extension value(s) should be allowed to be
* overridden by value(s) put as extensiondata in
* ExtendedInformation. Default is 'false'.
*
*
* See documentation for more information.
*
* @version $Id: BasicCertificateExtension.java 30582 2018-11-22 17:30:08Z samuellb $
*/
public class BasicCertificateExtension extends CertificateExtension implements CustomCertificateExtension {
private static final long serialVersionUID = 6896964791897238060L;
//private static final Logger log = Logger.getLogger(BasicCertificateExtension.class);
private static final InternalResources intres = InternalResources.getInstance();
private static final String DISPLAY_NAME = "Basic Certificate Extension";
private enum Encoding {
ENCODING_DERBITSTRING("DERBITSTRING"),
ENCODING_DERINTEGER("DERINTEGER"),
ENCODING_DEROCTETSTRING("DEROCTETSTRING"),
ENCODING_DERBOOLEAN("DERBOOLEAN"),
ENCODING_DERPRINTABLESTRING("DERPRINTABLESTRING"),
ENCODING_DERUTF8STRING("DERUTF8STRING"),
ENCODING_DERIA5STRING("DERIA5STRING"),
ENCODING_DERNULL("DERNULL"),
ENCODING_DEROBJECT("DEROBJECT"),
ENCODING_DEROID("DERBOJECTIDENTIFIER");
private static final Map lookupMap = new HashMap();
static {
for(Encoding encoding : Encoding.values()) {
lookupMap.put(encoding.value(), encoding);
}
}
private final String value;
private Encoding(String value) {
this.value = value;
}
public String value() {
return value;
}
public boolean equals(Encoding otherValue) {
if(otherValue == null) {
return false;
}
return value.equalsIgnoreCase(otherValue.value());
}
public static final Encoding fromString(String value) {
return lookupMap.get(StringUtils.upperCase(value, Locale.ROOT));
}
}
/**
* The value is expected to by hex encoded and is added as an byte array
* as the extension value.
**/
private static String ENCODING_RAW = "RAW";
private static String ENCODING_DERNULL = "DERNULL";
// Defined Properties
private static String PROPERTY_VALUE = "value";
private static String PROPERTY_ENCODING = "encoding";
private static String PROPERTY_NVALUES = "nvalues";
private static String PROPERTY_DYNAMIC = "dynamic";
private static final Map propertiesMap = new HashMap();
static {
Encoding[] encodings = Encoding.values();
// +1 because we need to add RAW as well in the end
String[] encodingValues = new String[encodings.length+1];
for(int i = 0; i < encodings.length; i++) {
encodingValues[i] = encodings[i].value;
}
// Add RAW last
encodingValues[encodingValues.length-1] = ENCODING_RAW;
propertiesMap.put(PROPERTY_ENCODING, encodingValues);
propertiesMap.put(PROPERTY_VALUE, new String[]{});
propertiesMap.put(PROPERTY_DYNAMIC, CustomCertificateExtension.BOOLEAN);
}
{
setDisplayName(DISPLAY_NAME);
}
/**
* @deprecated use getValueEncoded instead.
*/
@Deprecated
@Override
public ASN1Encodable getValue(EndEntityInformation userData, CA ca, CertificateProfile certProfile, PublicKey userPublicKey, PublicKey caPublicKey, CertificateValidity val)
throws CertificateExtensionException {
throw new UnsupportedOperationException("Use getValueEncoded instead");
}
/**
* Returns the defined property 'value' in the encoding specified in 'encoding'.
*
* This certificate extension implementations overrides this method as it
* want to be able to return a byte[] with the extension value. Otherwise
* the implementation could have been put in the getValue method as the
* super class CertificateExtension has a default implementation for
* getValueEncoded which calls getValue.
*
* @param userData
* Used to lookup extension data
* @param ca
* not used
* @param certProfile
* not used
* @see org.cesecore.certificates.certificate.certextensions.CertificateExtension#getValueEncoded(EndEntityInformation, CA, CertificateProfile, PublicKey,
* PublicKey, CertificateValidity)
*/
@Override
public byte[] getValueEncoded(EndEntityInformation userData, CA ca, CertificateProfile certProfile, PublicKey userPublicKey,
PublicKey caPublicKey, CertificateValidity val) throws CertificateExtensionException {
String[] values = getValues(userData, null);
return handleValues(values);
}
@Override
public byte[] getValueEncoded(EndEntityInformation userData, CA ca, CertificateProfile certProfile, PublicKey userPublicKey,
PublicKey caPublicKey, CertificateValidity val, String oid) throws CertificateExtensionException {
String[] values = getValues(userData, oid);
return handleValues(values);
}
private byte[] handleValues(String[] values) throws CertificateExtensionException {
final byte[] result;
String encoding = StringUtils.trim(getProperties().getProperty(PROPERTY_ENCODING));
if (values == null || values.length == 0 || (values[0] == null && !encoding.equalsIgnoreCase(ENCODING_DERNULL))) {
if (!isRequiredFlag()) {
return null;
}
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.incorrectvalue", Integer.valueOf(getId()), getOID()));
}
if (encoding.equalsIgnoreCase(ENCODING_RAW)) {
if (values.length > 1) {
// nvalues can not be used together with encoding=RAW
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.certextmissconfigured", Integer.valueOf(getId())));
} else {
result = parseRaw(values[0]);
}
} else {
try {
if (values.length > 1) {
ASN1EncodableVector ev = new ASN1EncodableVector();
for (String value : values) {
ASN1Encodable derval = parseValue(encoding, value);
ev.add(derval);
}
result = new DERSequence(ev).getEncoded();
} else {
result = parseValue(encoding, values[0]).toASN1Primitive().getEncoded();
}
} catch (IOException ioe) {
throw new CertificateExtensionException(ioe.getMessage(), ioe);
}
}
return result;
}
/**
* Get the extension value by first looking in the ExtendedInformation (if
* dynamic is enabled) and then in the static configuration.
*
* @param userData The userdata to get the ExtendedInformation from
* @return The value(s) for the extension (usually 1) or null if no value found
*/
private String[] getValues(EndEntityInformation userData, final String oid) {
String[] result = null;
boolean dynamic = Boolean.parseBoolean(StringUtils.trim(getProperties().getProperty(PROPERTY_DYNAMIC, Boolean.FALSE.toString())));
String strnvalues = getProperties().getProperty(PROPERTY_NVALUES);
int nvalues;
if ( strnvalues == null || strnvalues.trim().equals("") ) {
nvalues = 0;
} else {
nvalues = Integer.parseInt(strnvalues);
}
if (dynamic) {
final ExtendedInformation ei = userData.getExtendedInformation();
if (ei == null) {
result = null;
} else {
if (nvalues < 1 ) {
String value = null;
if (oid != null) {
value = userData.getExtendedInformation().getExtensionData(oid);
if (value == null || value.trim().isEmpty()) {
value = userData.getExtendedInformation().getExtensionData(oid + "." + PROPERTY_VALUE);
}
} else {
value = userData.getExtendedInformation().getExtensionData(getOID());
if (value == null || value.trim().isEmpty()) {
value = userData.getExtendedInformation().getExtensionData(getOID() + "." + PROPERTY_VALUE);
}
}
if (value == null) {
result = null;
} else {
result = new String[] { value };
}
} else {
for (int i = 1; i <= nvalues; i++) {
String value = null;
if (oid != null) {
value = userData.getExtendedInformation().getExtensionData(oid + "." + PROPERTY_VALUE + Integer.toString(i));
} else {
value = userData.getExtendedInformation().getExtensionData(getOID() + "." + PROPERTY_VALUE + Integer.toString(i));
}
if (value != null) {
if (result == null) {
result = new String[nvalues];
}
result[i - 1] = value;
}
}
}
}
}
if (result == null) {
if (nvalues < 1 ) {
String value = getProperties().getProperty(PROPERTY_VALUE);
if ( value == null || value.trim().equals("") ) {
value = getProperties().getProperty(PROPERTY_VALUE+"1");
}
result = new String[] { value };
} else {
result = new String[nvalues];
for (int i=1; i<=nvalues; i++) {
result[i - 1] = getProperties().getProperty(PROPERTY_VALUE+Integer.toString(i));
}
}
}
return result;
}
private ASN1Encodable parseValue(String encoding, String value) throws CertificateExtensionException {
ASN1Encodable toret = null;
Encoding encodingType = Encoding.fromString(encoding);
if(encodingType == null) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.incorrectenc", encoding,
Integer.valueOf(getId())));
}
if (!Encoding.ENCODING_DERNULL.equals(encodingType) && ((value == null || value.trim().equals("")) && isRequiredFlag())) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.incorrectvalue", Integer.valueOf(getId()), getOID()));
}
switch(encodingType) {
case ENCODING_DERBITSTRING:
toret = parseDERBitString(value);
break;
case ENCODING_DERINTEGER:
toret = parseDERInteger(value);
break;
case ENCODING_DEROCTETSTRING:
toret = parseDEROctetString(value);
break;
case ENCODING_DERBOOLEAN:
toret = parseDERBoolean(value);
break;
case ENCODING_DEROID:
toret = parseDEROID(value);
break;
case ENCODING_DERPRINTABLESTRING:
toret = parseDERPrintableString(value);
break;
case ENCODING_DERUTF8STRING:
toret = parseDERUTF8String(value);
break;
case ENCODING_DERIA5STRING:
toret = parseDERIA5String(value);
break;
case ENCODING_DERNULL:
toret = DERNull.INSTANCE;
break;
case ENCODING_DEROBJECT:
toret = parseHexEncodedDERObject(value);
break;
default:
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.incorrectenc", encoding,
Integer.valueOf(getId())));
}
return toret;
}
private ASN1Encodable parseDERBitString(String value) throws CertificateExtensionException {
ASN1Encodable retval = null;
try {
BigInteger bigInteger = new BigInteger(value, 2);
int padBits = value.length() - 1 - value.lastIndexOf("1");
if (padBits == 8) {
padBits = 0;
}
byte[] byteArray = bigInteger.toByteArray();
if (byteArray[0] == 0) {
// Remove empty extra byte
// System.arraycopy handles creating of temporary array when destinatio is the same
System.arraycopy(byteArray, 1, byteArray, 0, byteArray.length-1);
}
retval = new DERBitString(byteArray, padBits);
} catch (NumberFormatException e) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.illegalvalue", value,
Integer.valueOf(getId()), getOID()));
}
return retval;
}
private ASN1Encodable parseDEROID(String value) throws CertificateExtensionException {
ASN1Encodable retval = null;
try {
retval = new ASN1ObjectIdentifier(value);
} catch (Exception e) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.illegalvalue", value,
Integer.valueOf(getId()), getOID()));
}
return retval;
}
private ASN1Encodable parseDERInteger(String value) throws CertificateExtensionException {
ASN1Encodable retval = null;
try {
BigInteger intValue = new BigInteger(value, 10);
retval = new ASN1Integer(intValue);
} catch (NumberFormatException e) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.illegalvalue", value,
Integer.valueOf(getId()), getOID()));
}
return retval;
}
private ASN1Encodable parseDEROctetString(String value) throws CertificateExtensionException {
ASN1Encodable retval = null;
if (value.matches("^\\p{XDigit}*")) {
byte[] bytes = Hex.decode(value);
retval = new DEROctetString(bytes);
} else {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.illegalvalue", value,
Integer.valueOf(getId()), getOID()));
}
return retval;
}
/**
* Tries to read the hex-string as an DERObject. If it contains more than one ASN1Encodable object, return a DERSequence of the objects.
*/
private ASN1Encodable parseHexEncodedDERObject(String value) throws CertificateExtensionException {
ASN1Encodable retval = null;
if (value.matches("^\\p{XDigit}*")) {
byte[] bytes = Hex.decode(value);
try {
ASN1InputStream ais = new ASN1InputStream(bytes);
ASN1Encodable firstObject = ais.readObject();
if (ais.available() > 0) {
ASN1EncodableVector ev = new ASN1EncodableVector();
ev.add(firstObject);
while (ais.available() > 0) {
ev.add(ais.readObject());
}
retval = new DERSequence(ev);
} else {
retval = firstObject;
}
ais.close();
} catch (Exception e) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.illegalvalue", value,
Integer.valueOf(getId()), getOID()));
}
} else {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.illegalvalue", value,
Integer.valueOf(getId()), getOID()));
}
return retval;
}
private ASN1Encodable parseDERBoolean(String value) throws CertificateExtensionException {
ASN1Encodable retval = null;
if (value.equalsIgnoreCase("TRUE")) {
retval = ASN1Boolean.TRUE;
}
if (value.equalsIgnoreCase("FALSE")) {
retval = ASN1Boolean.FALSE;
}
if (retval == null) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.illegalvalue", value,
Integer.valueOf(getId()), getOID()));
}
return retval;
}
private ASN1Encodable parseDERPrintableString(String value) throws CertificateExtensionException {
try {
return new DERPrintableString(value, true);
} catch (IllegalArgumentException e) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.illegalvalue", value,
Integer.valueOf(getId()), getOID()));
}
}
private ASN1Encodable parseDERUTF8String(String value) {
return new DERUTF8String(value);
}
private ASN1Encodable parseDERIA5String(String value) throws CertificateExtensionException {
try {
return new DERIA5String(value, true);
} catch (java.lang.IllegalArgumentException e) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.illegalvalue", value,
Integer.valueOf(getId()), getOID()));
}
}
private byte[] parseRaw(String value) throws CertificateExtensionException {
if(value == null) {
throw new CertificateExtensionException(intres.getLocalizedMessage("certext.basic.incorrectvalue", Integer.valueOf(getId()), getOID()));
}
return Hex.decode(value);
}
@Override
public Map getAvailableProperties() {
return propertiesMap;
}
}