package org.cagrid.gaards.pki;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Writer;
import java.math.BigInteger;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CRLException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.RSAPrivateKey;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OutputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.DSAParameter;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.util.encoders.Base64;
/**
* @author <A href="mailto:langella@bmi.osu.edu">Stephen Langella </A>
* @author <A href="mailto:oster@bmi.osu.edu">Scott Oster </A>
* @author <A href="mailto:hastings@bmi.osu.edu">Shannon Hastings </A>
* @version $Id: ArgumentManagerTable.java,v 1.2 2004/10/15 16:35:16 langella
* Exp $
*/
public class PEMWriter extends BufferedWriter {
/**
* Base constructor.
*
* @param out
* output stream to use.
*/
public PEMWriter(Writer out) {
super(out);
}
private void writeEncoded(byte[] bytes) throws IOException {
char[] buf = new char[64];
bytes = Base64.encode(bytes);
for (int i = 0; i < bytes.length; i += buf.length) {
int index = 0;
while (index != buf.length) {
if ((i + index) >= bytes.length) {
break;
}
buf[index] = (char) bytes[i + index];
index++;
}
this.write(buf, 0, index);
this.newLine();
}
}
public void writeObject(Object o) throws IOException {
String type;
byte[] encoding;
if (o instanceof X509Certificate) {
type = "CERTIFICATE";
try {
encoding = ((X509Certificate) o).getEncoded();
} catch (CertificateEncodingException e) {
throw new IOException("Cannot encode object: " + e.toString());
}
} else if (o instanceof X509CRL) {
type = "X509 CRL";
try {
encoding = ((X509CRL) o).getEncoded();
} catch (CRLException e) {
throw new IOException("Cannot encode object: " + e.toString());
}
} else if (o instanceof PrivateKey) {
ByteArrayInputStream bIn = new ByteArrayInputStream(((Key) o).getEncoded());
ASN1InputStream aIn = new ASN1InputStream(bIn);
PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) aIn.readObject());
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
if (o instanceof RSAPrivateKey) {
type = "RSA PRIVATE KEY";
aOut.writeObject(info.getPrivateKey());
} else if (o instanceof DSAPrivateKey) {
type = "DSA PRIVATE KEY";
DSAParameter p = DSAParameter.getInstance(info.getAlgorithmId().getParameters());
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new DERInteger(0));
v.add(new DERInteger(p.getP()));
v.add(new DERInteger(p.getQ()));
v.add(new DERInteger(p.getG()));
BigInteger x = ((DSAPrivateKey) o).getX();
BigInteger y = p.getG().modPow(x, p.getP());
v.add(new DERInteger(y));
v.add(new DERInteger(x));
aOut.writeObject(new DERSequence(v));
} else {
throw new IOException("Cannot identify private key");
}
encoding = bOut.toByteArray();
} else if (o instanceof PublicKey) {
type = "PUBLIC KEY";
encoding = ((PublicKey) o).getEncoded();
} else if (o instanceof PKCS10CertificationRequest) {
type = "CERTIFICATE REQUEST";
encoding = ((PKCS10CertificationRequest) o).getEncoded();
} else {
throw new IOException("unknown object passed - can't encode.");
}
this.write("-----BEGIN " + type + "-----");
this.newLine();
writeEncoded(encoding);
this.write("-----END " + type + "-----");
this.newLine();
}
/**
* Writes a newline, which is NOT like the base class's use of
* the system property <tt>line.separator</tt>,
* and is not necessarily a single
* newline ('\n') character.
*
* @exception IOException If an I/O error occurs
*/
public void newLine() throws IOException {
write("\n");
}
}