| package org.bouncycastle.openssl; |
| |
| import java.io.IOException; |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.bouncycastle.asn1.ASN1EncodableVector; |
| import org.bouncycastle.asn1.ASN1Integer; |
| import org.bouncycastle.asn1.ASN1ObjectIdentifier; |
| import org.bouncycastle.asn1.DERSequence; |
| import org.bouncycastle.asn1.cms.ContentInfo; |
| import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; |
| import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; |
| import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; |
| import org.bouncycastle.asn1.x509.DSAParameter; |
| import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; |
| import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; |
| import org.bouncycastle.cert.X509AttributeCertificateHolder; |
| import org.bouncycastle.cert.X509CRLHolder; |
| import org.bouncycastle.cert.X509CertificateHolder; |
| import org.bouncycastle.pkcs.PKCS10CertificationRequest; |
| import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; |
| import org.bouncycastle.util.Strings; |
| import org.bouncycastle.util.io.pem.PemGenerationException; |
| import org.bouncycastle.util.io.pem.PemHeader; |
| import org.bouncycastle.util.io.pem.PemObject; |
| import org.bouncycastle.util.io.pem.PemObjectGenerator; |
| |
| /** |
| * PEM generator for the original set of PEM objects used in Open SSL. |
| */ |
| public class MiscPEMGenerator |
| implements PemObjectGenerator |
| { |
| private static final ASN1ObjectIdentifier[] dsaOids = |
| { |
| X9ObjectIdentifiers.id_dsa, |
| OIWObjectIdentifiers.dsaWithSHA1 |
| }; |
| |
| private static final byte[] hexEncodingTable = |
| { |
| (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', |
| (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F' |
| }; |
| |
| private final Object obj; |
| private final PEMEncryptor encryptor; |
| |
| public MiscPEMGenerator(Object o) |
| { |
| this.obj = o; // use of this confuses some earlier JDKs. |
| this.encryptor = null; |
| } |
| |
| public MiscPEMGenerator(Object o, PEMEncryptor encryptor) |
| { |
| this.obj = o; |
| this.encryptor = encryptor; |
| } |
| |
| private PemObject createPemObject(Object o) |
| throws IOException |
| { |
| String type; |
| byte[] encoding; |
| |
| if (o instanceof PemObject) |
| { |
| return (PemObject)o; |
| } |
| if (o instanceof PemObjectGenerator) |
| { |
| return ((PemObjectGenerator)o).generate(); |
| } |
| if (o instanceof X509CertificateHolder) |
| { |
| type = "CERTIFICATE"; |
| |
| encoding = ((X509CertificateHolder)o).getEncoded(); |
| } |
| else if (o instanceof X509CRLHolder) |
| { |
| type = "X509 CRL"; |
| |
| encoding = ((X509CRLHolder)o).getEncoded(); |
| } |
| else if (o instanceof X509TrustedCertificateBlock) |
| { |
| type = "TRUSTED CERTIFICATE"; |
| |
| encoding = ((X509TrustedCertificateBlock)o).getEncoded(); |
| } |
| else if (o instanceof PrivateKeyInfo) |
| { |
| PrivateKeyInfo info = (PrivateKeyInfo)o; |
| ASN1ObjectIdentifier algOID = info.getPrivateKeyAlgorithm().getAlgorithm(); |
| |
| if (algOID.equals(PKCSObjectIdentifiers.rsaEncryption)) |
| { |
| type = "RSA PRIVATE KEY"; |
| |
| encoding = info.parsePrivateKey().toASN1Primitive().getEncoded(); |
| } |
| else if (algOID.equals(dsaOids[0]) || algOID.equals(dsaOids[1])) |
| { |
| type = "DSA PRIVATE KEY"; |
| |
| DSAParameter p = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters()); |
| ASN1EncodableVector v = new ASN1EncodableVector(); |
| |
| v.add(new ASN1Integer(0)); |
| v.add(new ASN1Integer(p.getP())); |
| v.add(new ASN1Integer(p.getQ())); |
| v.add(new ASN1Integer(p.getG())); |
| |
| BigInteger x = ASN1Integer.getInstance(info.parsePrivateKey()).getValue(); |
| BigInteger y = p.getG().modPow(x, p.getP()); |
| |
| v.add(new ASN1Integer(y)); |
| v.add(new ASN1Integer(x)); |
| |
| encoding = new DERSequence(v).getEncoded(); |
| } |
| else if (algOID.equals(X9ObjectIdentifiers.id_ecPublicKey)) |
| { |
| type = "EC PRIVATE KEY"; |
| |
| encoding = info.parsePrivateKey().toASN1Primitive().getEncoded(); |
| } |
| else |
| { |
| throw new IOException("Cannot identify private key"); |
| } |
| } |
| else if (o instanceof SubjectPublicKeyInfo) |
| { |
| type = "PUBLIC KEY"; |
| |
| encoding = ((SubjectPublicKeyInfo)o).getEncoded(); |
| } |
| else if (o instanceof X509AttributeCertificateHolder) |
| { |
| type = "ATTRIBUTE CERTIFICATE"; |
| encoding = ((X509AttributeCertificateHolder)o).getEncoded(); |
| } |
| else if (o instanceof org.bouncycastle.pkcs.PKCS10CertificationRequest) |
| { |
| type = "CERTIFICATE REQUEST"; |
| encoding = ((PKCS10CertificationRequest)o).getEncoded(); |
| } |
| else if (o instanceof PKCS8EncryptedPrivateKeyInfo) |
| { |
| type = "ENCRYPTED PRIVATE KEY"; |
| encoding = ((PKCS8EncryptedPrivateKeyInfo)o).getEncoded(); |
| } |
| else if (o instanceof ContentInfo) |
| { |
| type = "PKCS7"; |
| encoding = ((ContentInfo)o).getEncoded(); |
| } |
| else |
| { |
| throw new PemGenerationException("unknown object passed - can't encode."); |
| } |
| |
| if (encryptor != null) |
| { |
| String dekAlgName = Strings.toUpperCase(encryptor.getAlgorithm()); |
| |
| // Note: For backward compatibility |
| if (dekAlgName.equals("DESEDE")) |
| { |
| dekAlgName = "DES-EDE3-CBC"; |
| } |
| |
| |
| byte[] iv = encryptor.getIV(); |
| |
| byte[] encData = encryptor.encrypt(encoding); |
| |
| List headers = new ArrayList(2); |
| |
| headers.add(new PemHeader("Proc-Type", "4,ENCRYPTED")); |
| headers.add(new PemHeader("DEK-Info", dekAlgName + "," + getHexEncoded(iv))); |
| |
| return new PemObject(type, headers, encData); |
| } |
| return new PemObject(type, encoding); |
| } |
| |
| private String getHexEncoded(byte[] bytes) |
| throws IOException |
| { |
| char[] chars = new char[bytes.length * 2]; |
| |
| for (int i = 0; i != bytes.length; i++) |
| { |
| int v = bytes[i] & 0xff; |
| |
| chars[2 * i] = (char)(hexEncodingTable[(v >>> 4)]); |
| chars[2 * i + 1] = (char)(hexEncodingTable[v & 0xf]); |
| } |
| |
| return new String(chars); |
| } |
| |
| public PemObject generate() |
| throws PemGenerationException |
| { |
| try |
| { |
| return createPemObject(obj); |
| } |
| catch (IOException e) |
| { |
| throw new PemGenerationException("encoding exception: " + e.getMessage(), e); |
| } |
| } |
| } |