org.jruby.ext.openssl.impl.PKCS7 Maven / Gradle / Ivy
/***** 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
*
* 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.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.cert.X509CRL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
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.RC2ParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DEREncodable;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DERUTCTime;
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;
import org.jruby.ext.openssl.x509store.Store;
import org.jruby.ext.openssl.x509store.StoreContext;
import org.jruby.ext.openssl.x509store.X509AuxCertificate;
import org.jruby.ext.openssl.x509store.X509Utils;
/** c: PKCS7
*
* Basically equivalent of the ContentInfo structures in PKCS#7.
*
* @author Ola Bini
*/
@SuppressWarnings("deprecation")
public class PKCS7 {
// OpenSSL behavior: PKCS#7 ObjectId for "ITU-T" + "0"
private static final String EMPTY_PKCS7_OID = "0.0";
/* content as defined by the type */
/* all encryption/message digests are applied to the 'contents',
* leaving out the 'type' field. */
private PKCS7Data data;
public Object ctrl(int cmd, Object v, Object ignored) throws PKCS7Exception {
return this.data.ctrl(cmd, v, ignored);
}
public void setDetached(int v) throws PKCS7Exception {
ctrl(OP_SET_DETACHED_SIGNATURE, Integer.valueOf(v), null);
}
public int getDetached() throws PKCS7Exception {
return ((Integer)ctrl(OP_GET_DETACHED_SIGNATURE, null, null)).intValue();
}
public boolean isDetached() throws PKCS7Exception {
return isSigned() && getDetached() != 0;
}
private void initiateWith(Integer nid, DEREncodable content) throws PKCS7Exception {
this.data = PKCS7Data.fromASN1(nid, content);
}
/**
* ContentInfo ::= SEQUENCE {
* contentType ContentType,
* content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
*
* ContentType ::= OBJECT IDENTIFIER
*/
public static PKCS7 fromASN1(DEREncodable obj) throws PKCS7Exception {
PKCS7 p7 = new PKCS7();
int size = ((ASN1Sequence) obj).size();
if (size == 0) {
return p7;
}
DERObjectIdentifier contentType = (DERObjectIdentifier) (((ASN1Sequence) obj).getObjectAt(0));
if (EMPTY_PKCS7_OID.equals(contentType.getId())) {
// OpenSSL behavior
p7.setType(ASN1Registry.NID_undef);
} else {
Integer nid = ASN1Registry.obj2nid(contentType);
DEREncodable content = size == 1 ? (DEREncodable) null : ((ASN1Sequence) obj).getObjectAt(1);
if (content != null && content instanceof DERTaggedObject && ((DERTaggedObject) content).getTagNo() == 0) {
content = ((DERTaggedObject) content).getObject();
}
p7.initiateWith(nid, content);
}
return p7;
}
/* c: d2i_PKCS7_bio
*
*/
public static PKCS7 fromASN1(BIO bio) throws IOException, PKCS7Exception {
ASN1InputStream ais = new ASN1InputStream(BIO.asInputStream(bio));
return fromASN1(ais.readObject());
}
public ASN1Encodable asASN1() {
ASN1EncodableVector vector = new ASN1EncodableVector();
DERObjectIdentifier contentType;
if (data == null) {
// OpenSSL behavior
contentType = new DERObjectIdentifier(EMPTY_PKCS7_OID);
} else {
contentType = ASN1Registry.nid2obj(getType());
}
vector.add(contentType);
if (data != null) {
vector.add(new DERTaggedObject(0, data.asASN1()));
}
return new DERSequence(vector);
}
/* c: i2d_PKCS7
*
*/
public byte[] toASN1() throws IOException {
return asASN1().getEncoded();
}
/* c: PKCS7_add_signature
*
*/
public SignerInfoWithPkey addSignature(X509AuxCertificate x509, PrivateKey pkey, MessageDigest dgst) throws PKCS7Exception{
SignerInfoWithPkey si = new SignerInfoWithPkey();
si.set(x509, pkey, dgst);
addSigner(si);
return si;
}
/* c: X509_find_by_issuer_and_serial
*
*/
public static X509AuxCertificate findByIssuerAndSerial(Collection certs, X509Name issuer, BigInteger serial) {
Name name = new Name(issuer);
for(X509AuxCertificate cert : certs) {
if(name.isEqual(cert.getIssuerX500Principal()) && serial.equals(cert.getSerialNumber())) {
return cert;
}
}
return null;
}
/* c: PKCS7_get0_signers
*
*/
public List getSigners(Collection certs, List sinfos, int flags) throws PKCS7Exception {
List signers = new ArrayList();
if(!isSigned()) {
throw new PKCS7Exception(F_PKCS7_GET0_SIGNERS,R_WRONG_CONTENT_TYPE);
}
if(sinfos.size() == 0) {
throw new PKCS7Exception(F_PKCS7_GET0_SIGNERS,R_NO_SIGNERS);
}
for(SignerInfoWithPkey si : sinfos) {
IssuerAndSerialNumber ias = si.getIssuerAndSerialNumber();
X509AuxCertificate signer = null;
// System.err.println("looking for: " + ias.getName() + " and " + ias.getCertificateSerialNumber());
// System.err.println(" in: " + certs);
// System.err.println(" in: " + getSign().getCert());
if(certs != null) {
signer = findByIssuerAndSerial(certs, ias.getName(), ias.getCertificateSerialNumber().getValue());
}
if(signer == null && (flags & NOINTERN) == 0 && getSign().getCert() != null) {
signer = findByIssuerAndSerial(getSign().getCert(), ias.getName(), ias.getCertificateSerialNumber().getValue());
}
if(signer == null) {
throw new PKCS7Exception(F_PKCS7_GET0_SIGNERS,R_SIGNER_CERTIFICATE_NOT_FOUND);
}
signers.add(signer);
}
return signers;
}
/* c: PKCS7_digest_from_attributes
*
*/
public ASN1OctetString digestFromAttributes(ASN1Set attributes) {
return (ASN1OctetString)SignerInfoWithPkey.getAttribute(attributes, ASN1Registry.NID_pkcs9_messageDigest);
}
/* c: PKCS7_signatureVerify
*
*/
public void signatureVerify(BIO bio, SignerInfoWithPkey si, X509AuxCertificate x509) throws PKCS7Exception {
if(!isSigned() && !isSignedAndEnveloped()) {
throw new PKCS7Exception(F_PKCS7_SIGNATUREVERIFY, R_WRONG_PKCS7_TYPE);
}
int md_type = ASN1Registry.obj2nid(si.getDigestAlgorithm().getObjectId()).intValue();
BIO btmp = bio;
MessageDigest mdc = null;
for(;;) {
if(btmp == null || (btmp = bio.findType(BIO.TYPE_MD)) == null) {
throw new PKCS7Exception(F_PKCS7_SIGNATUREVERIFY, R_UNABLE_TO_FIND_MESSAGE_DIGEST);
}
mdc = ((MessageDigestBIOFilter)btmp).getMessageDigest();
if(null == mdc) {
throw new PKCS7Exception(F_PKCS7_SIGNATUREVERIFY, -1);
}
if(EVP.type(mdc) == md_type) {
break;
}
btmp = btmp.next();
}
MessageDigest mdc_tmp = null;
try {
mdc_tmp = (MessageDigest)mdc.clone();
} catch(Exception e) {}
byte[] currentData = new byte[0];
ASN1Set sk = si.getAuthenticatedAttributes();
try {
if(sk != null && sk.size() > 0) {
byte[] md_dat = mdc_tmp.digest();
ASN1OctetString message_digest = digestFromAttributes(sk);
if(message_digest == null) {
throw new PKCS7Exception(F_PKCS7_SIGNATUREVERIFY, R_UNABLE_TO_FIND_MESSAGE_DIGEST);
}
if(!Arrays.equals(md_dat, message_digest.getOctets())) {
throw new NotVerifiedPKCS7Exception();
}
currentData = sk.getEncoded();
}
ASN1OctetString os = si.getEncryptedDigest();
PublicKey pkey = x509.getPublicKey();
Signature sign = Signature.getInstance(EVP.signatureAlgorithm(mdc_tmp, pkey));
sign.initVerify(pkey);
if(currentData.length > 0) {
sign.update(currentData);
}
if(!sign.verify(os.getOctets())) {
throw new NotVerifiedPKCS7Exception();
}
} catch(NotVerifiedPKCS7Exception e) {
throw e;
} catch(Exception e) {
System.err.println("Other exception");
e.printStackTrace();
throw new NotVerifiedPKCS7Exception();
}
}
/* c: PKCS7_verify
*
*/
public void verify(Collection certs, Store store, BIO indata, BIO out, int flags) throws PKCS7Exception {
if(!isSigned()) {
throw new PKCS7Exception(F_PKCS7_VERIFY, R_WRONG_CONTENT_TYPE);
}
if(getDetached() != 0 && indata == null) {
throw new PKCS7Exception(F_PKCS7_VERIFY, R_NO_CONTENT);
}
List sinfos = new ArrayList(getSignerInfo());
if(sinfos.size() == 0) {
throw new PKCS7Exception(F_PKCS7_VERIFY, R_NO_SIGNATURES_ON_DATA);
}
List signers = getSigners(certs, sinfos, flags);
if(signers == null) {
throw new NotVerifiedPKCS7Exception();
}
/* Now verify the certificates */
if((flags & NOVERIFY) == 0) {
for(X509AuxCertificate signer : signers) {
StoreContext cert_ctx = new StoreContext();
if((flags & NOCHAIN) == 0) {
if(cert_ctx.init(store, signer, new ArrayList(getSign().getCert())) == 0) {
throw new PKCS7Exception(F_PKCS7_VERIFY, -1);
}
cert_ctx.setPurpose(X509Utils.X509_PURPOSE_SMIME_SIGN);
} else if(cert_ctx.init(store, signer, null) == 0) {
throw new PKCS7Exception(F_PKCS7_VERIFY, -1);
}
cert_ctx.setExtraData(1, store.getExtraData(1));
if((flags & NOCRL) == 0) {
cert_ctx.setCRLs((List)getSign().getCrl());
}
try {
int i = cert_ctx.verifyCertificate();
int j = 0;
if(i <= 0) {
j = cert_ctx.getError();
}
cert_ctx.cleanup();
if(i <= 0) {
throw new PKCS7Exception(F_PKCS7_VERIFY, R_CERTIFICATE_VERIFY_ERROR, "Verify error:" + X509Utils.verifyCertificateErrorString(j));
}
} catch(PKCS7Exception e) {
throw e;
} catch(Exception e) {
throw new PKCS7Exception(F_PKCS7_VERIFY, R_CERTIFICATE_VERIFY_ERROR, e);
}
}
}
BIO tmpin = indata;
BIO p7bio = dataInit(tmpin);
BIO tmpout = null;
if((flags & TEXT) != 0) {
tmpout = BIO.mem();
} else {
tmpout = out;
}
byte[] buf = new byte[4096];
for(;;) {
try {
int i = p7bio.read(buf, 0, buf.length);
if(i <= 0) {
break;
}
if(tmpout != null) {
tmpout.write(buf, 0, i);
}
} catch(IOException e) {
throw new PKCS7Exception(F_PKCS7_VERIFY, -1, e);
}
}
if((flags & TEXT) != 0) {
new SMIME(Mime.DEFAULT).text(tmpout, out);
}
if((flags & NOSIGS) == 0) {
for(int i=0; i certs, BIO data, int flags) throws PKCS7Exception {
PKCS7 p7 = new PKCS7();
p7.setType(ASN1Registry.NID_pkcs7_signed);
p7.contentNew(ASN1Registry.NID_pkcs7_data);
SignerInfoWithPkey si = p7.addSignature(signcert, pkey, EVP.sha1());
if((flags & NOCERTS) == 0) {
p7.addCertificate(signcert);
if(certs != null) {
for(X509AuxCertificate c : certs) {
p7.addCertificate(c);
}
}
}
if((flags & NOATTR) == 0) {
si.addSignedAttribute(ASN1Registry.NID_pkcs9_contentType, ASN1Registry.nid2obj(ASN1Registry.NID_pkcs7_data));
if((flags & NOSMIMECAP) == 0) {
ASN1EncodableVector smcap = new ASN1EncodableVector();
smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_des_ede3_cbc)));
smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_rc2_cbc), new DERInteger(128)));
smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_rc2_cbc), new DERInteger(64)));
smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_rc2_cbc), new DERInteger(40)));
smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_des_cbc)));
si.addSignedAttribute(ASN1Registry.NID_SMIMECapabilities, new DERSequence(smcap));
}
}
if((flags & STREAM) != 0) {
return p7;
}
BIO p7bio = p7.dataInit(null);
try {
data.crlfCopy(p7bio, flags);
} catch(IOException e) {
throw new PKCS7Exception(F_PKCS7_SIGN, R_PKCS7_DATAFINAL_ERROR, e);
}
if((flags & DETACHED) != 0) {
p7.setDetached(1);
}
p7.dataFinal(p7bio);
return p7;
}
/* c: PKCS7_encrypt
*
*/
public static PKCS7 encrypt(Collection certs, byte[] in, CipherSpec cipher, int flags) throws PKCS7Exception {
PKCS7 p7 = new PKCS7();
p7.setType(ASN1Registry.NID_pkcs7_enveloped);
try {
p7.setCipher(cipher);
for(X509AuxCertificate x509 : certs) {
p7.addRecipient(x509);
}
BIO p7bio = p7.dataInit(null);
BIO.memBuf(in).crlfCopy(p7bio, flags);
p7bio.flush();
p7.dataFinal(p7bio);
return p7;
} catch(IOException e) {
throw new PKCS7Exception(F_PKCS7_ENCRYPT, R_PKCS7_DATAFINAL_ERROR, e);
}
}
/* c: PKCS7_decrypt
*
*/
public void decrypt(PrivateKey pkey, X509AuxCertificate cert, BIO data, int flags) throws PKCS7Exception {
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);
}
}
/** c: PKCS7_set_type
*
*/
public void setType(int type) throws PKCS7Exception {
switch(type) {
case ASN1Registry.NID_undef:
this.data = null;
break;
case ASN1Registry.NID_pkcs7_signed:
this.data = new PKCS7DataSigned();
break;
case ASN1Registry.NID_pkcs7_data:
this.data = new PKCS7DataData();
break;
case ASN1Registry.NID_pkcs7_signedAndEnveloped:
this.data = new PKCS7DataSignedAndEnveloped();
break;
case ASN1Registry.NID_pkcs7_enveloped:
this.data = new PKCS7DataEnveloped();
break;
case ASN1Registry.NID_pkcs7_encrypted:
this.data = new PKCS7DataEncrypted();
break;
case ASN1Registry.NID_pkcs7_digest:
this.data = new PKCS7DataDigest();
break;
default:
throw new PKCS7Exception(F_PKCS7_SET_TYPE,R_UNSUPPORTED_CONTENT_TYPE);
}
}
/** c: PKCS7_set_cipher
*
*/
public void setCipher(CipherSpec cipher) throws PKCS7Exception {
this.data.setCipher(cipher);
}
/** c: PKCS7_add_recipient
*
*/
public RecipInfo addRecipient(X509AuxCertificate recip) throws PKCS7Exception {
RecipInfo ri = new RecipInfo();
ri.set(recip);
addRecipientInfo(ri);
return ri;
}
/** c: PKCS7_content_new
*
*/
public void contentNew(int nid) throws PKCS7Exception {
PKCS7 ret = new PKCS7();
ret.setType(nid);
this.setContent(ret);
}
/** c: PKCS7_add_signer
*
*/
public void addSigner(SignerInfoWithPkey psi) throws PKCS7Exception {
this.data.addSigner(psi);
}
/** c: PKCS7_add_certificate
*
*/
public void addCertificate(X509AuxCertificate cert) throws PKCS7Exception {
this.data.addCertificate(cert);
}
/** c: PKCS7_add_crl
*
*/
public void addCRL(X509CRL crl) throws PKCS7Exception {
this.data.addCRL(crl);
}
/** c: PKCS7_add_recipient_info
*
*/
public void addRecipientInfo(RecipInfo ri) throws PKCS7Exception {
this.data.addRecipientInfo(ri);
}
/** c: PKCS7_set_content
*
*/
public void setContent(PKCS7 p7) throws PKCS7Exception {
this.data.setContent(p7);
}
/** c: PKCS7_get_signer_info
*
*/
public Collection getSignerInfo() {
return this.data.getSignerInfo();
}
private final static byte[] PEM_STRING_PKCS7_START = "-----BEGIN PKCS7-----".getBytes();
/** c: PEM_read_bio_PKCS7
*
*/
public static PKCS7 readPEM(BIO input) throws PKCS7Exception {
try {
byte[] buffer = new byte[SMIME.MAX_SMLEN];
int read = -1;
read = input.gets(buffer, SMIME.MAX_SMLEN);
if(read > PEM_STRING_PKCS7_START.length) {
byte[] tmp = new byte[PEM_STRING_PKCS7_START.length];
System.arraycopy(buffer, 0, tmp, 0, tmp.length);
if(Arrays.equals(PEM_STRING_PKCS7_START, tmp)) {
return fromASN1(BIO.base64Filter(input));
} else {
return null;
}
} else {
return null;
}
} catch(IOException e) {
return null;
}
}
/** c: stati PKCS7_bio_add_digest
*
*/
public BIO bioAddDigest(BIO pbio, AlgorithmIdentifier alg) throws PKCS7Exception {
try {
MessageDigest md = EVP.getDigest(alg.getObjectId());
BIO btmp = BIO.mdFilter(md);
if(pbio == null) {
return btmp;
} else {
pbio.push(btmp);
return pbio;
}
} catch(Exception e) {
throw new PKCS7Exception(F_PKCS7_BIO_ADD_DIGEST, R_UNKNOWN_DIGEST_TYPE, e);
}
}
/** c: PKCS7_dataDecode
*
*/
public BIO dataDecode(PrivateKey pkey, BIO inBio, X509AuxCertificate pcert) throws PKCS7Exception {
BIO out = null;
BIO btmp = null;
BIO etmp = null;
BIO bio = null;
byte[] dataBody = null;
Collection mdSk = null;
Collection rsk = null;
AlgorithmIdentifier encAlg = null;
Cipher evpCipher = null;
RecipInfo ri = null;
int i = getType();
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.getAlgorithm());
} catch(Exception e) {
e.printStackTrace(System.err);
throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CIPHER_TYPE, e);
}
break;
case ASN1Registry.NID_pkcs7_enveloped:
rsk = getEnveloped().getRecipientInfo();
dataBody = getEnveloped().getEncData().getEncData().getOctets();
encAlg = getEnveloped().getEncData().getAlgorithm();
try {
evpCipher = EVP.getCipher(encAlg.getAlgorithm());
} catch(Exception e) {
e.printStackTrace(System.err);
throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CIPHER_TYPE, e);
}
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.getAlgorithm());
btmp = BIO.mdFilter(evpMd);
if(out == null) {
out = btmp;
} else {
out.push(btmp);
}
btmp = null;
} catch(Exception e) {
e.printStackTrace(System.err);
throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNKNOWN_DIGEST_TYPE, e);
}
}
}
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 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 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 {
Cipher cipher = Cipher.getInstance(CipherSpec.getWrappingAlgorithm(pkey.getAlgorithm()));
cipher.init(Cipher.DECRYPT_MODE, pkey);
tmp = cipher.doFinal(ri.getEncKey().getOctets());
} catch (Exception e) {
e.printStackTrace(System.err);
throw new PKCS7Exception(F_PKCS7_DATADECODE, -1, e);
}
}
DEREncodable params = encAlg.getParameters();
try {
String algo = org.jruby.ext.openssl.Cipher.Algorithm.getAlgorithmBase(evpCipher);
if(params != null && params instanceof ASN1OctetString) {
if (algo.startsWith("RC2")) {
// J9's IBMJCE needs this exceptional RC2 support.
// Giving IvParameterSpec throws 'Illegal parameter' on IBMJCE.
SecretKeySpec sks = new SecretKeySpec(tmp, algo);
RC2ParameterSpec s = new RC2ParameterSpec(tmp.length * 8, ((ASN1OctetString) params).getOctets());
evpCipher.init(Cipher.DECRYPT_MODE, sks, s);
} else {
SecretKeySpec sks = new SecretKeySpec(tmp, algo);
IvParameterSpec iv = new IvParameterSpec(((ASN1OctetString) params).getOctets());
evpCipher.init(Cipher.DECRYPT_MODE, sks, iv);
}
} else {
evpCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(tmp, algo));
}
} catch(Exception e) {
e.printStackTrace(System.err);
throw new PKCS7Exception(F_PKCS7_DATADECODE, -1, e);
}
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
*
*/
public BIO dataInit(BIO bio) throws PKCS7Exception {
Collection mdSk = null;
ASN1OctetString os = null;
int i = this.data.getType();
Collection rsk = null;
AlgorithmIdentifier xa = null;
CipherSpec evpCipher = null;
BIO out = null;
BIO btmp = null;
EncContent enc = null;
switch (i) {
case ASN1Registry.NID_pkcs7_signed:
mdSk = getSign().getMdAlgs();
os = getSign().getContents().getOctetString();
break;
case ASN1Registry.NID_pkcs7_signedAndEnveloped:
rsk = getSignedAndEnveloped().getRecipientInfo();
mdSk = getSignedAndEnveloped().getMdAlgs();
enc = getSignedAndEnveloped().getEncData();
evpCipher = getSignedAndEnveloped().getEncData().getCipher();
if (null == evpCipher) {
throw new PKCS7Exception(F_PKCS7_DATAINIT, R_CIPHER_NOT_INITIALIZED);
}
break;
case ASN1Registry.NID_pkcs7_enveloped:
rsk = getEnveloped().getRecipientInfo();
enc = getEnveloped().getEncData();
evpCipher = getEnveloped().getEncData().getCipher();
if (null == evpCipher) {
throw new PKCS7Exception(F_PKCS7_DATAINIT, R_CIPHER_NOT_INITIALIZED);
}
break;
case ASN1Registry.NID_pkcs7_digest:
xa = getDigest().getMd();
os = getDigest().getContents().getOctetString();
break;
default:
throw new PKCS7Exception(F_PKCS7_DATAINIT, R_UNSUPPORTED_CONTENT_TYPE);
}
if (mdSk != null) {
for (AlgorithmIdentifier ai : mdSk) {
if ((out = bioAddDigest(out, ai)) == null) {
return null;
}
}
}
if (xa != null && (out = bioAddDigest(out, xa)) == null) {
return null;
}
if (evpCipher != null) {
byte[] tmp;
btmp = BIO.cipherFilter(evpCipher.getCipher());
String algoBase = evpCipher.getCipher().getAlgorithm();
if (algoBase.indexOf('/') != -1) {
algoBase = algoBase.split("/")[0];
}
try {
KeyGenerator gen = KeyGenerator.getInstance(algoBase);
gen.init(evpCipher.getKeyLenInBits(), new SecureRandom());
SecretKey key = gen.generateKey();
evpCipher.getCipher().init(Cipher.ENCRYPT_MODE, key);
if (null != rsk) {
for (RecipInfo ri : rsk) {
PublicKey pkey = ri.getCert().getPublicKey();
Cipher cipher = Cipher.getInstance(CipherSpec.getWrappingAlgorithm(pkey.getAlgorithm()));
cipher.init(Cipher.ENCRYPT_MODE, pkey);
tmp = cipher.doFinal(key.getEncoded());
ri.setEncKey(new DEROctetString(tmp));
}
}
} catch (Exception e) {
e.printStackTrace(System.err);
throw new PKCS7Exception(F_PKCS7_DATAINIT, R_ERROR_SETTING_CIPHER, e);
}
DERObjectIdentifier encAlgo = ASN1Registry.sym2oid(evpCipher.getOsslName());
if (encAlgo == null) {
throw new PKCS7Exception(F_PKCS7_DATAINIT, R_CIPHER_HAS_NO_OBJECT_IDENTIFIER);
}
if (evpCipher.getCipher().getIV() != null) {
enc.setAlgorithm(new AlgorithmIdentifier(encAlgo, new DEROctetString(evpCipher.getCipher().getIV())));
} else {
enc.setAlgorithm(new AlgorithmIdentifier(encAlgo));
}
if (out == null) {
out = btmp;
} else {
out.push(btmp);
}
btmp = null;
}
if (bio == null) {
if (isDetached()) {
bio = BIO.nullSink();
} else if (os != null && os.getOctets().length > 0) {
bio = BIO.memBuf(os.getOctets());
}
if (bio == null) {
bio = BIO.mem();
bio.setMemEofReturn(0);
}
}
if (out != null) {
out.push(bio);
} else {
out = bio;
}
bio = null;
return out;
}
/** c: static PKCS7_find_digest
*
*/
public BIO findDigest(MessageDigest[] pmd, BIO bio, int nid) throws PKCS7Exception {
while(true) {
bio = bio.findType(BIO.TYPE_MD);
if(bio == null) {
throw new PKCS7Exception(F_PKCS7_FIND_DIGEST, R_UNABLE_TO_FIND_MESSAGE_DIGEST);
}
pmd[0] = ((MessageDigestBIOFilter)bio).getMessageDigest();
if(pmd[0] == null) {
throw new PKCS7Exception(F_PKCS7_FIND_DIGEST, -1);
}
if(nid == EVP.type(pmd[0])) {
return bio;
}
bio = bio.next();
}
}
/** c: PKCS7_dataFinal
*
*/
public int dataFinal(BIO bio) throws PKCS7Exception {
Collection siSk = null;
BIO btmp;
byte[] buf;
MessageDigest mdc = null;
MessageDigest ctx_tmp = null;
ASN1Set sk;
int i = this.data.getType();
switch(i) {
case ASN1Registry.NID_pkcs7_signedAndEnveloped:
siSk = getSignedAndEnveloped().getSignerInfo();
break;
case ASN1Registry.NID_pkcs7_signed:
siSk = getSign().getSignerInfo();
break;
case ASN1Registry.NID_pkcs7_digest:
break;
default:
break;
}
if(siSk != null) {
for(SignerInfoWithPkey si : siSk) {
if(si.getPkey() == null) {
continue;
}
int j = ASN1Registry.obj2nid(si.getDigestAlgorithm().getObjectId());
btmp = bio;
MessageDigest[] _mdc = new MessageDigest[] {mdc};
btmp = findDigest(_mdc, btmp, j);
mdc = _mdc[0];
if(btmp == null) {
return 0;
}
try {
ctx_tmp = (MessageDigest)mdc.clone();
} catch(CloneNotSupportedException e) {
throw new RuntimeException(e);
}
sk = si.getAuthenticatedAttributes();
Signature sign = null;
try {
if(sk != null && sk.size() > 0) {
/* Add signing time if not already present */
if(null == si.getSignedAttribute(ASN1Registry.NID_pkcs9_signingTime)) {
DERUTCTime signTime = new DERUTCTime(Calendar.getInstance(TimeZone.getTimeZone("UTC")).getTime());
si.addSignedAttribute(ASN1Registry.NID_pkcs9_signingTime, signTime);
}
byte[] md_data = ctx_tmp.digest();
ASN1OctetString digest = new DEROctetString(md_data);
si.addSignedAttribute(ASN1Registry.NID_pkcs9_messageDigest, digest);
sk = si.getAuthenticatedAttributes();
sign = Signature.getInstance(EVP.signatureAlgorithm(ctx_tmp, si.getPkey()));
sign.initSign(si.getPkey());
byte[] abuf = sk.getEncoded();
sign.update(abuf);
}
if(sign != null) {
byte[] out = sign.sign();
si.setEncryptedDigest(new DEROctetString(out));
}
} catch(Exception e) {
throw new PKCS7Exception(F_PKCS7_DATAFINAL, -1, e);
}
}
} else if(i == ASN1Registry.NID_pkcs7_digest) {
int nid = ASN1Registry.obj2nid(getDigest().getMd().getObjectId());
MessageDigest[] _mdc = new MessageDigest[] {mdc};
bio = findDigest(_mdc, bio, nid);
mdc = _mdc[0];
byte[] md_data = mdc.digest();
ASN1OctetString digest = new DEROctetString(md_data);
getDigest().setDigest(digest);
}
if(!isDetached()) {
btmp = bio.findType(BIO.TYPE_MEM);
if(null == btmp) {
throw new PKCS7Exception(F_PKCS7_DATAFINAL, R_UNABLE_TO_FIND_MEM_BIO);
}
buf = ((MemBIO)btmp).getMemCopy();
switch(i) {
case ASN1Registry.NID_pkcs7_signedAndEnveloped:
getSignedAndEnveloped().getEncData().setEncData(new DEROctetString(buf));
break;
case ASN1Registry.NID_pkcs7_enveloped:
getEnveloped().getEncData().setEncData(new DEROctetString(buf));
break;
case ASN1Registry.NID_pkcs7_signed:
if(getSign().getContents().isData() && getDetached() != 0) {
getSign().getContents().setData(null);
} else {
getSign().getContents().setData(new DEROctetString(buf));
}
break;
case ASN1Registry.NID_pkcs7_digest:
if(getDigest().getContents().isData() && getDetached() != 0) {
getDigest().getContents().setData(null);
} else {
getDigest().getContents().setData(new DEROctetString(buf));
}
break;
}
}
return 1;
}
@Override
public String toString() {
return "#";
}
public static final int S_HEADER = 0;
public static final int S_BODY = 1;
public static final int S_TAIL = 2;
public static final int OP_SET_DETACHED_SIGNATURE = 1;
public static final int OP_GET_DETACHED_SIGNATURE = 2;
/* S/MIME related flags */
public static final int TEXT = 0x1;
public static final int NOCERTS = 0x2;
public static final int NOSIGS = 0x4;
public static final int NOCHAIN = 0x8;
public static final int NOINTERN = 0x10;
public static final int NOVERIFY = 0x20;
public static final int DETACHED = 0x40;
public static final int BINARY = 0x80;
public static final int NOATTR = 0x100;
public static final int NOSMIMECAP = 0x200;
public static final int NOOLDMIMETYPE = 0x400;
public static final int CRLFEOL = 0x800;
public static final int STREAM = 0x1000;
public static final int NOCRL = 0x2000;
/* Flags: for compatibility with older code */
public static final int SMIME_TEXT = TEXT;
public static final int SMIME_NOCERTS = NOCERTS;
public static final int SMIME_NOSIGS = NOSIGS;
public static final int SMIME_NOCHAIN = NOCHAIN;
public static final int SMIME_NOINTERN = NOINTERN;
public static final int SMIME_NOVERIFY = NOVERIFY;
public static final int SMIME_DETACHED = DETACHED;
public static final int SMIME_BINARY = BINARY;
public static final int SMIME_NOATTR = NOATTR;
/* Function codes. */
public static final int F_B64_READ_PKCS7 = 120;
public static final int F_B64_WRITE_PKCS7 = 121;
public static final int F_PKCS7_ADD_ATTRIB_SMIMECAP = 118;
public static final int F_PKCS7_ADD_CERTIFICATE = 100;
public static final int F_PKCS7_ADD_CRL = 101;
public static final int F_PKCS7_ADD_RECIPIENT_INFO = 102;
public static final int F_PKCS7_ADD_SIGNER = 103;
public static final int F_PKCS7_BIO_ADD_DIGEST = 125;
public static final int F_PKCS7_CTRL = 104;
public static final int F_PKCS7_DATADECODE = 112;
public static final int F_PKCS7_DATAFINAL = 128;
public static final int F_PKCS7_DATAINIT = 105;
public static final int F_PKCS7_DATASIGN = 106;
public static final int F_PKCS7_DATAVERIFY = 107;
public static final int F_PKCS7_DECRYPT = 114;
public static final int F_PKCS7_ENCRYPT = 115;
public static final int F_PKCS7_FIND_DIGEST = 127;
public static final int F_PKCS7_GET0_SIGNERS = 124;
public static final int F_PKCS7_SET_CIPHER = 108;
public static final int F_PKCS7_SET_CONTENT = 109;
public static final int F_PKCS7_SET_DIGEST = 126;
public static final int F_PKCS7_SET_TYPE = 110;
public static final int F_PKCS7_SIGN = 116;
public static final int F_PKCS7_SIGNATUREVERIFY = 113;
public static final int F_PKCS7_SIMPLE_SMIMECAP = 119;
public static final int F_PKCS7_VERIFY = 117;
public static final int F_SMIME_READ_PKCS7 = 122;
public static final int F_SMIME_TEXT = 123;
/* Reason codes. */
public static final int R_CERTIFICATE_VERIFY_ERROR = 117;
public static final int R_CIPHER_HAS_NO_OBJECT_IDENTIFIER = 144;
public static final int R_CIPHER_NOT_INITIALIZED = 116;
public static final int R_CONTENT_AND_DATA_PRESENT = 118;
public static final int R_DECODE_ERROR = 130;
public static final int R_DECRYPTED_KEY_IS_WRONG_LENGTH = 100;
public static final int R_DECRYPT_ERROR = 119;
public static final int R_DIGEST_FAILURE = 101;
public static final int R_ERROR_ADDING_RECIPIENT = 120;
public static final int R_ERROR_SETTING_CIPHER = 121;
public static final int R_INVALID_MIME_TYPE = 131;
public static final int R_INVALID_NULL_POINTER = 143;
public static final int R_MIME_NO_CONTENT_TYPE = 132;
public static final int R_MIME_PARSE_ERROR = 133;
public static final int R_MIME_SIG_PARSE_ERROR = 134;
public static final int R_MISSING_CERIPEND_INFO = 103;
public static final int R_NO_CONTENT = 122;
public static final int R_NO_CONTENT_TYPE = 135;
public static final int R_NO_MULTIPART_BODY_FAILURE = 136;
public static final int R_NO_MULTIPART_BOUNDARY = 137;
public static final int R_NO_RECIPIENT_MATCHES_CERTIFICATE = 115;
public static final int R_NO_RECIPIENT_MATCHES_KEY = 146;
public static final int R_NO_SIGNATURES_ON_DATA = 123;
public static final int R_NO_SIGNERS = 142;
public static final int R_NO_SIG_CONTENT_TYPE = 138;
public static final int R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE = 104;
public static final int R_PKCS7_ADD_SIGNATURE_ERROR = 124;
public static final int R_PKCS7_DATAFINAL = 126;
public static final int R_PKCS7_DATAFINAL_ERROR = 125;
public static final int R_PKCS7_DATASIGN = 145;
public static final int R_PKCS7_PARSE_ERROR = 139;
public static final int R_PKCS7_SIG_PARSE_ERROR = 140;
public static final int R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE = 127;
public static final int R_SIGNATURE_FAILURE = 105;
public static final int R_SIGNER_CERTIFICATE_NOT_FOUND = 128;
public static final int R_SIG_INVALID_MIME_TYPE = 141;
public static final int R_SMIME_TEXT_ERROR = 129;
public static final int R_UNABLE_TO_FIND_CERTIFICATE = 106;
public static final int R_UNABLE_TO_FIND_MEM_BIO = 107;
public static final int R_UNABLE_TO_FIND_MESSAGE_DIGEST = 108;
public static final int R_UNKNOWN_DIGEST_TYPE = 109;
public static final int R_UNKNOWN_OPERATION = 110;
public static final int R_UNSUPPORTED_CIPHER_TYPE = 111;
public static final int R_UNSUPPORTED_CONTENT_TYPE = 112;
public static final int R_WRONG_CONTENT_TYPE = 113;
public static final int R_WRONG_PKCS7_TYPE = 114;
public Envelope getEnveloped() {
return this.data.getEnveloped();
}
public SignEnvelope getSignedAndEnveloped() {
return this.data.getSignedAndEnveloped();
}
public Digest getDigest() {
return this.data.getDigest();
}
public Encrypt getEncrypted() {
return this.data.getEncrypted();
}
public ASN1Encodable getOther() {
return this.data.getOther();
}
public void setSign(Signed sign) {
this.data.setSign(sign);
}
public Signed getSign() {
return this.data.getSign();
}
public void setData(ASN1OctetString data) {
this.data.setData(data);
}
public ASN1OctetString getData() {
return this.data.getData();
}
public boolean isSigned() {
return this.data.isSigned();
}
public boolean isEncrypted() {
return this.data.isEncrypted();
}
public boolean isEnveloped() {
return this.data.isEnveloped();
}
public boolean isSignedAndEnveloped() {
return this.data.isSignedAndEnveloped();
}
public boolean isData() {
return this.data.isData();
}
public boolean isDigest() {
return this.data.isDigest();
}
public boolean isOther() {
return this.data.isOther();
}
public int getType() {
return this.data.getType();
}
/* c: static PKCS7_get_octet_string
*
*/
public ASN1OctetString getOctetString() {
if(isData()) {
return getData();
} else if(isOther() && getOther() != null && getOther() instanceof ASN1OctetString) {
return (ASN1OctetString)getOther();
}
return null;
}
}// PKCS7
© 2015 - 2025 Weber Informatics LLC | Privacy Policy