001: package org.bouncycastle.asn1.x509;
002:
003: import org.bouncycastle.asn1.ASN1InputStream;
004: import org.bouncycastle.asn1.DERObject;
005: import org.bouncycastle.asn1.DERObjectIdentifier;
006: import org.bouncycastle.asn1.DERPrintableString;
007: import org.bouncycastle.util.Strings;
008:
009: import java.io.IOException;
010:
011: /**
012: * It turns out that the number of standard ways the fields in a DN should be
013: * encoded into their ASN.1 counterparts is rapidly approaching the
014: * number of machines on the internet. By default the X509Name class
015: * will produce UTF8Strings in line with the current recommendations (RFC 3280).
016: * <p>
017: * An example of an encoder look like below:
018: * <pre>
019: * public class X509DirEntryConverter
020: * extends X509NameEntryConverter
021: * {
022: * public DERObject getConvertedValue(
023: * DERObjectIdentifier oid,
024: * String value)
025: * {
026: * if (str.length() != 0 && str.charAt(0) == '#')
027: * {
028: * return convertHexEncoded(str, 1);
029: * }
030: * if (oid.equals(EmailAddress))
031: * {
032: * return new DERIA5String(str);
033: * }
034: * else if (canBePrintable(str))
035: * {
036: * return new DERPrintableString(str);
037: * }
038: * else if (canBeUTF8(str))
039: * {
040: * return new DERUTF8String(str);
041: * }
042: * else
043: * {
044: * return new DERBMPString(str);
045: * }
046: * }
047: * }
048: */
049: public abstract class X509NameEntryConverter {
050: /**
051: * Convert an inline encoded hex string rendition of an ASN.1
052: * object back into its corresponding ASN.1 object.
053: *
054: * @param str the hex encoded object
055: * @param off the index at which the encoding starts
056: * @return the decoded object
057: */
058: protected DERObject convertHexEncoded(String str, int off)
059: throws IOException {
060: str = Strings.toLowerCase(str);
061: byte[] data = new byte[(str.length() - off) / 2];
062: for (int index = 0; index != data.length; index++) {
063: char left = str.charAt((index * 2) + off);
064: char right = str.charAt((index * 2) + off + 1);
065:
066: if (left < 'a') {
067: data[index] = (byte) ((left - '0') << 4);
068: } else {
069: data[index] = (byte) ((left - 'a' + 10) << 4);
070: }
071: if (right < 'a') {
072: data[index] |= (byte) (right - '0');
073: } else {
074: data[index] |= (byte) (right - 'a' + 10);
075: }
076: }
077:
078: ASN1InputStream aIn = new ASN1InputStream(data);
079:
080: return aIn.readObject();
081: }
082:
083: /**
084: * return true if the passed in String can be represented without
085: * loss as a PrintableString, false otherwise.
086: */
087: protected boolean canBePrintable(String str) {
088: return DERPrintableString.isPrintableString(str);
089: }
090:
091: /**
092: * Convert the passed in String value into the appropriate ASN.1
093: * encoded object.
094: *
095: * @param oid the oid associated with the value in the DN.
096: * @param value the value of the particular DN component.
097: * @return the ASN.1 equivalent for the value.
098: */
099: public abstract DERObject getConvertedValue(
100: DERObjectIdentifier oid, String value);
101: }
|