KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ejbca > core > protocol > cmp > CmpMessageHelper


1 /*************************************************************************
2  * *
3  * EJBCA: The OpenSource Certificate Authority *
4  * *
5  * This software is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU Lesser General Public *
7  * License as published by the Free Software Foundation; either *
8  * version 2.1 of the License, or any later version. *
9  * *
10  * See terms of license at gnu.org. *
11  * *
12  *************************************************************************/

13
14 package org.ejbca.core.protocol.cmp;
15
16 import java.io.ByteArrayInputStream JavaDoc;
17 import java.io.ByteArrayOutputStream JavaDoc;
18 import java.io.IOException JavaDoc;
19 import java.security.InvalidKeyException JavaDoc;
20 import java.security.MessageDigest JavaDoc;
21 import java.security.NoSuchAlgorithmException JavaDoc;
22 import java.security.NoSuchProviderException JavaDoc;
23 import java.security.PrivateKey JavaDoc;
24 import java.security.Signature JavaDoc;
25 import java.security.SignatureException JavaDoc;
26 import java.security.cert.CertificateEncodingException JavaDoc;
27 import java.security.cert.X509Certificate JavaDoc;
28 import java.util.Date JavaDoc;
29 import java.util.Random JavaDoc;
30
31 import javax.crypto.Mac;
32 import javax.crypto.SecretKey;
33 import javax.crypto.spec.SecretKeySpec;
34
35 import org.apache.log4j.Logger;
36 import org.bouncycastle.asn1.ASN1InputStream;
37 import org.bouncycastle.asn1.DERBitString;
38 import org.bouncycastle.asn1.DERGeneralizedTime;
39 import org.bouncycastle.asn1.DERInteger;
40 import org.bouncycastle.asn1.DERObjectIdentifier;
41 import org.bouncycastle.asn1.DEROctetString;
42 import org.bouncycastle.asn1.DEROutputStream;
43 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
44 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
45 import org.bouncycastle.asn1.x509.GeneralName;
46 import org.bouncycastle.asn1.x509.X509CertificateStructure;
47 import org.bouncycastle.asn1.x509.X509Name;
48 import org.bouncycastle.cms.CMSSignedGenerator;
49 import org.ejbca.core.model.ca.SignRequestException;
50 import org.ejbca.core.model.ra.NotFoundException;
51 import org.ejbca.core.protocol.FailInfo;
52 import org.ejbca.core.protocol.IResponseMessage;
53 import org.ejbca.core.protocol.ResponseStatus;
54 import org.ejbca.util.Base64;
55 import org.ejbca.util.CertTools;
56
57 import com.novosec.pkix.asn1.cmp.CMPObjectIdentifiers;
58 import com.novosec.pkix.asn1.cmp.CertRepMessage;
59 import com.novosec.pkix.asn1.cmp.CertResponse;
60 import com.novosec.pkix.asn1.cmp.PKIBody;
61 import com.novosec.pkix.asn1.cmp.PKIHeader;
62 import com.novosec.pkix.asn1.cmp.PKIMessage;
63 import com.novosec.pkix.asn1.cmp.PKIStatusInfo;
64 import com.novosec.pkix.asn1.crmf.PBMParameter;
65
66 /**
67  * Helper class to create different standard parts of CMP messages
68  *
69  * @author tomas
70  * @version $Id: CmpMessageHelper.java,v 1.9 2007/01/16 12:34:47 anatom Exp $
71  */

72 public class CmpMessageHelper {
73     private static Logger log = Logger.getLogger(CmpMessageHelper.class);
74
75     public static PKIHeader createPKIHeader(X509Name sender, X509Name recipient, String JavaDoc senderNonce, String JavaDoc recipientNonce, String JavaDoc transactionId) {
76         PKIHeader myPKIHeader =
77             new PKIHeader(
78                     new DERInteger(2),
79                     new GeneralName(sender),
80                     new GeneralName(recipient));
81         myPKIHeader.setMessageTime(new DERGeneralizedTime(new Date JavaDoc()));
82         if (senderNonce != null) {
83             myPKIHeader.setSenderNonce(new DEROctetString(Base64.decode(senderNonce.getBytes())));
84         }
85         if (recipientNonce != null) {
86             myPKIHeader.setRecipNonce(new DEROctetString(Base64.decode(recipientNonce.getBytes())));
87         }
88         if (transactionId != null) {
89             myPKIHeader.setTransactionID(new DEROctetString(Base64.decode(transactionId.getBytes())));
90         }
91         return myPKIHeader;
92     }
93
94     public static byte[] signPKIMessage(PKIMessage myPKIMessage, X509Certificate JavaDoc signCert, PrivateKey JavaDoc signKey, String JavaDoc digestAlg, String JavaDoc provider) throws InvalidKeyException JavaDoc, NoSuchProviderException JavaDoc, NoSuchAlgorithmException JavaDoc, SecurityException JavaDoc, SignatureException JavaDoc, IOException JavaDoc, CertificateEncodingException JavaDoc {
95         log.debug(">signPKIMessage()");
96         X509CertificateStructure signStruct = X509CertificateStructure.getInstance(new ASN1InputStream(new ByteArrayInputStream JavaDoc(signCert.getEncoded())).readObject());
97         CmpMessageHelper.buildCertBasedPKIProtection( myPKIMessage, signStruct, signKey, digestAlg, provider);
98
99         log.debug("<signPKIMessage()");
100         // Return response as byte array
101
return CmpMessageHelper.pkiMessageToByteArray(myPKIMessage);
102     }
103     
104     public static void buildCertBasedPKIProtection( PKIMessage pKIMessage, X509CertificateStructure cert, PrivateKey JavaDoc key, String JavaDoc digestAlg, String JavaDoc provider )
105     throws NoSuchProviderException JavaDoc, NoSuchAlgorithmException JavaDoc, SecurityException JavaDoc, SignatureException JavaDoc, InvalidKeyException JavaDoc
106     {
107         // SHA1WITHRSA
108
DERObjectIdentifier oid = PKCSObjectIdentifiers.sha1WithRSAEncryption;
109         if (digestAlg.equals(CMSSignedGenerator.DIGEST_SHA256)) {
110             oid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
111         }
112         if (digestAlg.equals(CMSSignedGenerator.DIGEST_MD5)) {
113             oid = PKCSObjectIdentifiers.md5WithRSAEncryption;
114         }
115         pKIMessage.getHeader().setProtectionAlg( new AlgorithmIdentifier(oid) );
116         
117         Signature JavaDoc sig = Signature.getInstance( pKIMessage.getHeader().getProtectionAlg().getObjectId().getId(), provider );
118         sig.initSign(key);
119         sig.update( pKIMessage.getProtectedBytes() );
120         
121         pKIMessage.setProtection( new DERBitString(sig.sign()) );
122         pKIMessage.addExtraCert( cert );
123     }
124     
125     public static byte[] protectPKIMessageWithPBE(PKIMessage msg, String JavaDoc keyId, String JavaDoc raSecret, String JavaDoc digestAlgId, String JavaDoc macAlgId, int iterationCount) throws NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc, InvalidKeyException JavaDoc, IOException JavaDoc {
126         log.debug(">protectPKIMessageWithPBE()");
127         // Create the PasswordBased protection of the message
128
PKIHeader head = msg.getHeader();
129         head.setSenderKID(new DEROctetString(keyId.getBytes()));
130         // SHA1
131
//AlgorithmIdentifier owfAlg = new AlgorithmIdentifier("1.3.14.3.2.26");
132
AlgorithmIdentifier owfAlg = new AlgorithmIdentifier(digestAlgId);
133         // iterations, usually something like 1024
134
DERInteger iteration = new DERInteger(iterationCount);
135         // HMAC/SHA1
136
//AlgorithmIdentifier macAlg = new AlgorithmIdentifier("1.2.840.113549.2.7");
137
AlgorithmIdentifier macAlg = new AlgorithmIdentifier(macAlgId);
138         // We need some random bytes for the nonce
139
byte[] saltbytes = createSenderNonce();
140         DEROctetString derSalt = new DEROctetString(saltbytes);
141         
142         // Create the new protected return message
143
//String objectId = "1.2.840.113533.7.66.13" = passwordBasedMac;
144
String JavaDoc objectId = CMPObjectIdentifiers.passwordBasedMac.getId();
145         PBMParameter pp = new PBMParameter(derSalt, owfAlg, iteration, macAlg);
146         AlgorithmIdentifier pAlg = new AlgorithmIdentifier(new DERObjectIdentifier(objectId), pp);
147         head.setProtectionAlg(pAlg);
148         PKIBody body = msg.getBody();
149         PKIMessage ret = new PKIMessage(head, body);
150
151         // Calculate the protection bits
152
byte[] rasecret = raSecret.getBytes();
153         byte[] basekey = new byte[rasecret.length + saltbytes.length];
154         for (int i = 0; i < rasecret.length; i++) {
155             basekey[i] = rasecret[i];
156         }
157         for (int i = 0; i < saltbytes.length; i++) {
158             basekey[rasecret.length+i] = saltbytes[i];
159         }
160         // Construct the base key according to rfc4210, section 5.1.3.1
161
MessageDigest JavaDoc dig = MessageDigest.getInstance(owfAlg.getObjectId().getId(), "BC");
162         for (int i = 0; i < iterationCount; i++) {
163             basekey = dig.digest(basekey);
164             dig.reset();
165         }
166         // Do the mac
167
String JavaDoc macOid = macAlg.getObjectId().getId();
168         byte[] protectedBytes = ret.getProtectedBytes();
169         Mac mac = Mac.getInstance(macOid, "BC");
170         SecretKey key = new SecretKeySpec(basekey, macOid);
171         mac.init(key);
172         mac.reset();
173         mac.update(protectedBytes, 0, protectedBytes.length);
174         byte[] out = mac.doFinal();
175         DERBitString bs = new DERBitString(out);
176
177         // Finally store the protection bytes in the msg
178
ret.setProtection(bs);
179         
180         log.debug("<protectPKIMessageWithPBE()");
181         // Return response as byte array
182
return CmpMessageHelper.pkiMessageToByteArray(ret);
183     }
184
185     public static byte[] pkiMessageToByteArray(PKIMessage msg) throws IOException JavaDoc {
186         // Return response as byte array
187
ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
188         DEROutputStream mout = new DEROutputStream( baos );
189         mout.writeObject( msg );
190         mout.close();
191         return baos.toByteArray();
192         
193     }
194
195     /** Creates a 16 bytes random sender nonce
196      *
197      * @return byte array of length 16
198      */

199     public static byte[] createSenderNonce() {
200         // Sendernonce is a random number
201
byte[] senderNonce = new byte[16];
202         Random JavaDoc randomSource;
203         randomSource = new Random JavaDoc();
204         randomSource.nextBytes(senderNonce);
205         return senderNonce;
206     }
207     /**
208      * creates a very simple error message in response to msg (that's why we switch sender and recipient)
209      * @param msg
210      * @param status
211      * @param failInfo
212      * @param failText
213      * @return IResponseMessage that can be sent to user
214      */

215     public static IResponseMessage createUnprotectedErrorMessage(BaseCmpMessage msg, ResponseStatus status, FailInfo failInfo, String JavaDoc failText) {
216         // Create a failure message
217
if (log.isDebugEnabled()) {
218             log.debug("Creating an unprotected error message with status="+status.getValue()+", failInfo="+failInfo+", failText="+failText);
219         }
220         CmpErrorResponseMessage resp = new CmpErrorResponseMessage();
221         resp.setSenderNonce(new String JavaDoc(Base64.encode(CmpMessageHelper.createSenderNonce())));
222         if (msg != null) {
223             resp.setRecipientNonce(msg.getSenderNonce());
224             resp.setSender(msg.getRecipient());
225             resp.setRecipient(msg.getSender());
226             resp.setTransactionId(msg.getTransactionId());
227         } else {
228             // We didn't even have a request the get these from, so send back some dummy values
229
resp.setSender(new GeneralName(CertTools.stringToBcX509Name("CN=Failure Sender")));
230             resp.setRecipient(new GeneralName(CertTools.stringToBcX509Name("CN=Failure Recipient")));
231         }
232         resp.setFailInfo(failInfo);
233         resp.setStatus( status);
234         resp.setFailText(failText);
235         try {
236             resp.create();
237         } catch (InvalidKeyException JavaDoc e) {
238             log.error("Exception during CMP processing: ", e);
239         } catch (NoSuchAlgorithmException JavaDoc e) {
240             log.error("Exception during CMP processing: ", e);
241         } catch (NoSuchProviderException JavaDoc e) {
242             log.error("Exception during CMP processing: ", e);
243         } catch (SignRequestException e) {
244             log.error("Exception during CMP processing: ", e);
245         } catch (NotFoundException e) {
246             log.error("Exception during CMP processing: ", e);
247         } catch (IOException JavaDoc e) {
248             log.error("Exception during CMP processing: ", e);
249         }
250         return resp;
251     }
252     
253     /**
254      * creates a very simple error message in response to msg (that's why we switch sender and recipient)
255      * @param msg
256      * @param status
257      * @param failInfo
258      * @param failText
259      * @return IResponseMessage that can be sent to user
260      */

261     public static PKIBody createCertRequestRejectBody(PKIHeader header, PKIStatusInfo info, int requestId, int requestType) {
262         // Create a failure message
263
if (log.isDebugEnabled()) {
264             log.debug("Creating a cert request rejection message");
265         }
266
267         log.debug("Creating a CertRepMessage 'rejected'");
268
269         /*
270         String senderNonce = new String(Base64.encode(CmpMessageHelper.createSenderNonce()));
271         String rcptNonce = null;
272         X509Name sender = CertTools.stringToBcX509Name("CN=Failure Sender");
273         X509Name rcpt = CertTools.stringToBcX509Name("CN=Failure Recipient");
274         String transactionId = msg.getTransactionId();
275         PKIHeader myPKIHeader = CmpMessageHelper.createPKIHeader(sender, rcpt, senderNonce, rcptNonce, transactionId);
276         */

277         
278         CertResponse myCertResponse = new CertResponse(new DERInteger(requestId), info);
279         CertRepMessage myCertRepMessage = new CertRepMessage(myCertResponse);
280
281
282         int respType = requestType + 1; // 1 = intitialization response, 3 = certification response etc
283
log.debug("Creating response body of type respType.");
284         PKIBody myPKIBody = new PKIBody(myCertRepMessage, respType);
285         
286         return myPKIBody;
287     }
288 }
289
Popular Tags