Title: [1101] trunk/jopenssl/src/java/org/jruby/ext/openssl: Add lots of decoding parts, EVP helpers and some other stuff

Diff

Modified: trunk/jopenssl/src/java/org/jruby/ext/openssl/PKCS7.java (1100 => 1101)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/PKCS7.java	2008-08-11 12:36:54 UTC (rev 1100)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/PKCS7.java	2008-08-11 12:36:58 UTC (rev 1101)
@@ -387,8 +387,20 @@
 
     @JRubyMethod(rest=true)
     public IRubyObject decrypt(IRubyObject[] args) {
-        System.err.println("WARNING: un-implemented method called PKCS7#decrypt");
-        return getRuntime().getNil();
+        IRubyObject flags = getRuntime().getNil();
+        if(Arity.checkArgumentCount(getRuntime(), args, 2, 3) == 3) {
+            flags = args[2];
+        }
+        IRubyObject pkey = args[0];
+        IRubyObject cert = args[1];
+        PrivateKey key = ((PKey)pkey).getPrivateKey();
+        X509AuxCertificate x509 = ((X509Cert)cert).getAuxCert();
+        int flg = flags.isNil() ? 0 : RubyNumeric.fix2int(flags);
+
+        BIO out = BIO.mem();
+        p7.decrypt(key, x509, out, flg);
+
+        return membio2str(getRuntime(), out);
     }
 
     @JRubyMethod(name={"to_pem","to_s"})

Modified: trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/BIO.java (1100 => 1101)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/BIO.java	2008-08-11 12:36:54 UTC (rev 1100)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/BIO.java	2008-08-11 12:36:58 UTC (rev 1101)
@@ -148,6 +148,13 @@
         return bio;
     }
 
+    /** c: BIO_new(BIO_f_buffered())
+     *
+     */
+    public static BIO buffered() {
+        return null;
+    }
+
     /** c: BIO_new(BIO_s_mem())
      *
      */

Added: trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/EVP.java (0 => 1101)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/EVP.java	                        (rev 0)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/EVP.java	2008-08-11 12:36:58 UTC (rev 1101)
@@ -0,0 +1,106 @@
+/***** BEGIN LICENSE BLOCK *****
+ * Version: CPL 1.0/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Common Public
+ * License Version 1.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.eclipse.org/legal/cpl-v10.html
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * Copyright (C) 2008 Ola Bini <[EMAIL PROTECTED]>
+ * 
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the CPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the CPL, the GPL or the LGPL.
+ ***** END LICENSE BLOCK *****/
+package org.jruby.ext.openssl.impl;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.jruby.ext.openssl.OpenSSLReal;
+
+/**
+ *
+ * @author <a href="" PROTECTED]">Ola Bini</a>
+ */
+public class EVP {
+    // This is a class that will collect mappings from ASN1 stuff to
+    // matching Cipher and other algorithms.
+
+    // Typical examples: 
+    //  EVP_get_cipherbyobj
+    //  EVP_get_digestbynid
+
+    /* c: EVP_get_cipherbyobj
+     *
+     */
+    public static Cipher getCipher(DERObjectIdentifier oid) throws NoSuchAlgorithmException, 
+                                                                   NoSuchPaddingException {
+        return Cipher.getInstance(oid.getId(), OpenSSLReal.PROVIDER);
+    }
+
+    /* c: EVP_get_cipherbynid
+     *
+     */
+    public static Cipher getCipher(int nid) throws NoSuchAlgorithmException, 
+                                                                   NoSuchPaddingException {
+        return getCipher(ASN1Registry.nid2obj(nid));
+    }
+
+    /* c: EVP_get_digestbyobj
+     *
+     */
+    public static MessageDigest getDigest(DERObjectIdentifier oid) throws NoSuchAlgorithmException {
+        return MessageDigest.getInstance(oid.getId(), OpenSSLReal.PROVIDER);
+    }
+
+    /* c: EVP_get_digestbynid
+     *
+     */
+    public static MessageDigest getDigest(int nid) throws NoSuchAlgorithmException {
+        return getDigest(ASN1Registry.nid2obj(nid));
+    }
+
+    /* c: EVP_PKEY_decrypt
+     *
+     */
+    public static byte[] decrypt(byte[] input, int offset, int len, Key key) throws InvalidKeyException,
+                                                                                    NoSuchAlgorithmException,
+                                                                                    NoSuchPaddingException,
+                                                                                    IllegalBlockSizeException, 
+                                                                                    BadPaddingException {
+        Cipher cipher = Cipher.getInstance(key.getAlgorithm(), OpenSSLReal.PROVIDER);
+        cipher.init(Cipher.DECRYPT_MODE, key);
+        return cipher.doFinal(input, offset, len);
+    }
+
+    /* c: EVP_PKEY_decrypt
+     *
+     */
+    public static byte[] decrypt(byte[] input, Key key) throws InvalidKeyException,
+                                                               NoSuchAlgorithmException,
+                                                               NoSuchPaddingException,
+                                                               IllegalBlockSizeException, 
+                                                               BadPaddingException {
+        return decrypt(input, 0, input.length, key);
+    }
+}// EVP

Modified: trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/PKCS7.java (1100 => 1101)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/PKCS7.java	2008-08-11 12:36:54 UTC (rev 1100)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/PKCS7.java	2008-08-11 12:36:58 UTC (rev 1101)
@@ -29,6 +29,7 @@
 
 import java.io.IOException;
 import java.security.MessageDigest;
+import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.Signature;
@@ -36,12 +37,14 @@
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import java.util.Calendar;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.TimeZone;
 import javax.crypto.Cipher;
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
@@ -59,6 +62,7 @@
 import org.bouncycastle.asn1.pkcs.Attribute;
 import org.bouncycastle.asn1.pkcs.SignerInfo;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.jruby.ext.openssl.OpenSSLReal;
 
 /** c: PKCS7
  *
@@ -178,6 +182,31 @@
         }
     }
 
+    /* c: PKCS7_decrypt
+     *
+     */
+    public void decrypt(PrivateKey pkey, X509Certificate cert, BIO data, int flags) {
+        if(!isEnveloped()) {
+            throw new PKCS7Exception(F_PKCS7_DECRYPT, R_WRONG_CONTENT_TYPE);
+        }
+        try {
+            BIO tmpmem = dataDecode(pkey, null, cert);
+            if((flags & TEXT) == TEXT) {
+                BIO tmpbuf = BIO.buffered();
+                BIO bread = tmpbuf.push(tmpmem);
+                new SMIME(Mime.DEFAULT).text(bread, data);
+            } else {
+                int i;
+                byte[] buf = new byte[4096];
+                while((i = tmpmem.read(buf, 0, 4096)) > 0) {
+                    data.write(buf, 0, i);
+                }
+            }
+        } catch(IOException e) {
+            throw new PKCS7Exception(F_PKCS7_DECRYPT, R_DECRYPT_ERROR, e.toString());
+        }
+    }
+
     /** c: PKCS7_set_type
      *
      */
@@ -309,7 +338,7 @@
      */
     public BIO bioAddDigest(BIO pbio, AlgorithmIdentifier alg) {
         try {
-            MessageDigest md = MessageDigest.getInstance(ASN1Registry.o2a(alg.getObjectId()));
+            MessageDigest md = EVP.getDigest(alg.getObjectId());
             BIO btmp = BIO.mdFilter(md);
             if(pbio == null) {
                 return btmp;
@@ -322,6 +351,158 @@
         }
     }
 
+    /** c: PKCS7_dataDecode
+     *
+     */
+    public BIO dataDecode(PrivateKey pkey, BIO inBio, X509Certificate pcert) {
+        BIO out = null;
+        BIO btmp = null;
+        BIO etmp = null;
+        BIO bio = null;
+        byte[] dataBody = null;
+        Set<AlgorithmIdentifier> mdSk = null;
+        List<RecipInfo> rsk = null;
+        AlgorithmIdentifier encAlg = null;
+        AlgorithmIdentifier xalg = null;
+        Cipher evpCipher = null;
+        RecipInfo ri = null;
+
+        int i = getType();
+        state = S_HEADER;
+
+
+        switch(i) {
+        case ASN1Registry.NID_pkcs7_signed:
+            dataBody = getSign().getContents().getOctetString().getOctets();
+            mdSk = getSign().getMdAlgs();
+            break;
+        case ASN1Registry.NID_pkcs7_signedAndEnveloped:
+            rsk = getSignedAndEnveloped().getRecipientInfo();
+            mdSk = getSignedAndEnveloped().getMdAlgs();
+            dataBody = getSignedAndEnveloped().getEncData().getEncData().getOctets();
+            encAlg = getSignedAndEnveloped().getEncData().getAlgorithm();
+            try {
+                evpCipher = EVP.getCipher(encAlg.getObjectId());
+            } catch(Exception e) {
+                throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CIPHER_TYPE);
+            }
+            xalg = getSignedAndEnveloped().getEncData().getAlgorithm();
+            break;
+        case ASN1Registry.NID_pkcs7_enveloped: 
+            rsk = getEnveloped().getRecipientInfo();
+            dataBody = getEnveloped().getEncData().getEncData().getOctets();
+            encAlg = getEnveloped().getEncData().getAlgorithm();
+            try {
+                evpCipher = EVP.getCipher(encAlg.getObjectId());
+            } catch(Exception e) {
+                throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CIPHER_TYPE);
+            }
+            xalg = getEnveloped().getEncData().getAlgorithm();
+            break;
+        default:
+            throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CONTENT_TYPE);
+        }
+
+        /* We will be checking the signature */
+        if(mdSk != null) {
+            for(AlgorithmIdentifier xa : mdSk) {
+                try {
+                    MessageDigest evpMd = EVP.getDigest(xa.getObjectId());
+                    btmp = BIO.mdFilter(evpMd);
+                    if(out == null) {
+                        out = btmp;
+                    } else {
+                        out.push(btmp);
+                    }
+                    btmp = null;
+                } catch(Exception e) {
+                    throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNKNOWN_DIGEST_TYPE);
+                }
+            }
+        }
+
+
+        if(evpCipher != null) {
+
+            /* It was encrypted, we need to decrypt the secret key
+             * with the private key */
+
+            /* Find the recipientInfo which matches the passed certificate
+             * (if any)
+             */
+            if(pcert != null) {
+                for(Iterator<RecipInfo> iter = rsk.iterator(); iter.hasNext();) {
+                    ri = iter.next();
+                    if(ri.compare(pcert)) {
+                        break;
+                    }
+                    ri = null;
+                }
+                if(null == ri) {
+                    throw new PKCS7Exception(F_PKCS7_DATADECODE, R_NO_RECIPIENT_MATCHES_CERTIFICATE);
+                }
+            }
+
+            byte[] tmp = null;
+            /* If we haven't got a certificate try each ri in turn */
+            if(null == pcert) {
+                for(Iterator<RecipInfo> iter = rsk.iterator(); iter.hasNext();) {
+                    ri = iter.next();
+                    try {
+                        tmp = EVP.decrypt(ri.getEncKey().getOctets(), pkey);
+                        if(tmp != null) {
+                            break;
+                        }
+                    } catch(Exception e) {
+                        tmp = null;
+                    }
+                    ri = null;
+                }
+                if(ri == null) {
+                    throw new PKCS7Exception(F_PKCS7_DATADECODE, R_NO_RECIPIENT_MATCHES_KEY);
+                }
+            } else {
+                try {
+                    tmp = EVP.decrypt(ri.getEncKey().getOctets(), pkey);
+                } catch(Exception e) {
+                    throw new PKCS7Exception(F_PKCS7_DATADECODE, -1, e.toString());
+                }
+            }
+
+            DEREncodable params = encAlg.getParameters();
+            try {
+                if(params != null && params instanceof ASN1OctetString) {
+                    evpCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(tmp, evpCipher.getAlgorithm()), new IvParameterSpec(((ASN1OctetString)params).getOctets()));
+                } else {
+                    evpCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(tmp, evpCipher.getAlgorithm()));
+                }
+            } catch(Exception e) {
+                throw new PKCS7Exception(F_PKCS7_DATADECODE, -1, e.toString());
+            }
+
+            etmp = BIO.cipherFilter(evpCipher);
+            if(out == null) {
+                out = etmp;
+            } else {
+                out.push(etmp);
+            }
+            etmp = null;
+        }
+        
+        if(isDetached() || inBio != null) {
+            bio = inBio;
+        } else {
+            if(dataBody != null && dataBody.length > 0) {
+                bio = BIO.memBuf(dataBody);
+            } else {
+                bio = BIO.mem();
+            }
+        }
+        out.push(bio);
+        bio = null;
+        return out;
+    }
+
     /** c: PKCS7_dataInit
      *
      */
@@ -331,7 +512,6 @@
         int i = this.data.getType();
         state = S_HEADER;
         List<RecipInfo> rsk = null;
-        AlgorithmIdentifier xalg = null;
         AlgorithmIdentifier xa = null;
         Cipher evpCipher = null;
         BIO out = null;
@@ -347,7 +527,6 @@
             rsk = getSignedAndEnveloped().getRecipientInfo();
             mdSk = getSignedAndEnveloped().getMdAlgs();
             enc = getSignedAndEnveloped().getEncData();
-            xalg = getSignedAndEnveloped().getEncData().getAlgorithm();
             evpCipher = getSignedAndEnveloped().getEncData().getCipher();
             if(null == evpCipher) {
                 throw new PKCS7Exception(F_PKCS7_DATAINIT, R_CIPHER_NOT_INITIALIZED);
@@ -356,7 +535,6 @@
         case ASN1Registry.NID_pkcs7_enveloped:
             rsk = getEnveloped().getRecipientInfo();
             enc = getEnveloped().getEncData();
-            xalg = getEnveloped().getEncData().getAlgorithm();
             evpCipher = getEnveloped().getEncData().getCipher();
             if(null == evpCipher) {
                 throw new PKCS7Exception(F_PKCS7_DATAINIT, R_CIPHER_NOT_INITIALIZED);
@@ -382,22 +560,9 @@
             return null;
         }
 
-
-// 	if (evp_cipher != NULL)
-// 		{
-
-//             xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
-//             if (ivlen > 0) {
-//                 if (xalg->parameter == NULL) 
-//                     xalg->parameter=ASN1_TYPE_new();
-//                 if(EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0)
-//                     goto err;
-//             }
-// 		}
         if(evpCipher != null) {
             byte[] tmp;
             String algorithm = evpCipher.getAlgorithm();
-
             btmp = BIO.cipherFilter(evpCipher);
 
             int klen = -1;
@@ -408,7 +573,7 @@
             }
 
             try {
-                KeyGenerator gen = KeyGenerator.getInstance(algoBase);
+                KeyGenerator gen = KeyGenerator.getInstance(algoBase, OpenSSLReal.PROVIDER);
                 gen.init(new SecureRandom());
                 SecretKey key = gen.generateKey();
                 klen = ((SecretKeySpec)key).getEncoded().length*8;
@@ -417,7 +582,7 @@
                 if(null != rsk) {
                     for(RecipInfo ri : rsk) {
                         PublicKey pkey = ri.getCert().getPublicKey();
-                        Cipher cipher = Cipher.getInstance(pkey.getAlgorithm());
+                        Cipher cipher = Cipher.getInstance(pkey.getAlgorithm(), OpenSSLReal.PROVIDER);
                         cipher.init(Cipher.ENCRYPT_MODE, pkey);
                         tmp = cipher.doFinal(((SecretKeySpec)key).getEncoded());
                         ri.setEncKey(new DEROctetString(tmp));
@@ -442,7 +607,11 @@
                 }
             }
 
-            enc.setAlgorithm(new AlgorithmIdentifier(encAlgo));
+            if(evpCipher.getIV() != null) {
+                enc.setAlgorithm(new AlgorithmIdentifier(encAlgo, new DEROctetString(evpCipher.getIV())));
+            } else {
+                enc.setAlgorithm(new AlgorithmIdentifier(encAlgo));
+            }
 
             if(out == null) {
                 out = btmp;
@@ -555,7 +724,7 @@
                         si.addSignedAttribute(ASN1Registry.NID_pkcs9_messageDigest, digest);
 
                         sk = si.getAuthenticatedAttributes();
-                        sign = Signature.getInstance(ctx_tmp.getAlgorithm());
+                        sign = Signature.getInstance(ctx_tmp.getAlgorithm(), OpenSSLReal.PROVIDER);
                         sign.initSign(si.getPkey());
 
                         byte[] abuf = sk.getEncoded();

Modified: trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/RecipInfo.java (1100 => 1101)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/RecipInfo.java	2008-08-11 12:36:54 UTC (rev 1100)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/RecipInfo.java	2008-08-11 12:36:58 UTC (rev 1101)
@@ -41,6 +41,7 @@
 import org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.X509Name;
+import org.jruby.ext.openssl.x509store.Name;
 
 /** PKCS7_RECIP_INFO
  *
@@ -203,6 +204,16 @@
         this.cert = newCert;
     }
 
+    /* c: static pkcs7_cmp_ri
+     *
+     */
+    public boolean compare(X509Certificate pcert) {
+        if(!new Name(issuerAndSerial.getName()).isEqual(pcert.getIssuerX500Principal())) {
+            return false;
+        }
+        return pcert.getSerialNumber().compareTo(issuerAndSerial.getCertificateSerialNumber().getValue()) == 0;
+    }
+
     /**
      * RecipientInfo ::= SEQUENCE {
      *   version Version,

Modified: trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/SMIME.java (1100 => 1101)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/SMIME.java	2008-08-11 12:36:54 UTC (rev 1100)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/impl/SMIME.java	2008-08-11 12:36:58 UTC (rev 1101)
@@ -88,6 +88,37 @@
         return isEol;
     }
 
+
+    /* c: SMIME_text
+     *
+     */
+    public void text(BIO input, BIO output) {
+// 	char iobuf[4096];
+// 	int len;
+// 	STACK_OF(MIME_HEADER) *headers;
+// 	MIME_HEADER *hdr;
+
+// 	if (!(headers = mime_parse_hdr(in))) {
+// 		PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_MIME_PARSE_ERROR);
+// 		return 0;
+// 	}
+// 	if(!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) {
+// 		PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_MIME_NO_CONTENT_TYPE);
+// 		sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
+// 		return 0;
+// 	}
+// 	if (strcmp (hdr->value, "text/plain")) {
+// 		PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_INVALID_MIME_TYPE);
+// 		ERR_add_error_data(2, "type: ", hdr->value);
+// 		sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
+// 		return 0;
+// 	}
+// 	sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
+// 	while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
+// 						BIO_write(out, iobuf, len);
+// 	return 1;
+    }
+
     /* c: static mime_bound_check
      *
      */
_______________________________________________
Jruby-extras-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/jruby-extras-devel

Reply via email to