/* * * Copyright (c) 2013 - 2017 Lijun Liao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT * OF THIRD PARTY RIGHTS. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the XiPKI software without * disclosing the source code of your own applications. * * For more information, please contact Lijun Liao at this * address: lijun.liao@gmail.com */ package org.xipki.commons.security.util; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.security.NoSuchProviderException; import java.security.cert.CRLException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1String; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.DERUniversalString; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x500.AttributeTypeAndValue; import org.bouncycastle.asn1.x500.DirectoryString; import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.style.IETFUtils; import org.bouncycastle.asn1.x500.style.RFC4519Style; import org.bouncycastle.asn1.x509.AccessDescription; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x509.CertificateList; import org.bouncycastle.asn1.x509.DSAParameter; import org.bouncycastle.asn1.x509.ExtendedKeyUsage; import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.KeyPurposeId; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.cert.X509AttributeCertificateHolder; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xipki.commons.common.ConfPairs; import org.xipki.commons.common.util.CollectionUtil; import org.xipki.commons.common.util.IoUtil; import org.xipki.commons.common.util.ParamUtil; import org.xipki.commons.security.FpIdCalculator; import org.xipki.commons.security.KeyUsage; import org.xipki.commons.security.ObjectIdentifiers; import org.xipki.commons.security.exception.BadInputException; /** * @author Lijun Liao * @since 2.0.0 */ public class X509Util { private static final Logger LOG = LoggerFactory.getLogger(X509Util.class); private static CertificateFactory certFact; private static Object certFactLock = new Object(); private X509Util() { } public static String getCommonName(final X500Principal name) { ParamUtil.requireNonNull("name", name); return getCommonName(X500Name.getInstance(name.getEncoded())); } public static String getCommonName(final X500Name name) { ParamUtil.requireNonNull("name", name); RDN[] rdns = name.getRDNs(ObjectIdentifiers.DN_CN); if (rdns != null && rdns.length > 0) { RDN rdn = rdns[0]; AttributeTypeAndValue atv = null; if (rdn.isMultiValued()) { for (AttributeTypeAndValue m : rdn.getTypesAndValues()) { if (m.getType().equals(ObjectIdentifiers.DN_CN)) { atv = m; break; } } } else { atv = rdn.getFirst(); } return (atv == null) ? null : rdnValueToString(atv.getValue()); } return null; } public static X500Name reverse(final X500Name name) { ParamUtil.requireNonNull("name", name); RDN[] orig = name.getRDNs(); final int n = orig.length; RDN[] newRdn = new RDN[n]; for (int i = 0; i < n; i++) { newRdn[i] = orig[n - 1 - i]; } return new X500Name(newRdn); } public static X509Certificate parseCert(final String fileName) throws IOException, CertificateException { ParamUtil.requireNonNull("fileName", fileName); return parseCert(new File(IoUtil.expandFilepath(fileName))); } public static X509Certificate parseCert(final File file) throws IOException, CertificateException { ParamUtil.requireNonNull("file", file); FileInputStream in = new FileInputStream(IoUtil.expandFilepath(file)); try { return parseCert(in); } finally { in.close(); } } public static X509Certificate parseCert(final byte[] certBytes) throws CertificateException { ParamUtil.requireNonNull("certBytes", certBytes); return parseCert(new ByteArrayInputStream(certBytes)); } public static X509Certificate parseCert(final InputStream certStream) throws CertificateException { ParamUtil.requireNonNull("certStream", certStream); X509Certificate cert = (X509Certificate) getCertFactory().generateCertificate(certStream); if (cert == null) { throw new CertificateEncodingException( "the given one is not a valid X.509 certificate"); } return cert; } private static CertificateFactory getCertFactory() throws CertificateException { synchronized (certFactLock) { if (certFact == null) { try { certFact = CertificateFactory.getInstance("X.509", "BC"); } catch (NoSuchProviderException ex) { throw new CertificateException("NoSuchProviderException: " + ex.getMessage()); } } return certFact; } } public static X509Certificate parseBase64EncodedCert(final String base64EncodedCert) throws CertificateException { ParamUtil.requireNonNull("base64EncodedCert", base64EncodedCert); return parseCert(Base64.decode(base64EncodedCert)); } public static X509Certificate parsePemEncodedCert(final String pemEncodedCert) throws CertificateException { ParamUtil.requireNonNull("pemEncodedCert", pemEncodedCert); String b64 = pemEncodedCert.replace("-----BEGIN CERTIFICATE-----", "") .replace("-----END CERTIFICATE-----", ""); return parseBase64EncodedCert(b64); } public static X509Certificate toX509Cert( final org.bouncycastle.asn1.x509.Certificate asn1Cert) throws CertificateException { byte[] encodedCert; try { encodedCert = asn1Cert.getEncoded(); } catch (IOException ex) { throw new CertificateEncodingException("could not get encoded certificate", ex); } return parseCert(encodedCert); } public static X509CRL toX509Crl(final CertificateList asn1CertList) throws CertificateException, CRLException { byte[] encodedCrl; try { encodedCrl = asn1CertList.getEncoded(); } catch (IOException ex) { throw new CRLException("could not get encoded CRL", ex); } return parseCrl(encodedCrl); } public static X509CRL parseCrl(final String file) throws IOException, CertificateException, CRLException { ParamUtil.requireNonBlank("file", file); return parseCrl(new FileInputStream(IoUtil.expandFilepath(file))); } public static X509CRL parseCrl(final byte[] encodedCrl) throws CertificateException, CRLException { ParamUtil.requireNonNull("encodedCrl", encodedCrl); return parseCrl(new ByteArrayInputStream(encodedCrl)); } public static X509CRL parseCrl(final InputStream crlStream) throws CertificateException, CRLException { ParamUtil.requireNonNull("crlStream", crlStream); X509CRL crl = (X509CRL) getCertFactory().generateCRL(crlStream); if (crl == null) { throw new CRLException( "the given one is not a valid X.509 CRL"); } return crl; } public static String getRfc4519Name(final X500Principal name) { ParamUtil.requireNonNull("name", name); return getRfc4519Name(X500Name.getInstance(name.getEncoded())); } public static String getRfc4519Name(final X500Name name) { ParamUtil.requireNonNull("name", name); return RFC4519Style.INSTANCE.toString(name); } /** * First canonicalized the name, and then compute the SHA-1 finger-print over the * canonicalized subject string. */ public static long fpCanonicalizedName(final X500Principal prin) { ParamUtil.requireNonNull("prin", prin); X500Name x500Name = X500Name.getInstance(prin.getEncoded()); return fpCanonicalizedName(x500Name); } public static long fpCanonicalizedName(final X500Name name) { ParamUtil.requireNonNull("name", name); String canonicalizedName = canonicalizName(name); byte[] encoded; try { encoded = canonicalizedName.getBytes("UTF-8"); } catch (UnsupportedEncodingException ex) { encoded = canonicalizedName.getBytes(); } return FpIdCalculator.hash(encoded); } public static String canonicalizName(final X500Name name) { ParamUtil.requireNonNull("name", name); ASN1ObjectIdentifier[] tmpTypes = name.getAttributeTypes(); int len = tmpTypes.length; List<String> types = new ArrayList<>(len); for (ASN1ObjectIdentifier type : tmpTypes) { types.add(type.getId()); } Collections.sort(types); StringBuilder sb = new StringBuilder(); for (int i = 0; i < len; i++) { String type = types.get(i); if (i > 0) { sb.append(","); } sb.append(type).append("="); RDN[] rdns = name.getRDNs(new ASN1ObjectIdentifier(type)); List<String> values = new ArrayList<>(1); for (int j = 0; j < rdns.length; j++) { RDN rdn = rdns[j]; if (rdn.isMultiValued()) { AttributeTypeAndValue[] atvs = rdn.getTypesAndValues(); for (AttributeTypeAndValue atv : atvs) { if (type.equals(atv.getType().getId())) { String textValue = IETFUtils.valueToString(atv.getValue()).toLowerCase(); values.add(textValue); } } } else { String textValue = IETFUtils.valueToString(rdn.getFirst().getValue()).toLowerCase(); values.add(textValue); } } // end for(j) sb.append(values.get(0)); final int n2 = values.size(); if (n2 > 1) { for (int j = 1; j < n2; j++) { sb.append(";").append(values.get(j)); } } } // end for(i) return sb.toString(); } // method canonicalizName public static byte[] extractSki(final X509Certificate cert) throws CertificateEncodingException { byte[] extValue = getCoreExtValue(cert, Extension.subjectKeyIdentifier); if (extValue == null) { return null; } try { return ASN1OctetString.getInstance(extValue).getOctets(); } catch (IllegalArgumentException ex) { throw new CertificateEncodingException(ex.getMessage()); } } public static byte[] extractSki(final org.bouncycastle.asn1.x509.Certificate cert) throws CertificateEncodingException { ParamUtil.requireNonNull("cert", cert); Extension encodedSkiValue = cert.getTBSCertificate().getExtensions().getExtension( Extension.subjectKeyIdentifier); if (encodedSkiValue == null) { return null; } try { return ASN1OctetString.getInstance(encodedSkiValue.getParsedValue()).getOctets(); } catch (IllegalArgumentException ex) { throw new CertificateEncodingException("invalid extension SubjectKeyIdentifier: " + ex.getMessage()); } } public static byte[] extractAki(final X509Certificate cert) throws CertificateEncodingException { byte[] extValue = getCoreExtValue(cert, Extension.authorityKeyIdentifier); if (extValue == null) { return null; } try { AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance(extValue); return aki.getKeyIdentifier(); } catch (IllegalArgumentException ex) { throw new CertificateEncodingException("invalid extension AuthorityKeyIdentifier: " + ex.getMessage()); } } public static byte[] extractAki(final org.bouncycastle.asn1.x509.Certificate cert) throws CertificateEncodingException { ParamUtil.requireNonNull("cert", cert); try { AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.fromExtensions( cert.getTBSCertificate().getExtensions()); return (aki == null) ? null : aki.getKeyIdentifier(); } catch (IllegalArgumentException ex) { throw new CertificateEncodingException("invalid extension AuthorityKeyIdentifier: " + ex.getMessage()); } } public static String rdnValueToString(final ASN1Encodable value) { ParamUtil.requireNonNull("value", value); if (value instanceof ASN1String && !(value instanceof DERUniversalString)) { return ((ASN1String) value).getString(); } else { try { return "#" + bytesToString( Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))); } catch (IOException ex) { throw new IllegalArgumentException("other value has no encoded form"); } } } private static String bytesToString(final byte[] data) { char[] cs = new char[data.length]; for (int i = 0; i != cs.length; i++) { cs[i] = (char) (data[i] & 0xff); } return new String(cs); } public static org.bouncycastle.asn1.x509.KeyUsage createKeyUsage(final Set<KeyUsage> usages) { if (CollectionUtil.isEmpty(usages)) { return null; } int usage = 0; for (KeyUsage keyUsage : usages) { usage |= keyUsage.getBcUsage(); } return new org.bouncycastle.asn1.x509.KeyUsage(usage); } public static ExtendedKeyUsage createExtendedUsage( final Collection<ASN1ObjectIdentifier> usages) { if (CollectionUtil.isEmpty(usages)) { return null; } List<ASN1ObjectIdentifier> list = new ArrayList<>(usages); List<ASN1ObjectIdentifier> sortedUsages = sortOidList(list); KeyPurposeId[] kps = new KeyPurposeId[sortedUsages.size()]; int idx = 0; for (ASN1ObjectIdentifier oid : sortedUsages) { kps[idx++] = KeyPurposeId.getInstance(oid); } return new ExtendedKeyUsage(kps); } // sort the list and remove duplicated OID. public static List<ASN1ObjectIdentifier> sortOidList(final List<ASN1ObjectIdentifier> oids) { ParamUtil.requireNonNull("oids", oids); List<String> list = new ArrayList<>(oids.size()); for (ASN1ObjectIdentifier m : oids) { list.add(m.getId()); } Collections.sort(list); List<ASN1ObjectIdentifier> sorted = new ArrayList<>(oids.size()); for (String m : list) { for (ASN1ObjectIdentifier n : oids) { if (m.equals(n.getId()) && !sorted.contains(n)) { sorted.add(n); } } } return sorted; } public static boolean hasKeyusage(final X509Certificate cert, final KeyUsage usage) { ParamUtil.requireNonNull("cert", cert); boolean[] keyusage = cert.getKeyUsage(); if (keyusage != null && keyusage.length > usage.getBit()) { return keyusage[usage.getBit()]; } return false; } public static byte[] getCoreExtValue(final X509Certificate cert, final ASN1ObjectIdentifier type) throws CertificateEncodingException { ParamUtil.requireNonNull("cert", cert); ParamUtil.requireNonNull("type", type); byte[] fullExtValue = cert.getExtensionValue(type.getId()); if (fullExtValue == null) { return null; } try { return ASN1OctetString.getInstance(fullExtValue).getOctets(); } catch (IllegalArgumentException ex) { throw new CertificateEncodingException("invalid extension " + type.getId() + ": " + ex.getMessage()); } } public static byte[] getCoreExtValue(final X509AttributeCertificateHolder cert, final ASN1ObjectIdentifier type) throws CertificateEncodingException { ParamUtil.requireNonNull("cert", cert); ParamUtil.requireNonNull("type", type); Extension ext = cert.getExtension(type); if (ext == null) { return null; } return ext.getExtnValue().getOctets(); } /** * Cross certificate will not be considered. */ public static X509Certificate[] buildCertPath(final X509Certificate cert, final Set<? extends Certificate> certs) { ParamUtil.requireNonNull("cert", cert); List<X509Certificate> certChain = new LinkedList<>(); certChain.add(cert); try { if (certs != null && !isSelfSigned(cert)) { while (true) { X509Certificate caCert = getCaCertOf(certChain.get(certChain.size() - 1), certs); if (caCert == null) { break; } certChain.add(caCert); if (isSelfSigned(caCert)) { // reaches root self-signed certificate break; } } } } catch (CertificateEncodingException ex) { LOG.warn("CertificateEncodingException: {}", ex.getMessage()); } final int n = certChain.size(); int len = n; if (n > 1) { for (int i = 1; i < n; i++) { int pathLen = certChain.get(i).getBasicConstraints(); if (pathLen < 0 || pathLen < i) { len = i; break; } } } // end for if (len == n) { return certChain.toArray(new X509Certificate[0]); } else { X509Certificate[] ret = new X509Certificate[len]; for (int i = 0; i < len; i++) { ret[i] = certChain.get(i); } return ret; } } // method buildCertPath private static X509Certificate getCaCertOf(final X509Certificate cert, final Set<? extends Certificate> caCerts) throws CertificateEncodingException { ParamUtil.requireNonNull("cert", cert); if (isSelfSigned(cert)) { return null; } for (Certificate caCert : caCerts) { if (!(caCert instanceof X509Certificate)) { continue; } X509Certificate x509CaCert = (X509Certificate) caCert; if (!issues(x509CaCert, cert)) { continue; } try { cert.verify(x509CaCert.getPublicKey()); return x509CaCert; } catch (Exception ex) { LOG.warn("could not verify certificate: {}", ex.getMessage()); } } return null; } public static boolean isSelfSigned(final X509Certificate cert) throws CertificateEncodingException { ParamUtil.requireNonNull("cert", cert); boolean equals = cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal()); if (equals) { byte[] ski = extractSki(cert); byte[] aki = extractAki(cert); if (ski != null && aki != null) { equals = Arrays.equals(ski, aki); } } return equals; } public static boolean issues(final X509Certificate issuerCert, final X509Certificate cert) throws CertificateEncodingException { ParamUtil.requireNonNull("issuerCert", issuerCert); ParamUtil.requireNonNull("cert", cert); boolean isCa = issuerCert.getBasicConstraints() >= 0; if (!isCa) { return false; } boolean issues = issuerCert.getSubjectX500Principal().equals( cert.getIssuerX500Principal()); if (issues) { byte[] ski = extractSki(issuerCert); byte[] aki = extractAki(cert); if (ski != null) { issues = Arrays.equals(ski, aki); } } if (issues) { long issuerNotBefore = issuerCert.getNotBefore().getTime(); long issuerNotAfter = issuerCert.getNotAfter().getTime(); long notBefore = cert.getNotBefore().getTime(); issues = notBefore <= issuerNotAfter && notBefore >= issuerNotBefore; } return issues; } public static SubjectPublicKeyInfo toRfc3279Style(final SubjectPublicKeyInfo publicKeyInfo) throws InvalidKeySpecException { ParamUtil.requireNonNull("publicKeyInfo", publicKeyInfo); ASN1ObjectIdentifier algOid = publicKeyInfo.getAlgorithm().getAlgorithm(); ASN1Encodable keyParameters = publicKeyInfo.getAlgorithm().getParameters(); if (PKCSObjectIdentifiers.rsaEncryption.equals(algOid)) { if (DERNull.INSTANCE.equals(keyParameters)) { return publicKeyInfo; } else { AlgorithmIdentifier keyAlgId = new AlgorithmIdentifier(algOid, DERNull.INSTANCE); return new SubjectPublicKeyInfo(keyAlgId, publicKeyInfo.getPublicKeyData().getBytes()); } } else if (X9ObjectIdentifiers.id_dsa.equals(algOid)) { if (keyParameters == null) { return publicKeyInfo; } else if (DERNull.INSTANCE.equals(keyParameters)) { AlgorithmIdentifier keyAlgId = new AlgorithmIdentifier(algOid); return new SubjectPublicKeyInfo(keyAlgId, publicKeyInfo.getPublicKeyData().getBytes()); } else { try { DSAParameter.getInstance(keyParameters); } catch (IllegalArgumentException ex) { throw new InvalidKeySpecException("keyParameters is not null and Dss-Parms"); } return publicKeyInfo; } } else if (X9ObjectIdentifiers.id_ecPublicKey.equals(algOid)) { if (keyParameters == null) { throw new InvalidKeySpecException("keyParameters is not an OBJECT IDENTIFIER"); } try { ASN1ObjectIdentifier.getInstance(keyParameters); } catch (IllegalArgumentException ex) { throw new InvalidKeySpecException("keyParameters is not an OBJECT IDENTIFIER"); } return publicKeyInfo; } else { return publicKeyInfo; } } public static String cutText(final String text, final int maxLen) { ParamUtil.requireNonNull("text", text); if (text.length() <= maxLen) { return text; } StringBuilder sb = new StringBuilder(maxLen); sb.append(text.substring(0, maxLen - 13)); sb.append("...skipped..."); return sb.toString(); } public static String cutX500Name(final X500Name name, final int maxLen) { String text = getRfc4519Name(name); return cutText(text, maxLen); } public static String cutX500Name(final X500Principal name, final int maxLen) { String text = getRfc4519Name(name); return cutText(text, maxLen); } public static Extension createExtensionSubjectAltName(final List<String> taggedValues, final boolean critical) throws BadInputException { GeneralNames names = createGeneralNames(taggedValues); if (names == null) { return null; } try { return new Extension(Extension.subjectAlternativeName, critical, names.getEncoded()); } catch (IOException ex) { throw new RuntimeException(ex.getMessage(), ex); } } public static Extension createExtensionSubjectInfoAccess( final List<String> accessMethodAndLocations, final boolean critical) throws BadInputException { if (CollectionUtil.isEmpty(accessMethodAndLocations)) { return null; } ASN1EncodableVector vector = new ASN1EncodableVector(); for (String accessMethodAndLocation : accessMethodAndLocations) { vector.add(createAccessDescription(accessMethodAndLocation)); } ASN1Sequence seq = new DERSequence(vector); try { return new Extension(Extension.subjectInfoAccess, critical, seq.getEncoded()); } catch (IOException ex) { throw new RuntimeException(ex.getMessage(), ex); } } public static AccessDescription createAccessDescription(final String accessMethodAndLocation) throws BadInputException { ParamUtil.requireNonNull("accessMethodAndLocation", accessMethodAndLocation); ConfPairs pairs; try { pairs = new ConfPairs(accessMethodAndLocation); } catch (IllegalArgumentException ex) { throw new BadInputException("invalid accessMethodAndLocation " + accessMethodAndLocation); } Set<String> oids = pairs.getNames(); if (oids == null || oids.size() != 1) { throw new BadInputException("invalid accessMethodAndLocation " + accessMethodAndLocation); } String accessMethodS = oids.iterator().next(); String taggedValue = pairs.getValue(accessMethodS); ASN1ObjectIdentifier accessMethod = new ASN1ObjectIdentifier(accessMethodS); GeneralName location = createGeneralName(taggedValue); return new AccessDescription(accessMethod, location); } public static GeneralNames createGeneralNames(final List<String> taggedValues) throws BadInputException { if (CollectionUtil.isEmpty(taggedValues)) { return null; } int len = taggedValues.size(); GeneralName[] names = new GeneralName[len]; for (int i = 0; i < len; i++) { names[i] = createGeneralName(taggedValues.get(i)); } return new GeneralNames(names); } /** * * @param taggedValue [tag]value, and the value for tags otherName and ediPartyName is * type=value. */ public static GeneralName createGeneralName(final String taggedValue) throws BadInputException { ParamUtil.requireNonBlank("taggedValue", taggedValue); int tag = -1; String value = null; if (taggedValue.charAt(0) == '[') { int idx = taggedValue.indexOf(']', 1); if (idx > 1 && idx < taggedValue.length() - 1) { String tagS = taggedValue.substring(1, idx); try { tag = Integer.parseInt(tagS); value = taggedValue.substring(idx + 1); } catch (NumberFormatException ex) { throw new BadInputException("invalid tag '" + tagS + "'"); } } } if (tag == -1) { throw new BadInputException("invalid taggedValue " + taggedValue); } switch (tag) { case GeneralName.otherName: if (value == null) { throw new BadInputException("invalid otherName: no value specified"); } int idxSep = value.indexOf("="); if (idxSep == -1 || idxSep == 0 || idxSep == value.length() - 1) { throw new BadInputException("invalid otherName " + value); } String otherTypeOid = value.substring(0, idxSep); ASN1ObjectIdentifier type = new ASN1ObjectIdentifier(otherTypeOid); String otherValue = value.substring(idxSep + 1); ASN1EncodableVector vector = new ASN1EncodableVector(); vector.add(type); vector.add(new DERTaggedObject(true, 0, new DERUTF8String(otherValue))); DERSequence seq = new DERSequence(vector); return new GeneralName(GeneralName.otherName, seq); case GeneralName.rfc822Name: return new GeneralName(tag, value); case GeneralName.dNSName: return new GeneralName(tag, value); case GeneralName.directoryName: X500Name x500Name = reverse(new X500Name(value)); return new GeneralName(GeneralName.directoryName, x500Name); case GeneralName.ediPartyName: if (value == null) { throw new BadInputException("invalid ediPartyName: no value specified"); } idxSep = value.indexOf("="); if (idxSep == -1 || idxSep == value.length() - 1) { throw new BadInputException("invalid ediPartyName " + value); } String nameAssigner = (idxSep == 0) ? null : value.substring(0, idxSep); String partyName = value.substring(idxSep + 1); vector = new ASN1EncodableVector(); if (nameAssigner != null) { vector.add(new DERTaggedObject(false, 0, new DirectoryString(nameAssigner))); } vector.add(new DERTaggedObject(false, 1, new DirectoryString(partyName))); seq = new DERSequence(vector); return new GeneralName(GeneralName.ediPartyName, seq); case GeneralName.uniformResourceIdentifier: return new GeneralName(tag, value); case GeneralName.iPAddress: return new GeneralName(tag, value); case GeneralName.registeredID: return new GeneralName(tag, value); default: throw new RuntimeException("unsupported tag " + tag); } // end switch (tag) } // method createGeneralName }