/* * Copyright (c) 2011-2012 ICM Uniwersytet Warszawski All rights reserved. * See LICENCE file for licensing information. * * Parts of this class are derived from the glite.security.util-java module, * copyrighted as follows: * * Copyright (c) Members of the EGEE Collaboration. 2004. See * http://www.eu-egee.org/partners/ for details on the copyright holders. */ package eu.emi.security.authn.x509.proxy; import java.io.IOException; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.List; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.pkcs.Attribute; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.pkcs.PKCS10CertificationRequest; import eu.emi.security.authn.x509.helpers.JavaAndBCStyle; import eu.emi.security.authn.x509.helpers.proxy.DraftRFCProxyCertInfoExtension; import eu.emi.security.authn.x509.helpers.proxy.ProxyAddressRestrictionData; import eu.emi.security.authn.x509.helpers.proxy.ProxyCertInfoExtension; import eu.emi.security.authn.x509.helpers.proxy.ProxyHelper; import eu.emi.security.authn.x509.helpers.proxy.ProxySAMLExtension; import eu.emi.security.authn.x509.helpers.proxy.ProxyTracingExtension; import eu.emi.security.authn.x509.helpers.proxy.RFCProxyCertInfoExtension; import eu.emi.security.authn.x509.impl.CertificateUtils; /** * A class to get the information from the proxy certificate request. * * @author J. Hahkala * @author K. Benedyczak */ public class ProxyCSRInfo { static { CertificateUtils.configureSecProvider(); } private PKCS10CertificationRequest csr; private List<CertificateExtension> extensions = new ArrayList<CertificateExtension>(); private String samlAssertion; private ProxyCertInfoExtension proxyExt; private String proxyExtOid; private String tracingSubject; private String tracingIssuer; private String[][] sourceRestrictions; private String[][] targetRestrictions; /** * Generates new instance of this class using the Certificate Signing Request * @param csr certificate signing request * @throws CertificateException if the Certificate Signing Request is invalid */ public ProxyCSRInfo(PKCS10CertificationRequest csr) throws CertificateException { this.csr = csr; try { parseRequestedExtensions(); } catch (IOException e) { throw new CertificateException("The CSR can not be parsed as a Proxy CSR", e); } } /** * The type of the proxy certificate requested is returned or null if can not be determined. In principle * the null response means that the DN is not a valid LEGACY proxy DN, and that either RFC or DRAFT * proxy should be generated. * @return the proxy type */ public ProxyType getProxyType() { if (proxyExtOid != null && proxyExtOid.equals(RFCProxyCertInfoExtension.RFC_EXTENSION_OID)) return ProxyType.RFC3820; if (proxyExtOid != null && proxyExtOid.equals(DraftRFCProxyCertInfoExtension.DRAFT_EXTENSION_OID)) return ProxyType.DRAFT_RFC; String value; try { value = getLastCN(); } catch (IllegalArgumentException e) //empty or wrong subject { value = ""; } catch (IOException e) { throw new IllegalArgumentException("The CSR can not be parsed", e); } if ("proxy".equals(value.toLowerCase()) || "limited proxy".equals(value.toLowerCase())) return ProxyType.LEGACY; return null; } private String getLastCN() throws IllegalArgumentException, IOException { byte[] subject = csr.getSubject().getEncoded(ASN1Encoding.DER); X500Name withDefaultStyle = X500Name.getInstance(subject); JavaAndBCStyle style = new JavaAndBCStyle(); return ProxyHelper.getLastCN(X500Name.getInstance(style, withDefaultStyle)); } /** * Used to check whether the Certificate Signing Request is for a limited proxy or not. * @return null if not set */ public Boolean isLimited() { ProxyPolicy policy = getPolicy(); if (policy != null) { return ProxyPolicy.LIMITED_PROXY_OID.equals(policy.getPolicyOID()); } else { String value; try { value = getLastCN(); } catch (IllegalArgumentException e) //empty or wrong subject { value = ""; } catch (IOException e) { throw new IllegalArgumentException("The CSR can not be parsed", e); } if (value.toLowerCase().equals("proxy")) return false; else if ("limited proxy".equals(value.toLowerCase())) return true; return null; } } /** * Gets the requested RFC proxy extension policy OID and octets of the * policy. See RFC3820. Policy can be null in case the OID in it self * defines the behavior, like with "inherit all" policy or * "independent" policy. * @return the requested policy or null if not set */ public ProxyPolicy getPolicy() { if (proxyExt == null) return null; return proxyExt.getPolicy(); } /** * Returns an requested URL of the proxy tracing issuer. * * @return The proxy tracing issuer URL in String format, * or null if was not requested. */ public String getProxyTracingIssuer() { return tracingIssuer; } /** * Returns a requested URL of the proxy tracing subject. * @return The proxy tracing subject URL in String format, * or null if was not requested. */ public String getProxyTracingSubject() { return tracingSubject; } /** * Returns the SAML extension from the certificate chain. * * @return The SAML assertion in String format or null if not set */ public String getSAMLExtension() { return samlAssertion; } /** * Returns the proxy path length limit set in the Certificate Signing Request. * Returns an Integer.MAX_VALUE value if length is set to be unlimited. * @return the requested proxy path length. */ public Integer getProxyPathLimit() { if (proxyExt == null) return Integer.MAX_VALUE; return proxyExt.getProxyPathLimit(); } /** * Gets the proxy source restriction data from the Certificate Signing Request. * The returned array has as the first item the array of allowed namespaces * and as the second item the array of excluded namespaces. * @return null if the extension was not set */ public String[][] getProxySourceRestrictions() { return sourceRestrictions; } /** * Gets the proxy target restriction data from the Certificate Signing Request. * The returned array has as the first item the array of allowed namespaces * and as the second item the array of excluded namespaces. * @return null if the extension was not set */ public String[][] getProxyTargetRestrictions() { return targetRestrictions; } private void parseRequestedExtensions() throws IOException { Attribute[] attrs = csr.getAttributes(); if (attrs == null) return; for (Attribute attr: attrs) { if (PKCSObjectIdentifiers.pkcs_9_at_extensionRequest.getId().equals( attr.getAttrType().getId())) { if (attr.getAttrValues().size() == 0) continue; ASN1Encodable req = attr.getAttrValues().getObjectAt(0); CertificateExtension ext = new CertificateExtension(req.toASN1Primitive().getEncoded(ASN1Encoding.DER)); handleRequestedExtension(ext); } } } private void handleRequestedExtension(CertificateExtension ext) throws IOException { String oid = ext.getOid(); byte[] val = ext.getValue().toASN1Primitive().getEncoded(ASN1Encoding.DER); if (oid.equals(DraftRFCProxyCertInfoExtension.DRAFT_EXTENSION_OID)) { proxyExtOid = oid; proxyExt = new DraftRFCProxyCertInfoExtension(val); } else if (oid.equals(RFCProxyCertInfoExtension.RFC_EXTENSION_OID)) { proxyExtOid = oid; proxyExt = new RFCProxyCertInfoExtension(val); } else if (oid.equals(ProxySAMLExtension.LEGACY_SAML_OID) || oid.equals(ProxySAMLExtension.SAML_OID)) { samlAssertion = new ProxySAMLExtension(val).getSAML(); } else if (oid.equals(ProxyTracingExtension.PROXY_TRACING_ISSUER_EXTENSION_OID)) { tracingIssuer = new ProxyTracingExtension(val).getURL(); } else if (oid.equals(ProxyTracingExtension.PROXY_TRACING_SUBJECT_EXTENSION_OID)) { tracingSubject = new ProxyTracingExtension(val).getURL(); } else if (oid.equals(ProxyAddressRestrictionData.SOURCE_RESTRICTION_OID)) { sourceRestrictions = new String[2][]; sourceRestrictions[0] = new ProxyAddressRestrictionData(val).getPermittedAddresses(); sourceRestrictions[1] = new ProxyAddressRestrictionData(val).getExcludedAddresses(); } else if (oid.equals(ProxyAddressRestrictionData.TARGET_RESTRICTION_OID)) { targetRestrictions = new String[2][]; targetRestrictions[0] = new ProxyAddressRestrictionData(val).getPermittedAddresses(); targetRestrictions[1] = new ProxyAddressRestrictionData(val).getExcludedAddresses(); } else { extensions.add(ext); } } }