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
*
*/