
org.italiangrid.voms.asn1.VOMSACUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of voms-api-java Show documentation
Show all versions of voms-api-java Show documentation
Java APIs to validate and request VOMS attribute certificates
The newest version!
/**
* Copyright (c) Istituto Nazionale di Fisica Nucleare, 2006-2014.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.italiangrid.voms.asn1;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.x509.Attribute;
import org.bouncycastle.asn1.x509.AttributeCertificate;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.IetfAttrSyntax;
import org.bouncycastle.asn1.x509.Target;
import org.bouncycastle.asn1.x509.TargetInformation;
import org.bouncycastle.asn1.x509.Targets;
import org.bouncycastle.cert.X509AttributeCertificateHolder;
import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
import org.italiangrid.voms.VOMSAttribute;
import org.italiangrid.voms.VOMSError;
import org.italiangrid.voms.VOMSGenericAttribute;
import org.italiangrid.voms.ac.impl.VOMSAttributesImpl;
import org.italiangrid.voms.ac.impl.VOMSGenericAttributeImpl;
/**
* A set of VOMS AC handling utilities.
*
* @author Andrea Ceccanti
*
*/
public class VOMSACUtils implements VOMSConstants {
public static final String POLICY_AUTHORITY_SEP = "://";
/**
* Returns the VOMS extension, if present, in a given certificate
*
* @param cert
* the {@link X509Certificate} where the extension will be searched
* @return the DER-encoded octet string of the extension value or null if it
* is not present.
*/
public static byte[] getVOMSExtensionFromCertificate(X509Certificate cert) {
return cert.getExtensionValue(VOMSConstants.VOMS_EXTENSION_OID.getId());
}
/**
* Deserializes the VOMS Attribute certificates in a given certificate
* extension
*
* @param vomsExtension
* the VOMS extension
* @return the possibly empty {@link List} of {@link AttributeCertificate}
* extracted from a given extension
* @throws IOException
* in case of deserialization errors
*/
public static List getACsFromVOMSExtension(
byte[] vomsExtension) throws IOException {
List acs = null;
if (vomsExtension == null)
return Collections.emptyList();
acs = new ArrayList();
// Convert extension to a DEROctetString
ASN1InputStream asn1Stream = new ASN1InputStream(new ByteArrayInputStream(
vomsExtension));
byte[] payload = ((DEROctetString) asn1Stream.readObject()).getOctets();
asn1Stream.close();
asn1Stream = new ASN1InputStream(new ByteArrayInputStream(payload));
// VOMS extension is SEQUENCE of SET of AttributeCertificate
// now, SET is an ordered sequence, and an AC is a sequence as
// well -- thus the three nested ASN.1 sequences below...
ASN1Sequence baseSequence = (ASN1Sequence) asn1Stream.readObject();
asn1Stream.close();
@SuppressWarnings("unchecked")
Enumeration setSequence = baseSequence.getObjects();
while (setSequence.hasMoreElements()) {
ASN1Sequence acSequence = setSequence.nextElement();
@SuppressWarnings("unchecked")
Enumeration theACs = acSequence.getObjects();
while (theACs.hasMoreElements()) {
AttributeCertificate parsedAC =
AttributeCertificate.getInstance(theACs.nextElement());
acs.add(parsedAC);
}
}
return acs;
}
/**
* Deserializes the VOMS Attribute certificates, if present, in a given
* certificate passed as argument
*
* @param cert
* the {@link X509Certificate} where the ACs will be searched
* @return the possibly empty {@link List} of {@link AttributeCertificate}
* objects extracted from the VOMS extension
* @throws IOException
* in case of deserialization errors
*/
public static List getACsFromCertificate(
X509Certificate cert) throws IOException {
return getACsFromVOMSExtension(getVOMSExtensionFromCertificate(cert));
}
/**
* Deserializes the FQANs contained in a {@link IetfAttrSyntax} object
*
* @param attr
* the {@link IetfAttrSyntax} attribute syntax object containing the
* VOMS extension
* @return a {@link List} of FQANs
*/
private static List deserializeFQANs(IetfAttrSyntax attr) {
if (attr.getValueType() != IetfAttrSyntax.VALUE_OCTETS)
raiseACNonConformantError("unsupported attribute values encoding.");
List fqans = new ArrayList();
ASN1OctetString[] values = (ASN1OctetString[]) attr.getValues();
for (ASN1OctetString s : values)
fqans.add(new String(s.getOctets()));
return fqans;
}
@SuppressWarnings("rawtypes")
private static List deserializeACTargets(
X509AttributeCertificateHolder ac) {
List targets = new ArrayList();
Extension targetExtension = ac.getExtension(Extension.targetInformation);
if (targetExtension == null)
return targets;
TargetInformation ti = TargetInformation
.getInstance((ASN1Sequence) targetExtension.getParsedValue());
// Only one Targets according to RFC 3281
Targets asn1TargetContainer = ti.getTargetsObjects()[0];
// The deserialization has to be done by hand since it seems VOMS
// does not correctly encode the ACTargets extension...
ASN1Sequence targetSequence = (ASN1Sequence) asn1TargetContainer
.toASN1Primitive();
Target[] asn1Targets = new Target[targetSequence.size()];
int count = 0;
for (Enumeration e = targetSequence.getObjects(); e.hasMoreElements();) {
// There's one sequence more than expected here that makes
// the bc constructor fail...
ASN1Sequence seq = (ASN1Sequence) e.nextElement();
ASN1TaggedObject val = (ASN1TaggedObject) seq.getObjectAt(0);
asn1Targets[count++] = Target.getInstance(val);
}
// Extract the actual string
for (Target t : asn1Targets) {
GeneralName targetURI = t.getTargetName();
if (targetURI.getTagNo() != GeneralName.uniformResourceIdentifier)
raiseACNonConformantError("wrong AC target extension encoding. Only URI targets are supported.");
String targetString = ((DERIA5String) targetURI.getName()).getString();
targets.add(targetString);
}
return targets;
}
private static void raiseACNonConformantError(String errorString) {
throw new VOMSError("Non conformant VOMS Attribute certificate: "
+ errorString);
}
/**
* Peforms some sanity checks on the format of the policy authority field
* found in a VOMS extension. The enforced format is: vo://host:port
*
* @param attr
* the {@link IetfAttrSyntax} attribute syntax object containing the
* VOMS extension
* @return the validated policy authority as a {@link String}
*/
private static String policyAuthoritySanityChecks(IetfAttrSyntax attr) {
// The policy authority value is encoded as a DERIA5String
String policyAuthority = ((DERIA5String) attr.getPolicyAuthority()
.getNames()[0].getName()).getString();
// PolicyAuthority scheme: ://:
int index = policyAuthority.indexOf(POLICY_AUTHORITY_SEP);
if ((index < 0) || (index == policyAuthority.length() - 1))
raiseACNonConformantError("unsupported policy authority encoding '"
+ policyAuthority + "'");
return policyAuthority;
}
/**
* Deserializes the information in a list of VOMS attribute certificates.
*
* @param acs
* a {@link List} of VOMS acs
* @return a possibly empty list of {@link VOMSAttribute}
*/
public static List deserializeVOMSAttributes(
List acs) {
if (acs == null || acs.size() == 0)
return Collections.emptyList();
List attributes = new ArrayList();
for (AttributeCertificate a : acs) {
attributes.add(deserializeVOMSAttributes(a));
}
return attributes;
}
/**
* Deserializes the information in a VOMS attribute certificate.
*
* @param ac
* a VOMS {@link AttributeCertificate}
* @return a {@link VOMSAttribute} object which provides more convenient
* access to the VOMS authorization information
*/
public static VOMSAttribute deserializeVOMSAttributes(AttributeCertificate ac) {
VOMSAttributesImpl attrs = new VOMSAttributesImpl();
X509AttributeCertificateHolder acHolder = new X509AttributeCertificateHolder(
ac);
Attribute[] asn1Attrs = acHolder.getAttributes(VOMS_FQANS_OID);
for (Attribute a : asn1Attrs) {
ASN1Primitive theVOMSDerObject = a.getAttributeValues()[0]
.toASN1Primitive();
IetfAttrSyntax attrSyntax = IetfAttrSyntax.getInstance(ASN1Sequence
.getInstance(theVOMSDerObject));
String policyAuthority = policyAuthoritySanityChecks(attrSyntax);
// The policy authority string has the following format:
// ://:
attrs.setVO(policyAuthority.substring(0,
policyAuthority.indexOf(POLICY_AUTHORITY_SEP)));
attrs.setHost(policyAuthority.substring(
policyAuthority.indexOf(POLICY_AUTHORITY_SEP) + 3,
policyAuthority.lastIndexOf(":")));
attrs.setPort(Integer.parseInt(policyAuthority.substring(policyAuthority
.lastIndexOf(":") + 1)));
attrs.setFQANs(deserializeFQANs(attrSyntax));
attrs.setNotBefore(acHolder.getNotBefore());
attrs.setNotAfter(acHolder.getNotAfter());
attrs.setSignature(acHolder.getSignature());
attrs.setGenericAttributes(deserializeGAs(acHolder));
attrs.setAACertificates(deserializeACCerts(acHolder));
attrs.setTargets(deserializeACTargets(acHolder));
attrs.setVOMSAC(acHolder);
try {
attrs.setIssuer(new X500Principal(acHolder.getIssuer().getNames()[0]
.getEncoded()));
attrs.setHolder(new X500Principal(acHolder.getHolder().getIssuer()[0]
.getEncoded()));
attrs.setHolderSerialNumber(acHolder.getHolder().getSerialNumber());
} catch (IOException e) {
throw new VOMSError(
"Error parsing attribute certificate issuer or holder name: "
+ e.getMessage(), e);
}
}
return attrs;
}
/**
* Deserializes the VOMS generic attributes
*
* @param ac
* the VOMS {@link X509AttributeCertificateHolder}
* @return the {@link List} of {@link VOMSGenericAttribute} contained in the
* ac
*/
private static List deserializeGAs(
X509AttributeCertificateHolder ac) {
List gas = new ArrayList();
Extension gasExtension = ac.getExtension(VOMS_GENERIC_ATTRS_OID);
if (gasExtension == null)
return gas;
// SEQUENCE of TagList - contains just one taglist element
ASN1Sequence tagContainerSeq = (ASN1Sequence) gasExtension.getParsedValue();
if (tagContainerSeq.size() != 1)
raiseACNonConformantError("unsupported generic attributes container format.");
// TagList - this also should be a sigle element sequence
ASN1Sequence tagListSeq = (ASN1Sequence) tagContainerSeq.getObjectAt(0);
if (tagListSeq.size() > 1)
raiseACNonConformantError("unsupported taglist format.");
// This TagList sequence is empty, gLite 3.2 VOMS versions had a bug
// that added the extension even there were no attributes encoded...
if (tagListSeq.size() == 0)
return gas;
// Down one level
tagListSeq = (ASN1Sequence) tagListSeq.getObjectAt(0);
// TODO: check policyAuthority!!
// GeneralNames policyAuthority =
// GeneralNames.getInstance(tagListSeq.getObjectAt(0));
// tags SEQUENCE OF Tag
ASN1Sequence tags = (ASN1Sequence) tagListSeq.getObjectAt(1);
@SuppressWarnings("unchecked")
Enumeration e = tags.getObjects();
while (e.hasMoreElements()) {
ASN1Sequence theActualTag = e.nextElement();
if (theActualTag.size() != 3)
raiseACNonConformantError("unsupported tag format.");
VOMSGenericAttributeImpl attribute = new VOMSGenericAttributeImpl();
attribute.setName(new String(DEROctetString.getInstance(
theActualTag.getObjectAt(0)).getOctets()));
attribute.setValue(new String(DEROctetString.getInstance(
theActualTag.getObjectAt(1)).getOctets()));
attribute.setContext(new String(DEROctetString.getInstance(
theActualTag.getObjectAt(2)).getOctets()));
gas.add(attribute);
}
return gas;
}
/**
* Deserializes the VOMS ACCerts extension
*
* @param ac
* the VOMS {@link X509AttributeCertificateHolder}
* @return the parsed array of {@link X509Certificate}
*/
private static X509Certificate[] deserializeACCerts(
X509AttributeCertificateHolder ac) {
List certs = new ArrayList();
Extension e = ac.getExtension(VOMS_CERTS_OID);
if (e == null) {
return null;
}
ASN1Sequence certSeq = (ASN1Sequence) e.getParsedValue();
if (certSeq.size() != 1) {
raiseACNonConformantError("unsupported accerts format.");
}
// Down one level
certSeq = (ASN1Sequence) certSeq.getObjectAt(0);
@SuppressWarnings("unchecked")
Enumeration encodedCerts = certSeq.getObjects();
CertificateFactory cf = new CertificateFactory();
while (encodedCerts.hasMoreElements()) {
DLSequence s = encodedCerts.nextElement();
X509Certificate theCert;
try {
ASN1InputStream stream = new ASN1InputStream(s.getEncoded());
theCert = (X509Certificate) cf.engineGenerateCertificate(stream);
} catch (CertificateParsingException ex) {
throw new VOMSError("Certificate parsing error: " + ex.getMessage(), ex);
} catch (CertificateEncodingException ex) {
throw new VOMSError("Certificate encoding error: " + ex.getMessage(),
ex);
} catch (CertificateException ex) {
throw new VOMSError("Error generating certificate from parsed data: "
+ ex.getMessage(), ex);
} catch (IOException ex) {
throw new VOMSError("Certficate parsing error : "+ex.getMessage(),
ex);
}
certs.add(theCert);
}
return certs.toArray(new X509Certificate[certs.size()]);
}
private VOMSACUtils() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy