001/* 002 * $Id: PdfPublicKeySecurityHandler.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044 045/** 046 * The below 2 methods are from pdfbox. 047 * 048 * private DERObject createDERForRecipient(byte[] in, X509Certificate cert) ; 049 * private KeyTransRecipientInfo computeRecipientInfo(X509Certificate x509certificate, byte[] abyte0); 050 * 051 * 2006-11-22 Aiken Sam. 052 */ 053 054/** 055 * Copyright (c) 2003-2006, www.pdfbox.org 056 * All rights reserved. 057 * 058 * Redistribution and use in source and binary forms, with or without 059 * modification, are permitted provided that the following conditions are met: 060 * 061 * 1. Redistributions of source code must retain the above copyright notice, 062 * this list of conditions and the following disclaimer. 063 * 2. Redistributions in binary form must reproduce the above copyright notice, 064 * this list of conditions and the following disclaimer in the documentation 065 * and/or other materials provided with the distribution. 066 * 3. Neither the name of pdfbox; nor the names of its 067 * contributors may be used to endorse or promote products derived from this 068 * software without specific prior written permission. 069 * 070 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 071 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 072 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 073 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY 074 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 075 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 076 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 077 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 078 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 079 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 080 * 081 * http://www.pdfbox.org 082 * 083 */ 084 085package com.itextpdf.text.pdf; 086 087import java.io.ByteArrayInputStream; 088import java.io.ByteArrayOutputStream; 089import java.io.IOException; 090import java.security.AlgorithmParameterGenerator; 091import java.security.AlgorithmParameters; 092import java.security.GeneralSecurityException; 093import java.security.NoSuchAlgorithmException; 094import java.security.SecureRandom; 095import java.security.cert.Certificate; 096import java.security.cert.X509Certificate; 097import java.util.ArrayList; 098 099import javax.crypto.Cipher; 100import javax.crypto.KeyGenerator; 101import javax.crypto.SecretKey; 102 103import org.bouncycastle.asn1.ASN1InputStream; 104import org.bouncycastle.asn1.DERObject; 105import org.bouncycastle.asn1.DERObjectIdentifier; 106import org.bouncycastle.asn1.DEROctetString; 107import org.bouncycastle.asn1.DEROutputStream; 108import org.bouncycastle.asn1.DERSet; 109import org.bouncycastle.asn1.cms.ContentInfo; 110import org.bouncycastle.asn1.cms.EncryptedContentInfo; 111import org.bouncycastle.asn1.cms.EnvelopedData; 112import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; 113import org.bouncycastle.asn1.cms.KeyTransRecipientInfo; 114import org.bouncycastle.asn1.cms.RecipientIdentifier; 115import org.bouncycastle.asn1.cms.RecipientInfo; 116import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 117import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 118import org.bouncycastle.asn1.x509.TBSCertificateStructure; 119 120/** 121 * @author Aiken Sam (aikensam@ieee.org) 122 */ 123public class PdfPublicKeySecurityHandler { 124 125 static final int SEED_LENGTH = 20; 126 127 private ArrayList<PdfPublicKeyRecipient> recipients = null; 128 129 private byte[] seed = new byte[SEED_LENGTH]; 130 131 public PdfPublicKeySecurityHandler() { 132 KeyGenerator key; 133 try { 134 key = KeyGenerator.getInstance("AES"); 135 key.init(192, new SecureRandom()); 136 SecretKey sk = key.generateKey(); 137 System.arraycopy(sk.getEncoded(), 0, seed, 0, SEED_LENGTH); // create the 20 bytes seed 138 } catch (NoSuchAlgorithmException e) { 139 seed = SecureRandom.getSeed(SEED_LENGTH); 140 } 141 142 recipients = new ArrayList<PdfPublicKeyRecipient>(); 143 } 144 145 public void addRecipient(PdfPublicKeyRecipient recipient) { 146 recipients.add(recipient); 147 } 148 149 protected byte[] getSeed() { 150 return seed.clone(); 151 } 152 /* 153 public PdfPublicKeyRecipient[] getRecipients() { 154 recipients.toArray(); 155 return (PdfPublicKeyRecipient[])recipients.toArray(); 156 }*/ 157 158 public int getRecipientsSize() { 159 return recipients.size(); 160 } 161 162 public byte[] getEncodedRecipient(int index) throws IOException, GeneralSecurityException { 163 //Certificate certificate = recipient.getX509(); 164 PdfPublicKeyRecipient recipient = recipients.get(index); 165 byte[] cms = recipient.getCms(); 166 167 if (cms != null) return cms; 168 169 Certificate certificate = recipient.getCertificate(); 170 int permission = recipient.getPermission();//PdfWriter.AllowCopy | PdfWriter.AllowPrinting | PdfWriter.AllowScreenReaders | PdfWriter.AllowAssembly; 171 int revision = 3; 172 173 permission |= revision==3 ? 0xfffff0c0 : 0xffffffc0; 174 permission &= 0xfffffffc; 175 permission += 1; 176 177 byte[] pkcs7input = new byte[24]; 178 179 byte one = (byte)permission; 180 byte two = (byte)(permission >> 8); 181 byte three = (byte)(permission >> 16); 182 byte four = (byte)(permission >> 24); 183 184 System.arraycopy(seed, 0, pkcs7input, 0, 20); // put this seed in the pkcs7 input 185 186 pkcs7input[20] = four; 187 pkcs7input[21] = three; 188 pkcs7input[22] = two; 189 pkcs7input[23] = one; 190 191 DERObject obj = createDERForRecipient(pkcs7input, (X509Certificate)certificate); 192 193 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 194 195 DEROutputStream k = new DEROutputStream(baos); 196 197 k.writeObject(obj); 198 199 cms = baos.toByteArray(); 200 201 recipient.setCms(cms); 202 203 return cms; 204 } 205 206 public PdfArray getEncodedRecipients() throws IOException, 207 GeneralSecurityException { 208 PdfArray EncodedRecipients = new PdfArray(); 209 byte[] cms = null; 210 for (int i=0; i<recipients.size(); i++) 211 try { 212 cms = getEncodedRecipient(i); 213 EncodedRecipients.add(new PdfLiteral(PdfContentByte.escapeString(cms))); 214 } catch (GeneralSecurityException e) { 215 EncodedRecipients = null; 216 } catch (IOException e) { 217 EncodedRecipients = null; 218 } 219 220 return EncodedRecipients; 221 } 222 223 private DERObject createDERForRecipient(byte[] in, X509Certificate cert) 224 throws IOException, 225 GeneralSecurityException 226 { 227 228 String s = "1.2.840.113549.3.2"; 229 230 AlgorithmParameterGenerator algorithmparametergenerator = AlgorithmParameterGenerator.getInstance(s); 231 AlgorithmParameters algorithmparameters = algorithmparametergenerator.generateParameters(); 232 ByteArrayInputStream bytearrayinputstream = new ByteArrayInputStream(algorithmparameters.getEncoded("ASN.1")); 233 ASN1InputStream asn1inputstream = new ASN1InputStream(bytearrayinputstream); 234 DERObject derobject = asn1inputstream.readObject(); 235 KeyGenerator keygenerator = KeyGenerator.getInstance(s); 236 keygenerator.init(128); 237 SecretKey secretkey = keygenerator.generateKey(); 238 Cipher cipher = Cipher.getInstance(s); 239 cipher.init(1, secretkey, algorithmparameters); 240 byte[] abyte1 = cipher.doFinal(in); 241 DEROctetString deroctetstring = new DEROctetString(abyte1); 242 KeyTransRecipientInfo keytransrecipientinfo = computeRecipientInfo(cert, secretkey.getEncoded()); 243 DERSet derset = new DERSet(new RecipientInfo(keytransrecipientinfo)); 244 AlgorithmIdentifier algorithmidentifier = new AlgorithmIdentifier(new DERObjectIdentifier(s), derobject); 245 EncryptedContentInfo encryptedcontentinfo = 246 new EncryptedContentInfo(PKCSObjectIdentifiers.data, algorithmidentifier, deroctetstring); 247 EnvelopedData env = new EnvelopedData(null, derset, encryptedcontentinfo, null); 248 ContentInfo contentinfo = 249 new ContentInfo(PKCSObjectIdentifiers.envelopedData, env); 250 return contentinfo.getDERObject(); 251 } 252 253 private KeyTransRecipientInfo computeRecipientInfo(X509Certificate x509certificate, byte[] abyte0) 254 throws GeneralSecurityException, IOException 255 { 256 ASN1InputStream asn1inputstream = 257 new ASN1InputStream(new ByteArrayInputStream(x509certificate.getTBSCertificate())); 258 TBSCertificateStructure tbscertificatestructure = 259 TBSCertificateStructure.getInstance(asn1inputstream.readObject()); 260 AlgorithmIdentifier algorithmidentifier = tbscertificatestructure.getSubjectPublicKeyInfo().getAlgorithmId(); 261 IssuerAndSerialNumber issuerandserialnumber = 262 new IssuerAndSerialNumber( 263 tbscertificatestructure.getIssuer(), 264 tbscertificatestructure.getSerialNumber().getValue()); 265 Cipher cipher = Cipher.getInstance(algorithmidentifier.getObjectId().getId()); 266 cipher.init(1, x509certificate); 267 DEROctetString deroctetstring = new DEROctetString(cipher.doFinal(abyte0)); 268 RecipientIdentifier recipId = new RecipientIdentifier(issuerandserialnumber); 269 return new KeyTransRecipientInfo( recipId, algorithmidentifier, deroctetstring); 270 } 271}