| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.x509;  | 
 | 
 | 
 | 
import java.io.IOException;  | 
 | 
import java.io.OutputStream;  | 
 | 
import java.lang.reflect.Constructor;  | 
 | 
import java.lang.reflect.Field;  | 
 | 
import java.lang.reflect.InvocationTargetException;  | 
 | 
import java.security.cert.CertificateException;  | 
 | 
import java.util.*;  | 
 | 
 | 
 | 
import sun.security.util.HexDumpEncoder;  | 
 | 
 | 
 | 
import sun.security.util.*;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public class CertificateExtensions implements CertAttrSet<Extension> { | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static final String IDENT = "x509.info.extensions";  | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public static final String NAME = "extensions";  | 
 | 
 | 
 | 
    private static final Debug debug = Debug.getInstance("x509"); | 
 | 
 | 
 | 
    private Map<String,Extension> map = Collections.synchronizedMap(  | 
 | 
            new TreeMap<String,Extension>());  | 
 | 
    private boolean unsupportedCritExt = false;  | 
 | 
 | 
 | 
    private Map<String,Extension> unparseableExtensions;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public CertificateExtensions() { } | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public CertificateExtensions(DerInputStream in) throws IOException { | 
 | 
        init(in);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private void init(DerInputStream in) throws IOException { | 
 | 
 | 
 | 
        DerValue[] exts = in.getSequence(5);  | 
 | 
 | 
 | 
        for (int i = 0; i < exts.length; i++) { | 
 | 
            Extension ext = new Extension(exts[i]);  | 
 | 
            parseExtension(ext);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static Class<?>[] PARAMS = {Boolean.class, Object.class}; | 
 | 
 | 
 | 
      | 
 | 
    private void parseExtension(Extension ext) throws IOException { | 
 | 
        try { | 
 | 
            Class<?> extClass = OIDMap.getClass(ext.getExtensionId());  | 
 | 
            if (extClass == null) {    | 
 | 
                if (ext.isCritical()) { | 
 | 
                    unsupportedCritExt = true;  | 
 | 
                }  | 
 | 
                if (map.put(ext.getExtensionId().toString(), ext) == null) { | 
 | 
                    return;  | 
 | 
                } else { | 
 | 
                    throw new IOException("Duplicate extensions not allowed"); | 
 | 
                }  | 
 | 
            }  | 
 | 
            Constructor<?> cons = extClass.getConstructor(PARAMS);  | 
 | 
 | 
 | 
            Object[] passed = new Object[] {Boolean.valueOf(ext.isCritical()), | 
 | 
                    ext.getExtensionValue()};  | 
 | 
                    CertAttrSet<?> certExt = (CertAttrSet<?>)  | 
 | 
                            cons.newInstance(passed);  | 
 | 
                    if (map.put(certExt.getName(), (Extension)certExt) != null) { | 
 | 
                        throw new IOException("Duplicate extensions not allowed"); | 
 | 
                    }  | 
 | 
        } catch (InvocationTargetException invk) { | 
 | 
            Throwable e = invk.getTargetException();  | 
 | 
            if (ext.isCritical() == false) { | 
 | 
                  | 
 | 
                if (unparseableExtensions == null) { | 
 | 
                    unparseableExtensions = new TreeMap<String,Extension>();  | 
 | 
                }  | 
 | 
                unparseableExtensions.put(ext.getExtensionId().toString(),  | 
 | 
                        new UnparseableExtension(ext, e));  | 
 | 
                if (debug != null) { | 
 | 
                    debug.println("Debug info only." + | 
 | 
                       " Error parsing extension: " + ext);  | 
 | 
                    e.printStackTrace();  | 
 | 
                    HexDumpEncoder h = new HexDumpEncoder();  | 
 | 
                    System.err.println(h.encodeBuffer(ext.getExtensionValue()));  | 
 | 
                }  | 
 | 
                return;  | 
 | 
            }  | 
 | 
            if (e instanceof IOException) { | 
 | 
                throw (IOException)e;  | 
 | 
            } else { | 
 | 
                throw new IOException(e);  | 
 | 
            }  | 
 | 
        } catch (IOException e) { | 
 | 
            throw e;  | 
 | 
        } catch (Exception e) { | 
 | 
            throw new IOException(e);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void encode(OutputStream out)  | 
 | 
    throws CertificateException, IOException { | 
 | 
        encode(out, false);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void encode(OutputStream out, boolean isCertReq)  | 
 | 
    throws CertificateException, IOException { | 
 | 
        DerOutputStream extOut = new DerOutputStream();  | 
 | 
        Collection<Extension> allExts = map.values();  | 
 | 
        Object[] objs = allExts.toArray();  | 
 | 
 | 
 | 
        for (int i = 0; i < objs.length; i++) { | 
 | 
            if (objs[i] instanceof CertAttrSet)  | 
 | 
                ((CertAttrSet)objs[i]).encode(extOut);  | 
 | 
            else if (objs[i] instanceof Extension)  | 
 | 
                ((Extension)objs[i]).encode(extOut);  | 
 | 
            else  | 
 | 
                throw new CertificateException("Illegal extension object"); | 
 | 
        }  | 
 | 
 | 
 | 
        DerOutputStream seq = new DerOutputStream();  | 
 | 
        seq.write(DerValue.tag_Sequence, extOut);  | 
 | 
 | 
 | 
        DerOutputStream tmp;  | 
 | 
        if (!isCertReq) {  | 
 | 
            tmp = new DerOutputStream();  | 
 | 
            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)3),  | 
 | 
                    seq);  | 
 | 
        } else  | 
 | 
            tmp = seq;   | 
 | 
 | 
 | 
        out.write(tmp.toByteArray());  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void set(String name, Object obj) throws IOException { | 
 | 
        if (obj instanceof Extension) { | 
 | 
            map.put(name, (Extension)obj);  | 
 | 
        } else { | 
 | 
            throw new IOException("Unknown extension type."); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Extension get(String name) throws IOException { | 
 | 
        Extension obj = map.get(name);  | 
 | 
        if (obj == null) { | 
 | 
            throw new IOException("No extension found with name " + name); | 
 | 
        }  | 
 | 
        return (obj);  | 
 | 
    }  | 
 | 
 | 
 | 
    // Similar to get(String), but throw no exception, might return null.  | 
 | 
      | 
 | 
    Extension getExtension(String name) { | 
 | 
        return map.get(name);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void delete(String name) throws IOException { | 
 | 
        Object obj = map.get(name);  | 
 | 
        if (obj == null) { | 
 | 
            throw new IOException("No extension found with name " + name); | 
 | 
        }  | 
 | 
        map.remove(name);  | 
 | 
    }  | 
 | 
 | 
 | 
    public String getNameByOid(ObjectIdentifier oid) throws IOException { | 
 | 
        for (String name: map.keySet()) { | 
 | 
            if (map.get(name).getExtensionId().equals(oid)) { | 
 | 
                return name;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Enumeration<Extension> getElements() { | 
 | 
        return Collections.enumeration(map.values());  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Collection<Extension> getAllExtensions() { | 
 | 
        return map.values();  | 
 | 
    }  | 
 | 
 | 
 | 
    public Map<String,Extension> getUnparseableExtensions() { | 
 | 
        if (unparseableExtensions == null) { | 
 | 
            return Collections.emptyMap();  | 
 | 
        } else { | 
 | 
            return unparseableExtensions;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public String getName() { | 
 | 
        return NAME;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean hasUnsupportedCriticalExtension() { | 
 | 
        return unsupportedCritExt;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean equals(Object other) { | 
 | 
        if (this == other)  | 
 | 
            return true;  | 
 | 
        if (!(other instanceof CertificateExtensions))  | 
 | 
            return false;  | 
 | 
        Collection<Extension> otherC =  | 
 | 
                ((CertificateExtensions)other).getAllExtensions();  | 
 | 
        Object[] objs = otherC.toArray();  | 
 | 
 | 
 | 
        int len = objs.length;  | 
 | 
        if (len != map.size())  | 
 | 
            return false;  | 
 | 
 | 
 | 
        Extension otherExt, thisExt;  | 
 | 
        String key = null;  | 
 | 
        for (int i = 0; i < len; i++) { | 
 | 
            if (objs[i] instanceof CertAttrSet)  | 
 | 
                key = ((CertAttrSet)objs[i]).getName();  | 
 | 
            otherExt = (Extension)objs[i];  | 
 | 
            if (key == null)  | 
 | 
                key = otherExt.getExtensionId().toString();  | 
 | 
            thisExt = map.get(key);  | 
 | 
            if (thisExt == null)  | 
 | 
                return false;  | 
 | 
            if (! thisExt.equals(otherExt))  | 
 | 
                return false;  | 
 | 
        }  | 
 | 
        return this.getUnparseableExtensions().equals(  | 
 | 
                ((CertificateExtensions)other).getUnparseableExtensions());  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public int hashCode() { | 
 | 
        return map.hashCode() + getUnparseableExtensions().hashCode();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public String toString() { | 
 | 
        return map.toString();  | 
 | 
    }  | 
 | 
 | 
 | 
}  | 
 | 
 | 
 | 
class UnparseableExtension extends Extension { | 
 | 
    private String name;  | 
 | 
    private Throwable why;  | 
 | 
 | 
 | 
    public UnparseableExtension(Extension ext, Throwable why) { | 
 | 
        super(ext);  | 
 | 
 | 
 | 
        name = "";  | 
 | 
        try { | 
 | 
            Class<?> extClass = OIDMap.getClass(ext.getExtensionId());  | 
 | 
            if (extClass != null) { | 
 | 
                Field field = extClass.getDeclaredField("NAME"); | 
 | 
                name = (String)(field.get(null)) + " ";  | 
 | 
            }  | 
 | 
        } catch (Exception e) { | 
 | 
            // If we cannot find the name, just ignore it  | 
 | 
        }  | 
 | 
 | 
 | 
        this.why = why;  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override public String toString() { | 
 | 
        return super.toString() +  | 
 | 
                "Unparseable " + name + "extension due to\n" + why + "\n\n" +  | 
 | 
                new HexDumpEncoder().encodeBuffer(getExtensionValue());  | 
 | 
    }  | 
 | 
}  |